summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/common/DEPS3
-rw-r--r--content/common/pepper_plugin_registry.cc4
-rw-r--r--content/common/pepper_plugin_registry.h11
-rw-r--r--content/content_renderer.gypi91
-rw-r--r--content/content_tests.gypi38
-rw-r--r--content/ppapi_plugin/ppapi_thread.h4
-rw-r--r--content/public/common/pepper_plugin_info.cc6
-rw-r--r--content/public/common/pepper_plugin_info.h18
-rw-r--r--content/public/renderer/ppapi_plugin_instance.h105
-rw-r--r--content/public/renderer/renderer_ppapi_host.h3
-rw-r--r--content/renderer/media/crypto/content_decryption_module_factory.cc4
-rw-r--r--content/renderer/media/crypto/ppapi_decryptor.cc4
-rw-r--r--content/renderer/media/pepper_platform_video_decoder_impl.h2
-rw-r--r--content/renderer/media/video_destination_handler.cc4
-rw-r--r--content/renderer/media/webmediaplayer_impl.cc2
-rw-r--r--content/renderer/pepper/DEPS11
-rw-r--r--content/renderer/pepper/OWNERS3
-rw-r--r--content/renderer/pepper/audio_helper.cc88
-rw-r--r--content/renderer/pepper/audio_helper.h63
-rw-r--r--content/renderer/pepper/common.h26
-rw-r--r--content/renderer/pepper/content_decryptor_delegate.cc1051
-rw-r--r--content/renderer/pepper/content_decryptor_delegate.h195
-rw-r--r--content/renderer/pepper/event_conversion.cc735
-rw-r--r--content/renderer/pepper/event_conversion.h54
-rw-r--r--content/renderer/pepper/fullscreen_container.h48
-rw-r--r--content/renderer/pepper/gfx_conversion.h48
-rw-r--r--content/renderer/pepper/host_array_buffer_var.cc103
-rw-r--r--content/renderer/pepper/host_array_buffer_var.h49
-rw-r--r--content/renderer/pepper/host_globals.cc285
-rw-r--r--content/renderer/pepper/host_globals.h118
-rw-r--r--content/renderer/pepper/host_var_tracker.cc173
-rw-r--r--content/renderer/pepper/host_var_tracker.h110
-rw-r--r--content/renderer/pepper/host_var_tracker_unittest.cc138
-rw-r--r--content/renderer/pepper/message_channel.cc520
-rw-r--r--content/renderer/pepper/message_channel.h123
-rw-r--r--content/renderer/pepper/mock_platform_image_2d.cc34
-rw-r--r--content/renderer/pepper/mock_platform_image_2d.h32
-rw-r--r--content/renderer/pepper/mock_plugin_delegate.cc415
-rw-r--r--content/renderer/pepper/mock_plugin_delegate.h205
-rw-r--r--content/renderer/pepper/mock_resource.h28
-rw-r--r--content/renderer/pepper/npapi_glue.cc357
-rw-r--r--content/renderer/pepper/npapi_glue.h265
-rw-r--r--content/renderer/pepper/npobject_var.cc59
-rw-r--r--content/renderer/pepper/npobject_var.h71
-rw-r--r--content/renderer/pepper/pepper_audio_input_host.cc2
-rw-r--r--content/renderer/pepper/pepper_audio_input_host.h2
-rw-r--r--content/renderer/pepper/pepper_broker_impl.cc4
-rw-r--r--content/renderer/pepper/pepper_broker_impl.h4
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_event_handler.h2
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_host_helper.cc2
-rw-r--r--content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc2
-rw-r--r--content/renderer/pepper/pepper_file_chooser_host.cc2
-rw-r--r--content/renderer/pepper/pepper_file_io_host.cc8
-rw-r--r--content/renderer/pepper/pepper_file_io_host.h2
-rw-r--r--content/renderer/pepper/pepper_file_system_host.cc2
-rw-r--r--content/renderer/pepper/pepper_graphics_2d_host.cc10
-rw-r--r--content/renderer/pepper/pepper_graphics_2d_host.h2
-rw-r--r--content/renderer/pepper/pepper_in_process_resource_creation.cc2
-rw-r--r--content/renderer/pepper/pepper_in_process_resource_creation.h4
-rw-r--r--content/renderer/pepper/pepper_platform_audio_input_impl.h2
-rw-r--r--content/renderer/pepper/pepper_platform_audio_output_impl.h2
-rw-r--r--content/renderer/pepper/pepper_platform_context_3d_impl.h2
-rw-r--r--content/renderer/pepper/pepper_platform_image_2d_impl.h2
-rw-r--r--content/renderer/pepper/pepper_platform_video_capture_impl.h2
-rw-r--r--content/renderer/pepper/pepper_plugin_delegate_impl.cc13
-rw-r--r--content/renderer/pepper/pepper_plugin_delegate_impl.h2
-rw-r--r--content/renderer/pepper/pepper_url_loader_host.cc4
-rw-r--r--content/renderer/pepper/pepper_url_request_unittest.cc5
-rw-r--r--content/renderer/pepper/pepper_video_capture_host.cc4
-rw-r--r--content/renderer/pepper/pepper_video_capture_host.h4
-rw-r--r--content/renderer/pepper/pepper_video_destination_host.cc2
-rw-r--r--content/renderer/pepper/pepper_video_source_host.cc2
-rw-r--r--content/renderer/pepper/plugin_delegate.h692
-rw-r--r--content/renderer/pepper/plugin_module.cc634
-rw-r--r--content/renderer/pepper/plugin_module.h267
-rw-r--r--content/renderer/pepper/plugin_object.cc360
-rw-r--r--content/renderer/pepper/plugin_object.h95
-rw-r--r--content/renderer/pepper/ppapi_interface_factory.cc62
-rw-r--r--content/renderer/pepper/ppapi_interface_factory.h56
-rw-r--r--content/renderer/pepper/ppapi_plugin_instance_impl.cc2726
-rw-r--r--content/renderer/pepper/ppapi_plugin_instance_impl.h864
-rw-r--r--content/renderer/pepper/ppapi_plugin_instance_unittest.cc127
-rw-r--r--content/renderer/pepper/ppapi_unittest.cc169
-rw-r--r--content/renderer/pepper/ppapi_unittest.h65
-rw-r--r--content/renderer/pepper/ppapi_webplugin_impl.cc308
-rw-r--r--content/renderer/pepper/ppapi_webplugin_impl.h115
-rw-r--r--content/renderer/pepper/ppb_audio_impl.cc161
-rw-r--r--content/renderer/pepper/ppb_audio_impl.h86
-rw-r--r--content/renderer/pepper/ppb_broker_impl.cc103
-rw-r--r--content/renderer/pepper/ppb_broker_impl.h60
-rw-r--r--content/renderer/pepper/ppb_buffer_impl.cc113
-rw-r--r--content/renderer/pepper/ppb_buffer_impl.h80
-rw-r--r--content/renderer/pepper/ppb_file_ref_impl.cc511
-rw-r--r--content/renderer/pepper/ppb_file_ref_impl.h126
-rw-r--r--content/renderer/pepper/ppb_flash_message_loop_impl.cc116
-rw-r--r--content/renderer/pepper/ppb_flash_message_loop_impl.h54
-rw-r--r--content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc40
-rw-r--r--content/renderer/pepper/ppb_gpu_blacklist_private_impl.h22
-rw-r--r--content/renderer/pepper/ppb_graphics_3d_impl.cc328
-rw-r--r--content/renderer/pepper/ppb_graphics_3d_impl.h94
-rw-r--r--content/renderer/pepper/ppb_image_data_impl.cc278
-rw-r--r--content/renderer/pepper/ppb_image_data_impl.h197
-rw-r--r--content/renderer/pepper/ppb_network_monitor_private_impl.cc89
-rw-r--r--content/renderer/pepper/ppb_network_monitor_private_impl.h53
-rw-r--r--content/renderer/pepper/ppb_proxy_impl.cc79
-rw-r--r--content/renderer/pepper/ppb_proxy_impl.h22
-rw-r--r--content/renderer/pepper/ppb_scrollbar_impl.cc251
-rw-r--r--content/renderer/pepper/ppb_scrollbar_impl.h78
-rw-r--r--content/renderer/pepper/ppb_tcp_server_socket_private_impl.cc82
-rw-r--r--content/renderer/pepper/ppb_tcp_server_socket_private_impl.h40
-rw-r--r--content/renderer/pepper/ppb_tcp_socket_private_impl.cc134
-rw-r--r--content/renderer/pepper/ppb_tcp_socket_private_impl.h53
-rw-r--r--content/renderer/pepper/ppb_uma_private_impl.cc100
-rw-r--r--content/renderer/pepper/ppb_uma_private_impl.h21
-rw-r--r--content/renderer/pepper/ppb_var_deprecated_impl.cc437
-rw-r--r--content/renderer/pepper/ppb_var_deprecated_impl.h21
-rw-r--r--content/renderer/pepper/ppb_video_decoder_impl.cc303
-rw-r--r--content/renderer/pepper/ppb_video_decoder_impl.h88
-rw-r--r--content/renderer/pepper/ppb_widget_impl.cc80
-rw-r--r--content/renderer/pepper/ppb_widget_impl.h65
-rw-r--r--content/renderer/pepper/ppb_x509_certificate_private_impl.cc38
-rw-r--r--content/renderer/pepper/ppb_x509_certificate_private_impl.h37
-rw-r--r--content/renderer/pepper/ppp_pdf.h34
-rw-r--r--content/renderer/pepper/quota_file_io.cc424
-rw-r--r--content/renderer/pepper/quota_file_io.h117
-rw-r--r--content/renderer/pepper/quota_file_io_unittest.cc501
-rw-r--r--content/renderer/pepper/renderer_ppapi_host_impl.cc10
-rw-r--r--content/renderer/pepper/renderer_ppapi_host_impl.h4
-rw-r--r--content/renderer/pepper/resource_creation_impl.cc317
-rw-r--r--content/renderer/pepper/resource_creation_impl.h151
-rw-r--r--content/renderer/pepper/resource_helper.cc41
-rw-r--r--content/renderer/pepper/resource_helper.h53
-rw-r--r--content/renderer/pepper/url_request_info_util.cc205
-rw-r--r--content/renderer/pepper/url_request_info_util.h38
-rw-r--r--content/renderer/pepper/url_response_info_util.cc2
-rw-r--r--content/renderer/pepper/usb_key_code_conversion.cc23
-rw-r--r--content/renderer/pepper/usb_key_code_conversion.h27
-rw-r--r--content/renderer/pepper/usb_key_code_conversion_linux.cc32
-rw-r--r--content/renderer/pepper/usb_key_code_conversion_mac.cc28
-rw-r--r--content/renderer/pepper/usb_key_code_conversion_win.cc33
-rw-r--r--content/renderer/pepper/v8_var_converter.cc470
-rw-r--r--content/renderer/pepper/v8_var_converter.h35
-rw-r--r--content/renderer/pepper/v8_var_converter_unittest.cc387
-rw-r--r--content/renderer/render_widget.cc4
-rw-r--r--content/renderer/render_widget_fullscreen_pepper.cc4
-rw-r--r--content/renderer/render_widget_fullscreen_pepper.h2
-rw-r--r--content/renderer/renderer_main.cc9
147 files changed, 19627 insertions, 106 deletions
diff --git a/content/common/DEPS b/content/common/DEPS
index 2e11e26..d60a74e 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -6,6 +6,9 @@ include_rules = [
"-webkit/child",
"-webkit/renderer",
+ # TODO(jam): remove this
+ "+content/renderer/pepper/plugin_module.h",
+
# TODO(ananta|jamesr|scottmg) http://crbug.com/237249
"!webkit/child/websocketstreamhandle_impl.h",
diff --git a/content/common/pepper_plugin_registry.cc b/content/common/pepper_plugin_registry.cc
index 44bc6a0..041c50d 100644
--- a/content/common/pepper_plugin_registry.cc
+++ b/content/common/pepper_plugin_registry.cc
@@ -184,7 +184,7 @@ void PepperPluginRegistry::PluginModuleDead(
return;
}
}
- NOTREACHED(); // Should have always found the module above.
+ // Can occur in tests.
}
PepperPluginRegistry::~PepperPluginRegistry() {
@@ -209,7 +209,7 @@ PepperPluginRegistry::PepperPluginRegistry() {
continue; // Out of process plugins need no special pre-initialization.
scoped_refptr<webkit::ppapi::PluginModule> module =
- new webkit::ppapi::PluginModule(current.name, current.path, this,
+ new webkit::ppapi::PluginModule(current.name, current.path,
ppapi::PpapiPermissions(current.permissions));
AddLiveModule(current.path, module.get());
if (current.is_internal) {
diff --git a/content/common/pepper_plugin_registry.h b/content/common/pepper_plugin_registry.h
index b40f00b..6a94725 100644
--- a/content/common/pepper_plugin_registry.h
+++ b/content/common/pepper_plugin_registry.h
@@ -9,7 +9,9 @@
#include <map>
#include "content/public/common/pepper_plugin_info.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
+
+// TODO(jam): refactor
+#include "content/renderer/pepper/plugin_module.h"
namespace content {
@@ -24,8 +26,7 @@ bool MakePepperPluginInfo(const WebPluginInfo& webplugin_info,
// It keeps two lists. One list of preloaded in-process modules, and one list
// is a list of all live modules (some of which may be out-of-process and hence
// not preloaded).
-class PepperPluginRegistry
- : public webkit::ppapi::PluginDelegate::ModuleLifetime {
+class PepperPluginRegistry {
public:
~PepperPluginRegistry();
@@ -64,9 +65,7 @@ class PepperPluginRegistry
void AddLiveModule(const base::FilePath& path,
webkit::ppapi::PluginModule* module);
- // ModuleLifetime implementation.
- virtual void PluginModuleDead(
- webkit::ppapi::PluginModule* dead_module) OVERRIDE;
+ void PluginModuleDead(webkit::ppapi::PluginModule* dead_module);
private:
PepperPluginRegistry();
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 01a7048..e260a50 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -46,6 +46,7 @@
'public/renderer/navigation_state.cc',
'public/renderer/navigation_state.h',
'public/renderer/password_form_conversion_utils.h',
+ 'public/renderer/ppapi_plugin_instance.h',
'public/renderer/renderer_ppapi_host.h',
'public/renderer/render_frame.h',
'public/renderer/render_process_observer.cc',
@@ -258,8 +259,29 @@
'renderer/paint_aggregator.cc',
'renderer/paint_aggregator.h',
'renderer/password_form_conversion_utils.cc',
+ 'renderer/pepper/audio_helper.cc',
+ 'renderer/pepper/audio_helper.h',
+ 'renderer/pepper/common.h',
+ 'renderer/pepper/content_decryptor_delegate.cc',
+ 'renderer/pepper/content_decryptor_delegate.h',
'renderer/pepper/content_renderer_pepper_host_factory.cc',
'renderer/pepper/content_renderer_pepper_host_factory.h',
+ 'renderer/pepper/event_conversion.cc',
+ 'renderer/pepper/event_conversion.h',
+ 'renderer/pepper/fullscreen_container.h',
+ 'renderer/pepper/gfx_conversion.h',
+ 'renderer/pepper/host_array_buffer_var.cc',
+ 'renderer/pepper/host_array_buffer_var.h',
+ 'renderer/pepper/host_globals.cc',
+ 'renderer/pepper/host_globals.h',
+ 'renderer/pepper/host_var_tracker.cc',
+ 'renderer/pepper/host_var_tracker.h',
+ 'renderer/pepper/message_channel.cc',
+ 'renderer/pepper/message_channel.h',
+ 'renderer/pepper/npapi_glue.cc',
+ 'renderer/pepper/npapi_glue.h',
+ 'renderer/pepper/npobject_var.cc',
+ 'renderer/pepper/npobject_var.h',
'renderer/pepper/pepper_audio_input_host.cc',
'renderer/pepper/pepper_audio_input_host.h',
'renderer/pepper/pepper_broker_impl.cc',
@@ -311,10 +333,72 @@
'renderer/pepper/pepper_video_capture_host.h',
'renderer/pepper/pepper_websocket_host.cc',
'renderer/pepper/pepper_websocket_host.h',
+ 'renderer/pepper/plugin_delegate.h',
+ 'renderer/pepper/plugin_module.cc',
+ 'renderer/pepper/plugin_module.h',
+ 'renderer/pepper/plugin_object.cc',
+ 'renderer/pepper/plugin_object.h',
+ 'renderer/pepper/ppapi_interface_factory.cc',
+ 'renderer/pepper/ppapi_interface_factory.h',
+ 'renderer/pepper/ppapi_plugin_instance_impl.cc',
+ 'renderer/pepper/ppapi_plugin_instance_impl.h',
+ 'renderer/pepper/ppapi_webplugin_impl.cc',
+ 'renderer/pepper/ppapi_webplugin_impl.h',
+ 'renderer/pepper/ppb_audio_impl.cc',
+ 'renderer/pepper/ppb_audio_impl.h',
+ 'renderer/pepper/ppb_broker_impl.cc',
+ 'renderer/pepper/ppb_broker_impl.h',
+ 'renderer/pepper/ppb_buffer_impl.cc',
+ 'renderer/pepper/ppb_buffer_impl.h',
+ 'renderer/pepper/ppb_file_ref_impl.cc',
+ 'renderer/pepper/ppb_file_ref_impl.h',
+ 'renderer/pepper/ppb_flash_message_loop_impl.cc',
+ 'renderer/pepper/ppb_flash_message_loop_impl.h',
+ 'renderer/pepper/ppb_gpu_blacklist_private_impl.cc',
+ 'renderer/pepper/ppb_gpu_blacklist_private_impl.h',
+ 'renderer/pepper/ppb_graphics_3d_impl.cc',
+ 'renderer/pepper/ppb_graphics_3d_impl.h',
+ 'renderer/pepper/ppb_image_data_impl.cc',
+ 'renderer/pepper/ppb_image_data_impl.h',
+ 'renderer/pepper/ppb_network_monitor_private_impl.cc',
+ 'renderer/pepper/ppb_network_monitor_private_impl.h',
+ 'renderer/pepper/ppb_proxy_impl.cc',
+ 'renderer/pepper/ppb_proxy_impl.h',
+ 'renderer/pepper/ppb_scrollbar_impl.cc',
+ 'renderer/pepper/ppb_scrollbar_impl.h',
+ 'renderer/pepper/ppb_tcp_server_socket_private_impl.cc',
+ 'renderer/pepper/ppb_tcp_server_socket_private_impl.h',
+ 'renderer/pepper/ppb_tcp_socket_private_impl.cc',
+ 'renderer/pepper/ppb_tcp_socket_private_impl.h',
+ 'renderer/pepper/ppb_uma_private_impl.cc',
+ 'renderer/pepper/ppb_uma_private_impl.h',
+ 'renderer/pepper/ppb_var_deprecated_impl.cc',
+ 'renderer/pepper/ppb_var_deprecated_impl.h',
+ 'renderer/pepper/ppb_video_decoder_impl.cc',
+ 'renderer/pepper/ppb_video_decoder_impl.h',
+ 'renderer/pepper/ppb_widget_impl.cc',
+ 'renderer/pepper/ppb_widget_impl.h',
+ 'renderer/pepper/ppb_x509_certificate_private_impl.cc',
+ 'renderer/pepper/ppb_x509_certificate_private_impl.h',
+ 'renderer/pepper/quota_file_io.cc',
+ 'renderer/pepper/quota_file_io.h',
'renderer/pepper/renderer_ppapi_host_impl.cc',
'renderer/pepper/renderer_ppapi_host_impl.h',
+ 'renderer/pepper/resource_creation_impl.cc',
+ 'renderer/pepper/resource_creation_impl.h',
+ 'renderer/pepper/resource_helper.cc',
+ 'renderer/pepper/resource_helper.h',
+ 'renderer/pepper/url_request_info_util.cc',
+ '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.h',
+ 'renderer/pepper/usb_key_code_conversion.cc',
+ '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/v8_var_converter.cc',
+ 'renderer/pepper/v8_var_converter.h',
'renderer/plugin_channel_host.cc',
'renderer/plugin_channel_host.h',
'renderer/browser_plugin/browser_plugin.cc',
@@ -601,6 +685,13 @@
'renderer/media/crypto/ppapi_decryptor.h',
],
}],
+ ['enable_gpu!=1', {
+ 'sources!': [
+ 'renderer/pepper/ppb_graphics_3d_impl.cc',
+ 'renderer/pepper/ppb_graphics_3d_impl.h',
+ 'renderer/pepper/ppb_open_gl_es_impl.cc',
+ ],
+ }],
],
'target_conditions': [
['OS=="android"', {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 9e2564d..6f1c0efe 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -430,10 +430,21 @@
'renderer/media/video_capture_message_filter_unittest.cc',
'renderer/media/webaudiosourceprovider_impl_unittest.cc',
'renderer/paint_aggregator_unittest.cc',
- 'renderer/skia_benchmarking_extension_unittest.cc',
+ 'renderer/pepper/host_var_tracker_unittest.cc',
+ 'renderer/pepper/mock_platform_image_2d.cc',
+ 'renderer/pepper/mock_platform_image_2d.h',
+ 'renderer/pepper/mock_plugin_delegate.cc',
+ 'renderer/pepper/mock_plugin_delegate.h',
+ 'renderer/pepper/mock_resource.h',
+ 'renderer/pepper/ppapi_plugin_instance_unittest.cc',
+ 'renderer/pepper/ppapi_unittest.cc',
+ 'renderer/pepper/ppapi_unittest.h',
+ 'renderer/pepper/quota_file_io_unittest.cc',
+ 'renderer/pepper/v8_var_converter_unittest.cc',
'renderer/pepper/pepper_broker_impl_unittest.cc',
'renderer/render_thread_impl_unittest.cc',
'renderer/render_view_impl_unittest.cc',
+ 'renderer/skia_benchmarking_extension_unittest.cc',
'renderer/v8_value_converter_impl_unittest.cc',
'renderer/webplugin_impl_unittest.cc',
'test/image_decoder_test.cc',
@@ -531,17 +542,6 @@
'../webkit/mocks/mock_weburlloader.cc',
'../webkit/mocks/mock_weburlloader.h',
'../webkit/common/user_agent/user_agent_unittest.cc',
- '../webkit/plugins/ppapi/host_var_tracker_unittest.cc',
- '../webkit/plugins/ppapi/mock_platform_image_2d.cc',
- '../webkit/plugins/ppapi/mock_platform_image_2d.h',
- '../webkit/plugins/ppapi/mock_plugin_delegate.cc',
- '../webkit/plugins/ppapi/mock_plugin_delegate.h',
- '../webkit/plugins/ppapi/mock_resource.h',
- '../webkit/plugins/ppapi/ppapi_plugin_instance_unittest.cc',
- '../webkit/plugins/ppapi/ppapi_unittest.cc',
- '../webkit/plugins/ppapi/ppapi_unittest.h',
- '../webkit/plugins/ppapi/quota_file_io_unittest.cc',
- '../webkit/plugins/ppapi/v8_var_converter_unittest.cc',
'../webkit/browser/quota/mock_quota_manager.cc',
'../webkit/browser/quota/mock_quota_manager.h',
'../webkit/browser/quota/mock_quota_manager_unittest.cc',
@@ -848,6 +848,10 @@
'renderer/dom_serializer_browsertest.cc',
'renderer/mouse_lock_dispatcher_browsertest.cc',
'renderer/password_form_conversion_utils_browsertest.cc',
+ 'renderer/pepper/mock_platform_image_2d.cc',
+ 'renderer/pepper/mock_platform_image_2d.h',
+ 'renderer/pepper/mock_plugin_delegate.cc',
+ 'renderer/pepper/mock_plugin_delegate.h',
'renderer/pepper/mock_renderer_ppapi_host.cc',
'renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc',
'renderer/pepper/pepper_file_chooser_host_unittest.cc',
@@ -868,10 +872,6 @@
'test/content_browser_test_utils_mac.mm',
'test/content_browser_test_test.cc',
'test/content_test_launcher.cc',
- '../webkit/plugins/ppapi/mock_platform_image_2d.cc',
- '../webkit/plugins/ppapi/mock_platform_image_2d.h',
- '../webkit/plugins/ppapi/mock_plugin_delegate.cc',
- '../webkit/plugins/ppapi/mock_plugin_delegate.h',
'../webkit/renderer/cpp_binding_example.cc',
'../webkit/renderer/cpp_binding_example.h',
],
@@ -969,12 +969,12 @@
],
}],
['enable_plugins==0', {
+ 'sources/': [
+ ['exclude', '^renderer/pepper/'],
+ ],
'sources!': [
'browser/plugin_service_impl_browsertest.cc',
'browser/plugin_data_remover_impl_browsertest.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',
],
}],
['enable_pepper_cdms==1', {
diff --git a/content/ppapi_plugin/ppapi_thread.h b/content/ppapi_plugin/ppapi_thread.h
index 9fb56c1..7726a98 100644
--- a/content/ppapi_plugin/ppapi_thread.h
+++ b/content/ppapi_plugin/ppapi_thread.h
@@ -15,13 +15,13 @@
#include "base/scoped_native_library.h"
#include "build/build_config.h"
#include "content/child/child_thread.h"
+#include "content/public/common/pepper_plugin_info.h"
#include "ipc/ipc_listener.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/trusted/ppp_broker.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/proxy/plugin_proxy_delegate.h"
-#include "webkit/plugins/ppapi/plugin_module.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
@@ -138,7 +138,7 @@ class PpapiThread : public ChildThread,
ppapi::proxy::PluginGlobals plugin_globals_;
// Storage for plugin entry points.
- webkit::ppapi::PluginModule::EntryPoints plugin_entry_points_;
+ PepperPluginInfo::EntryPoints plugin_entry_points_;
// Callback to call when a new instance connects to the broker.
// Used only when is_broker_.
diff --git a/content/public/common/pepper_plugin_info.cc b/content/public/common/pepper_plugin_info.cc
index f8e88b2..21ef4e8 100644
--- a/content/public/common/pepper_plugin_info.cc
+++ b/content/public/common/pepper_plugin_info.cc
@@ -8,6 +8,12 @@
namespace content {
+PepperPluginInfo::EntryPoints::EntryPoints()
+ : get_interface(NULL),
+ initialize_module(NULL),
+ shutdown_module(NULL) {
+}
+
PepperPluginInfo::PepperPluginInfo()
: is_internal(false),
is_out_of_process(false),
diff --git a/content/public/common/pepper_plugin_info.h b/content/public/common/pepper_plugin_info.h
index 8106c6e..3cd54bc 100644
--- a/content/public/common/pepper_plugin_info.h
+++ b/content/public/common/pepper_plugin_info.h
@@ -11,11 +11,25 @@
#include "base/files/file_path.h"
#include "content/common/content_export.h"
#include "content/public/common/webplugininfo.h"
-#include "webkit/plugins/ppapi/plugin_module.h"
+#include "ppapi/c/pp_module.h"
+#include "ppapi/c/ppb.h"
namespace content {
struct CONTENT_EXPORT PepperPluginInfo {
+ typedef const void* (*GetInterfaceFunc)(const char*);
+ typedef int (*PPP_InitializeModuleFunc)(PP_Module, PPB_GetInterface);
+ typedef void (*PPP_ShutdownModuleFunc)();
+
+ struct EntryPoints {
+ // This structure is POD, with the constructor initializing to NULL.
+ CONTENT_EXPORT EntryPoints();
+
+ GetInterfaceFunc get_interface;
+ PPP_InitializeModuleFunc initialize_module;
+ PPP_ShutdownModuleFunc shutdown_module; // Optional, may be NULL.
+ };
+
PepperPluginInfo();
~PepperPluginInfo();
@@ -42,7 +56,7 @@ struct CONTENT_EXPORT PepperPluginInfo {
// When is_internal is set, this contains the function pointers to the
// entry points for the internal plugins.
- webkit::ppapi::PluginModule::EntryPoints internal_entry_points;
+ EntryPoints internal_entry_points;
// Permission bits from ppapi::Permission.
uint32 permissions;
diff --git a/content/public/renderer/ppapi_plugin_instance.h b/content/public/renderer/ppapi_plugin_instance.h
new file mode 100644
index 0000000..1e56e4c
--- /dev/null
+++ b/content/public/renderer/ppapi_plugin_instance.h
@@ -0,0 +1,105 @@
+// 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_PUBLIC_PPAPI_PLUGIN_INSTANCE_H_
+#define CONTENT_PUBLIC_PPAPI_PLUGIN_INSTANCE_H_
+
+#include "base/basictypes.h"
+#include "base/process/process_handle.h"
+#include "content/common/content_export.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/private/ppb_instance_private.h"
+
+class GURL;
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+class RenderView;
+}
+
+namespace gfx {
+class ImageSkia;
+class Rect;
+}
+
+namespace ppapi {
+class PpapiPermissions;
+class VarTracker;
+struct URLRequestInfoData;
+}
+
+namespace IPC {
+struct ChannelHandle;
+}
+
+namespace WebKit {
+class WebPluginContainer;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstance {
+ public:
+ static CONTENT_EXPORT PluginInstance* Get(PP_Instance instance_id);
+
+ virtual ~PluginInstance() {}
+
+ virtual content::RenderView* GetRenderView() = 0;
+
+ virtual WebKit::WebPluginContainer* GetContainer() = 0;
+
+ virtual ::ppapi::VarTracker* GetVarTracker() = 0;
+
+ virtual const GURL& GetPluginURL() = 0;
+
+ // Returns the location of this module.
+ virtual base::FilePath GetModulePath() = 0;
+
+ // Returns a reference to a file with the given path.
+ // The returned object will have a refcount of 0 (just like "new").
+ virtual PP_Resource CreateExternalFileReference(
+ const base::FilePath& external_file_path) = 0;
+
+ // Creates a PPB_ImageData given a Skia image.
+ virtual PP_Resource CreateImage(gfx::ImageSkia* source_image,
+ float scale) = 0;
+
+ // Switches this instance with one that uses the out of process IPC proxy.
+ virtual PP_ExternalPluginResult SwitchToOutOfProcessProxy(
+ const base::FilePath& file_path,
+ ::ppapi::PpapiPermissions permissions,
+ const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) = 0;
+
+ // Set this to true if plugin thinks it will always be on top. This allows us
+ // to use a more optimized painting path in some cases.
+ virtual void SetAlwaysOnTop(bool on_top) = 0;
+
+ // Returns true iff the plugin is a full-page plugin (i.e. not in an iframe
+ // or embedded in a page).
+ virtual bool IsFullPagePlugin() = 0;
+
+ // Switches between fullscreen and normal mode. If |delay_report| is set to
+ // false, it may report the new state through DidChangeView immediately. If
+ // true, it will delay it. When called from the plugin, delay_report should
+ // be true to avoid re-entrancy.
+ virtual void FlashSetFullscreen(bool fullscreen, bool delay_report) = 0;
+
+ virtual bool IsRectTopmost(const gfx::Rect& rect) = 0;
+
+ virtual int32_t Navigate(const ::ppapi::URLRequestInfoData& request,
+ const char* target,
+ bool from_user_action) = 0;
+
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_PUBLIC_PPAPI_PLUGIN_INSTANCE_H_
diff --git a/content/public/renderer/renderer_ppapi_host.h b/content/public/renderer/renderer_ppapi_host.h
index 5b33f7b..5f3caac 100644
--- a/content/public/renderer/renderer_ppapi_host.h
+++ b/content/public/renderer/renderer_ppapi_host.h
@@ -5,13 +5,13 @@
#ifndef CONTENT_PUBLIC_RENDERER_RENDERER_PPAPI_HOST_H_
#define CONTENT_PUBLIC_RENDERER_RENDERER_PPAPI_HOST_H_
+#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/platform_file.h"
#include "base/process.h"
#include "content/common/content_export.h"
#include "ipc/ipc_platform_file.h"
#include "ppapi/c/pp_instance.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
namespace base {
class FilePath;
@@ -38,7 +38,6 @@ class WebPluginContainer;
namespace webkit {
namespace ppapi {
class PluginInstance;
-class PluginModule;
}
}
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.cc b/content/renderer/media/crypto/content_decryption_module_factory.cc
index 71949fc..3138be2 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.cc
+++ b/content/renderer/media/crypto/content_decryption_module_factory.cc
@@ -10,11 +10,11 @@
#if defined(ENABLE_PEPPER_CDMS)
#include "content/renderer/media/crypto/ppapi_decryptor.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppapi_webplugin_impl.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebMediaPlayerClient.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
-#include "webkit/plugins/ppapi/ppapi_webplugin_impl.h"
#elif defined(OS_ANDROID)
#include "content/renderer/media/android/proxy_media_keys.h"
#include "content/renderer/media/android/webmediaplayer_proxy_android.h"
diff --git a/content/renderer/media/crypto/ppapi_decryptor.cc b/content/renderer/media/crypto/ppapi_decryptor.cc
index 33f30c9..7bf2aab8 100644
--- a/content/renderer/media/crypto/ppapi_decryptor.cc
+++ b/content/renderer/media/crypto/ppapi_decryptor.cc
@@ -12,13 +12,13 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "content/renderer/pepper/content_decryptor_delegate.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/data_buffer.h"
#include "media/base/decoder_buffer.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
-#include "webkit/plugins/ppapi/content_decryptor_delegate.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
namespace content {
diff --git a/content/renderer/media/pepper_platform_video_decoder_impl.h b/content/renderer/media/pepper_platform_video_decoder_impl.h
index 686974b..d3fc9a9 100644
--- a/content/renderer/media/pepper_platform_video_decoder_impl.h
+++ b/content/renderer/media/pepper_platform_video_decoder_impl.h
@@ -10,8 +10,8 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "media/video/video_decode_accelerator.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
namespace content {
diff --git a/content/renderer/media/video_destination_handler.cc b/content/renderer/media/video_destination_handler.cc
index 6745acc..39e6a39 100644
--- a/content/renderer/media/video_destination_handler.cc
+++ b/content/renderer/media/video_destination_handler.cc
@@ -11,10 +11,10 @@
#include "base/rand_util.h"
#include "content/renderer/media/media_stream_dependency_factory.h"
#include "content/renderer/media/media_stream_registry_interface.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
-#include "webkit/plugins/ppapi/ppb_image_data_impl.h"
using cricket::CaptureState;
using cricket::VideoFormat;
@@ -85,6 +85,7 @@ bool PpFrameWriter::IsScreencast() const {
void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
int64 time_stamp_ns) {
+#if defined(ENABLE_PLUGINS)
base::AutoLock auto_lock(lock_);
// This assumes the handler of the SignalFrameCaptured won't call Start/Stop.
// TODO(ronghuawu): Avoid the using of lock. One way is to post this call to
@@ -132,6 +133,7 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
// This signals to libJingle that a new VideoFrame is available.
// libJingle have no assumptions on what thread this signal come from.
SignalFrameCaptured(this, &frame);
+#endif
}
// PpFrameWriterProxy is a helper class to make sure the user won't use
diff --git a/content/renderer/media/webmediaplayer_impl.cc b/content/renderer/media/webmediaplayer_impl.cc
index bffda93..dac94c6 100644
--- a/content/renderer/media/webmediaplayer_impl.cc
+++ b/content/renderer/media/webmediaplayer_impl.cc
@@ -28,6 +28,7 @@
#include "content/renderer/media/webmediaplayer_params.h"
#include "content/renderer/media/webmediaplayer_util.h"
#include "content/renderer/media/webmediasourceclient_impl.h"
+#include "content/renderer/pepper/ppapi_webplugin_impl.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "media/audio/null_audio_sink.h"
#include "media/base/bind_to_loop.h"
@@ -55,7 +56,6 @@
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "v8/include/v8.h"
-#include "webkit/plugins/ppapi/ppapi_webplugin_impl.h"
#include "webkit/renderer/compositor_bindings/web_layer_impl.h"
using WebKit::WebCanvas;
diff --git a/content/renderer/pepper/DEPS b/content/renderer/pepper/DEPS
new file mode 100644
index 0000000..0b8e33d
--- /dev/null
+++ b/content/renderer/pepper/DEPS
@@ -0,0 +1,11 @@
+include_rules = [
+ "+ppapi/c",
+ "+ppapi/shared_impl",
+ "+ppapi/thunk",
+ "+printing",
+ "+media/audio",
+ "+media/base",
+ "+media/video",
+ "+ui/base/ime",
+ "+ui/base/range",
+]
diff --git a/content/renderer/pepper/OWNERS b/content/renderer/pepper/OWNERS
index dc19a03..c5db5bd 100644
--- a/content/renderer/pepper/OWNERS
+++ b/content/renderer/pepper/OWNERS
@@ -1,3 +1,6 @@
dmichael@chromium.org
raymes@chromium.org
yzshen@chromium.org
+
+per-file usb_key_code_*=garykac@chromium.org
+per-file usb_key_code_*=wez@chromium.org
diff --git a/content/renderer/pepper/audio_helper.cc b/content/renderer/pepper/audio_helper.cc
new file mode 100644
index 0000000..7eb0d87
--- /dev/null
+++ b/content/renderer/pepper/audio_helper.cc
@@ -0,0 +1,88 @@
+// 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/audio_helper.h"
+
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/c/pp_completion_callback.h"
+
+using ppapi::TrackedCallback;
+
+namespace webkit {
+namespace ppapi {
+
+// AudioHelper -----------------------------------------------------------------
+
+AudioHelper::AudioHelper() : shared_memory_size_for_create_callback_(0) {
+}
+
+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
+ return PP_OK;
+ }
+ return PP_ERROR_FAILED;
+}
+
+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_size = shared_memory_size_for_create_callback_;
+ return PP_OK;
+ }
+ return PP_ERROR_FAILED;
+}
+
+void AudioHelper::StreamCreated(
+ base::SharedMemoryHandle shared_memory_handle,
+ size_t shared_memory_size,
+ base::SyncSocket::Handle socket_handle) {
+ if (TrackedCallback::IsPending(create_callback_)) {
+ // Trusted side of proxy can specify a callback to recieve handles. In
+ // this case we don't need to map any data or start the thread since it
+ // will be handled by the proxy.
+ shared_memory_for_create_callback_.reset(
+ new base::SharedMemory(shared_memory_handle, false));
+ shared_memory_size_for_create_callback_ = shared_memory_size;
+ socket_for_create_callback_.reset(new base::SyncSocket(socket_handle));
+
+ create_callback_->Run(PP_OK);
+
+ // It might be nice to close the handles here to free up some system
+ // resources, but we can't since there's a race condition. The handles must
+ // be valid until they're sent over IPC, which is done from the I/O thread
+ // which will often get done after this code executes. We could do
+ // something more elaborate like an ACK from the plugin or post a task to
+ // the I/O thread and back, but this extra complexity doesn't seem worth it
+ // just to clean up these handles faster.
+ } else {
+ OnSetStreamInfo(shared_memory_handle, shared_memory_size, socket_handle);
+ }
+}
+
+void AudioHelper::SetCreateCallback(
+ scoped_refptr< ::ppapi::TrackedCallback> create_callback) {
+ DCHECK(!TrackedCallback::IsPending(create_callback_));
+ create_callback_ = create_callback;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/audio_helper.h b/content/renderer/pepper/audio_helper.h
new file mode 100644
index 0000000..854ac9a
--- /dev/null
+++ b/content/renderer/pepper/audio_helper.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_AUDIO_HELPER_H_
+#define CONTENT_RENDERER_PEPPER_AUDIO_HELPER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/sync_socket.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+
+namespace webkit {
+namespace ppapi {
+
+class AudioHelper : public PluginDelegate::PlatformAudioOutputClient {
+ public:
+ AudioHelper();
+ virtual ~AudioHelper();
+
+ // |PluginDelegate::PlatformAudioOutputClient| implementation.
+ virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle,
+ size_t shared_memory_size_,
+ base::SyncSocket::Handle socket) OVERRIDE;
+
+ void SetCreateCallback(
+ scoped_refptr< ::ppapi::TrackedCallback> create_callback);
+
+ protected:
+ // TODO(viettrungluu): This is all very poorly thought out. Refactor.
+
+ // To be called by implementations of |PPB_Audio_API|/|PPB_AudioInput_API|.
+ int32_t GetSyncSocketImpl(int* sync_socket);
+ int32_t GetSharedMemoryImpl(int* shm_handle, uint32_t* shm_size);
+
+ // To be implemented by subclasses to call their |SetStreamInfo()|.
+ virtual void OnSetStreamInfo(base::SharedMemoryHandle shared_memory_handle,
+ size_t shared_memory_size,
+ base::SyncSocket::Handle socket_handle) = 0;
+
+ private:
+ scoped_refptr< ::ppapi::TrackedCallback> create_callback_;
+
+ // When a create callback is being issued, these will save the info for
+ // querying from the callback. The proxy uses this to get the handles to the
+ // other process instead of mapping them in the renderer. These will be
+ // invalid all other times.
+ scoped_ptr<base::SharedMemory> shared_memory_for_create_callback_;
+ size_t shared_memory_size_for_create_callback_;
+ scoped_ptr<base::SyncSocket> socket_for_create_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioHelper);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_AUDIO_HELPER_H_
diff --git a/content/renderer/pepper/common.h b/content/renderer/pepper/common.h
new file mode 100644
index 0000000..ed51b62
--- /dev/null
+++ b/content/renderer/pepper/common.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_PEPPER_COMMON_H_
+#define CONTENT_RENDERER_PEPPER_COMMON_H_
+
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_var.h"
+
+namespace webkit {
+namespace ppapi {
+
+inline PP_Bool BoolToPPBool(bool value) {
+ return value ? PP_TRUE : PP_FALSE;
+}
+
+inline bool PPBoolToBool(PP_Bool value) {
+ return (PP_TRUE == value);
+}
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_COMMON_H_
+
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc
new file mode 100644
index 0000000..79d9cff
--- /dev/null
+++ b/content/renderer/pepper/content_decryptor_delegate.cc
@@ -0,0 +1,1051 @@
+// 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/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/safe_numerics.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_loop.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/video_decoder_config.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_buffer_api.h"
+#include "ui/gfx/rect.h"
+
+using ppapi::ArrayBufferVar;
+using ppapi::PpapiGlobals;
+using ppapi::ScopedPPResource;
+using ppapi::StringVar;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Buffer_API;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+// Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
+// resource. The |*resource|, if valid, will be in the ResourceTracker with a
+// 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, uint32_t size,
+ scoped_refptr<PPB_Buffer_Impl>* resource) {
+ TRACE_EVENT0("eme", "ContentDecryptorDelegate - MakeBufferResource");
+ DCHECK(resource);
+
+ if (!data || !size) {
+ DCHECK(!data && !size);
+ resource = NULL;
+ return true;
+ }
+
+ scoped_refptr<PPB_Buffer_Impl> buffer(
+ PPB_Buffer_Impl::CreateResource(instance, size));
+ if (!buffer.get())
+ return false;
+
+ BufferAutoMapper mapper(buffer.get());
+ if (!mapper.data() || mapper.size() < size)
+ return false;
+ memcpy(mapper.data(), data, size);
+
+ *resource = buffer;
+ return true;
+}
+
+// Copies the content of |str| into |array|.
+// 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]) {
+ if (array_size < str.size())
+ return false;
+
+ memcpy(array, str.data(), str.size());
+ return true;
+}
+
+// Fills the |block_info| with information from |encrypted_buffer|.
+//
+// Returns true if |block_info| is successfully filled. Returns false
+// otherwise.
+static bool MakeEncryptedBlockInfo(
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ uint32_t request_id,
+ PP_EncryptedBlockInfo* block_info) {
+ // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
+ // anywhere else.
+ memset(block_info, 0, sizeof(*block_info));
+ block_info->tracking_info.request_id = request_id;
+
+ // EOS buffers need a request ID and nothing more.
+ if (encrypted_buffer->end_of_stream())
+ return true;
+
+ DCHECK(encrypted_buffer->data_size())
+ << "DecryptConfig is set on an empty buffer";
+
+ block_info->tracking_info.timestamp =
+ encrypted_buffer->timestamp().InMicroseconds();
+ block_info->data_size = encrypted_buffer->data_size();
+
+ const media::DecryptConfig* decrypt_config =
+ encrypted_buffer->decrypt_config();
+ block_info->data_offset = decrypt_config->data_offset();
+
+ if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
+ !CopyStringToArray(decrypt_config->iv(), block_info->iv))
+ return false;
+
+ block_info->key_id_size = decrypt_config->key_id().size();
+ block_info->iv_size = decrypt_config->iv().size();
+
+ if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
+ return false;
+
+ block_info->num_subsamples = decrypt_config->subsamples().size();
+ for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
+ block_info->subsamples[i].clear_bytes =
+ decrypt_config->subsamples()[i].clear_bytes;
+ block_info->subsamples[i].cipher_bytes =
+ decrypt_config->subsamples()[i].cypher_bytes;
+ }
+
+ return true;
+}
+
+PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
+ switch (codec) {
+ case media::kCodecVorbis:
+ return PP_AUDIOCODEC_VORBIS;
+ case media::kCodecAAC:
+ return PP_AUDIOCODEC_AAC;
+ default:
+ return PP_AUDIOCODEC_UNKNOWN;
+ }
+}
+
+PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
+ switch (codec) {
+ case media::kCodecVP8:
+ return PP_VIDEOCODEC_VP8;
+ case media::kCodecH264:
+ return PP_VIDEOCODEC_H264;
+ default:
+ return PP_VIDEOCODEC_UNKNOWN;
+ }
+}
+
+PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
+ media::VideoCodecProfile profile) {
+ switch (profile) {
+ case media::VP8PROFILE_MAIN:
+ return PP_VIDEOCODECPROFILE_VP8_MAIN;
+ case media::H264PROFILE_BASELINE:
+ return PP_VIDEOCODECPROFILE_H264_BASELINE;
+ case media::H264PROFILE_MAIN:
+ return PP_VIDEOCODECPROFILE_H264_MAIN;
+ case media::H264PROFILE_EXTENDED:
+ return PP_VIDEOCODECPROFILE_H264_EXTENDED;
+ case media::H264PROFILE_HIGH:
+ return PP_VIDEOCODECPROFILE_H264_HIGH;
+ case media::H264PROFILE_HIGH10PROFILE:
+ return PP_VIDEOCODECPROFILE_H264_HIGH_10;
+ case media::H264PROFILE_HIGH422PROFILE:
+ return PP_VIDEOCODECPROFILE_H264_HIGH_422;
+ case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
+ return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
+ default:
+ return PP_VIDEOCODECPROFILE_UNKNOWN;
+ }
+}
+
+PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
+ media::VideoFrame::Format format) {
+ switch (format) {
+ case media::VideoFrame::YV12:
+ return PP_DECRYPTEDFRAMEFORMAT_YV12;
+ case media::VideoFrame::I420:
+ return PP_DECRYPTEDFRAMEFORMAT_I420;
+ default:
+ return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
+ }
+}
+
+media::Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
+ PP_DecryptResult result) {
+ switch (result) {
+ case PP_DECRYPTRESULT_SUCCESS:
+ return media::Decryptor::kSuccess;
+ case PP_DECRYPTRESULT_DECRYPT_NOKEY:
+ return media::Decryptor::kNoKey;
+ case PP_DECRYPTRESULT_NEEDMOREDATA:
+ return media::Decryptor::kNeedMoreData;
+ case PP_DECRYPTRESULT_DECRYPT_ERROR:
+ return media::Decryptor::kError;
+ case PP_DECRYPTRESULT_DECODE_ERROR:
+ return media::Decryptor::kError;
+ default:
+ NOTREACHED();
+ return media::Decryptor::kError;
+ }
+}
+
+PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
+ media::Decryptor::StreamType stream_type) {
+ switch (stream_type) {
+ case media::Decryptor::kAudio:
+ return PP_DECRYPTORSTREAMTYPE_AUDIO;
+ case media::Decryptor::kVideo:
+ return PP_DECRYPTORSTREAMTYPE_VIDEO;
+ default:
+ NOTREACHED();
+ return PP_DECRYPTORSTREAMTYPE_VIDEO;
+ }
+}
+
+} // namespace
+
+ContentDecryptorDelegate::ContentDecryptorDelegate(
+ PP_Instance pp_instance,
+ const PPP_ContentDecryptor_Private* plugin_decryption_interface)
+ : pp_instance_(pp_instance),
+ plugin_decryption_interface_(plugin_decryption_interface),
+ next_decryption_request_id_(1),
+ pending_audio_decrypt_request_id_(0),
+ pending_video_decrypt_request_id_(0),
+ pending_audio_decoder_init_request_id_(0),
+ pending_video_decoder_init_request_id_(0),
+ pending_audio_decode_request_id_(0),
+ pending_video_decode_request_id_(0),
+ weak_ptr_factory_(this),
+ weak_this_(weak_ptr_factory_.GetWeakPtr()),
+ audio_sample_format_(media::kUnknownSampleFormat),
+ audio_samples_per_second_(0),
+ audio_channel_count_(0),
+ audio_bytes_per_frame_(0) {
+}
+
+ContentDecryptorDelegate::~ContentDecryptorDelegate() {
+}
+
+void ContentDecryptorDelegate::Initialize(const std::string& key_system) {
+ // TODO(ddorwin): Add an Initialize method to PPP_ContentDecryptor_Private.
+ DCHECK(!key_system.empty());
+ key_system_ = key_system;
+}
+
+void ContentDecryptorDelegate::SetKeyEventCallbacks(
+ const media::KeyAddedCB& key_added_cb,
+ const media::KeyErrorCB& key_error_cb,
+ const media::KeyMessageCB& key_message_cb) {
+ key_added_cb_ = key_added_cb;
+ key_error_cb_ = key_error_cb;
+ key_message_cb_ = key_message_cb;
+}
+
+bool ContentDecryptorDelegate::GenerateKeyRequest(const std::string& type,
+ const uint8* init_data,
+ int init_data_length) {
+ PP_Var init_data_array =
+ PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
+ init_data_length, init_data);
+
+ plugin_decryption_interface_->GenerateKeyRequest(
+ pp_instance_,
+ StringVar::StringToPPVar(key_system_), // TODO(ddorwin): Remove.
+ StringVar::StringToPPVar(type),
+ init_data_array);
+ return true;
+}
+
+bool ContentDecryptorDelegate::AddKey(const std::string& session_id,
+ const uint8* key,
+ int key_length,
+ const uint8* init_data,
+ int init_data_length) {
+ PP_Var key_array =
+ PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(key_length,
+ key);
+ PP_Var init_data_array =
+ PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
+ init_data_length, init_data);
+
+ plugin_decryption_interface_->AddKey(
+ pp_instance_,
+ StringVar::StringToPPVar(session_id),
+ key_array,
+ init_data_array);
+ return true;
+}
+
+bool ContentDecryptorDelegate::CancelKeyRequest(const std::string& session_id) {
+ plugin_decryption_interface_->CancelKeyRequest(
+ pp_instance_,
+ StringVar::StringToPPVar(session_id));
+ return true;
+}
+
+// TODO(xhwang): Remove duplication of code in Decrypt(),
+// DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
+bool ContentDecryptorDelegate::Decrypt(
+ media::Decryptor::StreamType stream_type,
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ const media::Decryptor::DecryptCB& decrypt_cb) {
+ DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
+ // |{audio|video}_input_resource_| is not being used by the plugin
+ // now because there is only one pending audio/video decrypt request at any
+ // time. This is enforced by the media pipeline.
+ scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
+ if (!MakeMediaBufferResource(
+ stream_type, encrypted_buffer, &encrypted_resource) ||
+ !encrypted_resource.get()) {
+ return false;
+ }
+ ScopedPPResource pp_resource(encrypted_resource.get());
+
+ const uint32_t request_id = next_decryption_request_id_++;
+ DVLOG(2) << "Decrypt() - request_id " << request_id;
+
+ PP_EncryptedBlockInfo block_info = {};
+ DCHECK(encrypted_buffer->decrypt_config());
+ if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
+ return false;
+ }
+
+ // There is only one pending decrypt request at any time per stream. This is
+ // enforced by the media pipeline.
+ switch (stream_type) {
+ case media::Decryptor::kAudio:
+ DCHECK_EQ(pending_audio_decrypt_request_id_, 0u);
+ DCHECK(pending_audio_decrypt_cb_.is_null());
+ pending_audio_decrypt_request_id_ = request_id;
+ pending_audio_decrypt_cb_ = decrypt_cb;
+ break;
+ case media::Decryptor::kVideo:
+ DCHECK_EQ(pending_video_decrypt_request_id_, 0u);
+ DCHECK(pending_video_decrypt_cb_.is_null());
+ pending_video_decrypt_request_id_ = request_id;
+ pending_video_decrypt_cb_ = decrypt_cb;
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
+
+ plugin_decryption_interface_->Decrypt(pp_instance_,
+ pp_resource,
+ &block_info);
+ return true;
+}
+
+bool ContentDecryptorDelegate::CancelDecrypt(
+ media::Decryptor::StreamType stream_type) {
+ DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
+
+ media::Decryptor::DecryptCB decrypt_cb;
+ switch (stream_type) {
+ case media::Decryptor::kAudio:
+ // Release the shared memory as it can still be in use by the plugin.
+ // The next Decrypt() call will need to allocate a new shared memory
+ // buffer.
+ audio_input_resource_ = NULL;
+ pending_audio_decrypt_request_id_ = 0;
+ decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_);
+ break;
+ case media::Decryptor::kVideo:
+ // Release the shared memory as it can still be in use by the plugin.
+ // The next Decrypt() call will need to allocate a new shared memory
+ // buffer.
+ video_input_resource_ = NULL;
+ pending_video_decrypt_request_id_ = 0;
+ decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_);
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ if (!decrypt_cb.is_null())
+ decrypt_cb.Run(media::Decryptor::kSuccess, NULL);
+
+ return true;
+}
+
+bool ContentDecryptorDelegate::InitializeAudioDecoder(
+ const media::AudioDecoderConfig& decoder_config,
+ const media::Decryptor::DecoderInitCB& init_cb) {
+ PP_AudioDecoderConfig pp_decoder_config;
+ pp_decoder_config.codec =
+ MediaAudioCodecToPpAudioCodec(decoder_config.codec());
+ pp_decoder_config.channel_count =
+ media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
+ pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
+ pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
+ pp_decoder_config.request_id = next_decryption_request_id_++;
+
+ audio_sample_format_ = decoder_config.sample_format();
+ audio_samples_per_second_ = pp_decoder_config.samples_per_second;
+ audio_channel_count_ = pp_decoder_config.channel_count;
+ audio_bytes_per_frame_ = decoder_config.bytes_per_frame();
+
+ scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
+ if (!MakeBufferResource(pp_instance_,
+ decoder_config.extra_data(),
+ decoder_config.extra_data_size(),
+ &extra_data_resource)) {
+ return false;
+ }
+ ScopedPPResource pp_resource(extra_data_resource.get());
+
+ DCHECK_EQ(pending_audio_decoder_init_request_id_, 0u);
+ DCHECK(pending_audio_decoder_init_cb_.is_null());
+ pending_audio_decoder_init_request_id_ = pp_decoder_config.request_id;
+ pending_audio_decoder_init_cb_ = init_cb;
+
+ plugin_decryption_interface_->InitializeAudioDecoder(pp_instance_,
+ &pp_decoder_config,
+ pp_resource);
+ return true;
+}
+
+bool ContentDecryptorDelegate::InitializeVideoDecoder(
+ const media::VideoDecoderConfig& decoder_config,
+ const media::Decryptor::DecoderInitCB& init_cb) {
+ PP_VideoDecoderConfig pp_decoder_config;
+ pp_decoder_config.codec =
+ MediaVideoCodecToPpVideoCodec(decoder_config.codec());
+ pp_decoder_config.profile =
+ MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
+ pp_decoder_config.format =
+ MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
+ pp_decoder_config.width = decoder_config.coded_size().width();
+ pp_decoder_config.height = decoder_config.coded_size().height();
+ pp_decoder_config.request_id = next_decryption_request_id_++;
+
+ scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
+ if (!MakeBufferResource(pp_instance_,
+ decoder_config.extra_data(),
+ decoder_config.extra_data_size(),
+ &extra_data_resource)) {
+ return false;
+ }
+ ScopedPPResource pp_resource(extra_data_resource.get());
+
+ DCHECK_EQ(pending_video_decoder_init_request_id_, 0u);
+ DCHECK(pending_video_decoder_init_cb_.is_null());
+ pending_video_decoder_init_request_id_ = pp_decoder_config.request_id;
+ pending_video_decoder_init_cb_ = init_cb;
+
+ natural_size_ = decoder_config.natural_size();
+
+ plugin_decryption_interface_->InitializeVideoDecoder(pp_instance_,
+ &pp_decoder_config,
+ pp_resource);
+ return true;
+}
+
+bool ContentDecryptorDelegate::DeinitializeDecoder(
+ media::Decryptor::StreamType stream_type) {
+ CancelDecode(stream_type);
+
+ natural_size_ = gfx::Size();
+
+ // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
+ // stream type from media stack.
+ plugin_decryption_interface_->DeinitializeDecoder(
+ pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
+ return true;
+}
+
+bool ContentDecryptorDelegate::ResetDecoder(
+ media::Decryptor::StreamType stream_type) {
+ CancelDecode(stream_type);
+
+ // TODO(tomfinegan): Add decoder reset request tracking.
+ plugin_decryption_interface_->ResetDecoder(
+ pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
+ return true;
+}
+
+bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ const media::Decryptor::AudioDecodeCB& audio_decode_cb) {
+ // |audio_input_resource_| is not being used by the plugin now
+ // because there is only one pending audio decode request at any time.
+ // This is enforced by the media pipeline.
+ scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
+ if (!MakeMediaBufferResource(media::Decryptor::kAudio,
+ encrypted_buffer,
+ &encrypted_resource)) {
+ return false;
+ }
+
+ // The resource should not be NULL for non-EOS buffer.
+ if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
+ return false;
+
+ const uint32_t request_id = next_decryption_request_id_++;
+ DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
+
+ PP_EncryptedBlockInfo block_info = {};
+ if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
+ return false;
+ }
+
+ SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
+
+ // There is only one pending audio decode request at any time. This is
+ // enforced by the media pipeline. If this DCHECK is violated, our buffer
+ // reuse policy is not valid, and we may have race problems for the shared
+ // buffer.
+ DCHECK_EQ(pending_audio_decode_request_id_, 0u);
+ DCHECK(pending_audio_decode_cb_.is_null());
+ pending_audio_decode_request_id_ = request_id;
+ pending_audio_decode_cb_ = audio_decode_cb;
+
+ ScopedPPResource pp_resource(encrypted_resource.get());
+ plugin_decryption_interface_->DecryptAndDecode(pp_instance_,
+ PP_DECRYPTORSTREAMTYPE_AUDIO,
+ pp_resource,
+ &block_info);
+ return true;
+}
+
+bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ const media::Decryptor::VideoDecodeCB& video_decode_cb) {
+ // |video_input_resource_| is not being used by the plugin now
+ // because there is only one pending video decode request at any time.
+ // This is enforced by the media pipeline.
+ scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
+ if (!MakeMediaBufferResource(media::Decryptor::kVideo,
+ encrypted_buffer,
+ &encrypted_resource)) {
+ return false;
+ }
+
+ // The resource should not be 0 for non-EOS buffer.
+ if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
+ return false;
+
+ const uint32_t request_id = next_decryption_request_id_++;
+ DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
+ TRACE_EVENT_ASYNC_BEGIN0(
+ "eme", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
+
+ PP_EncryptedBlockInfo block_info = {};
+ if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
+ return false;
+ }
+
+ SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
+
+ // Only one pending video decode request at any time. This is enforced by the
+ // media pipeline. If this DCHECK is violated, our buffer
+ // reuse policy is not valid, and we may have race problems for the shared
+ // buffer.
+ DCHECK_EQ(pending_video_decode_request_id_, 0u);
+ DCHECK(pending_video_decode_cb_.is_null());
+ pending_video_decode_request_id_ = request_id;
+ pending_video_decode_cb_ = video_decode_cb;
+
+ // TODO(tomfinegan): Need to get stream type from media stack.
+ ScopedPPResource pp_resource(encrypted_resource.get());
+ plugin_decryption_interface_->DecryptAndDecode(pp_instance_,
+ PP_DECRYPTORSTREAMTYPE_VIDEO,
+ pp_resource,
+ &block_info);
+ return true;
+}
+
+void ContentDecryptorDelegate::NeedKey(PP_Var key_system_var,
+ PP_Var session_id_var,
+ PP_Var init_data_var) {
+ // TODO(ddorwin): Remove from PPB_ContentDecryptor_Private.
+ NOTREACHED();
+}
+
+void ContentDecryptorDelegate::KeyAdded(PP_Var key_system_var,
+ PP_Var session_id_var) {
+ if (key_added_cb_.is_null())
+ return;
+
+ StringVar* session_id_string = StringVar::FromPPVar(session_id_var);
+ if (!session_id_string) {
+ key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
+ return;
+ }
+
+ key_added_cb_.Run(session_id_string->value());
+}
+
+void ContentDecryptorDelegate::KeyMessage(PP_Var key_system_var,
+ PP_Var session_id_var,
+ PP_Var message_var,
+ PP_Var default_url_var) {
+ if (key_message_cb_.is_null())
+ return;
+
+ StringVar* session_id_string = StringVar::FromPPVar(session_id_var);
+
+ ArrayBufferVar* message_array_buffer =
+ ArrayBufferVar::FromPPVar(message_var);
+
+ std::vector<uint8> message;
+ if (message_array_buffer) {
+ const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
+ message.assign(data, data + message_array_buffer->ByteLength());
+ }
+
+ StringVar* default_url_string = StringVar::FromPPVar(default_url_var);
+
+ if (!session_id_string || !default_url_string) {
+ key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
+ return;
+ }
+
+ key_message_cb_.Run(session_id_string->value(),
+ message,
+ default_url_string->value());
+}
+
+void ContentDecryptorDelegate::KeyError(PP_Var key_system_var,
+ PP_Var session_id_var,
+ int32_t media_error,
+ int32_t system_code) {
+ if (key_error_cb_.is_null())
+ return;
+
+ StringVar* session_id_string = StringVar::FromPPVar(session_id_var);
+ if (!session_id_string) {
+ key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
+ return;
+ }
+
+ key_error_cb_.Run(session_id_string->value(),
+ static_cast<media::MediaKeys::KeyError>(media_error),
+ system_code);
+}
+
+void ContentDecryptorDelegate::DecoderInitializeDone(
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id,
+ PP_Bool success) {
+ if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
+ // If the request ID is not valid or does not match what's saved, do
+ // nothing.
+ if (request_id == 0 ||
+ request_id != pending_audio_decoder_init_request_id_)
+ return;
+
+ DCHECK(!pending_audio_decoder_init_cb_.is_null());
+ pending_audio_decoder_init_request_id_ = 0;
+ base::ResetAndReturn(
+ &pending_audio_decoder_init_cb_).Run(PP_ToBool(success));
+ } else {
+ if (request_id == 0 ||
+ request_id != pending_video_decoder_init_request_id_)
+ return;
+
+ if (!success)
+ natural_size_ = gfx::Size();
+
+ DCHECK(!pending_video_decoder_init_cb_.is_null());
+ pending_video_decoder_init_request_id_ = 0;
+ base::ResetAndReturn(
+ &pending_video_decoder_init_cb_).Run(PP_ToBool(success));
+ }
+}
+
+void ContentDecryptorDelegate::DecoderDeinitializeDone(
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id) {
+ // TODO(tomfinegan): Add decoder stop completion handling.
+}
+
+void ContentDecryptorDelegate::DecoderResetDone(
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id) {
+ // TODO(tomfinegan): Add decoder reset completion handling.
+}
+
+void ContentDecryptorDelegate::DeliverBlock(
+ PP_Resource decrypted_block,
+ const PP_DecryptedBlockInfo* block_info) {
+ DCHECK(block_info);
+
+ FreeBuffer(block_info->tracking_info.buffer_id);
+
+ const uint32_t request_id = block_info->tracking_info.request_id;
+ DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
+
+ // If the request ID is not valid or does not match what's saved, do nothing.
+ if (request_id == 0) {
+ DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
+ return;
+ }
+
+ media::Decryptor::DecryptCB decrypt_cb;
+ if (request_id == pending_audio_decrypt_request_id_) {
+ DCHECK(!pending_audio_decrypt_cb_.is_null());
+ pending_audio_decrypt_request_id_ = 0;
+ decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_);
+ } else if (request_id == pending_video_decrypt_request_id_) {
+ DCHECK(!pending_video_decrypt_cb_.is_null());
+ pending_video_decrypt_request_id_ = 0;
+ decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_);
+ } else {
+ DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
+ return;
+ }
+
+ media::Decryptor::Status status =
+ PpDecryptResultToMediaDecryptorStatus(block_info->result);
+ if (status != media::Decryptor::kSuccess) {
+ decrypt_cb.Run(status, NULL);
+ return;
+ }
+
+ EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
+ if (!enter.succeeded()) {
+ decrypt_cb.Run(media::Decryptor::kError, NULL);
+ return;
+ }
+ BufferAutoMapper mapper(enter.object());
+ if (!mapper.data() || !mapper.size() ||
+ mapper.size() < block_info->data_size) {
+ decrypt_cb.Run(media::Decryptor::kError, NULL);
+ return;
+ }
+
+ // 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()), block_info->data_size));
+ decrypted_buffer->set_timestamp(base::TimeDelta::FromMicroseconds(
+ block_info->tracking_info.timestamp));
+ decrypt_cb.Run(media::Decryptor::kSuccess, decrypted_buffer);
+}
+
+// Use a non-class-member function here so that if for some reason
+// ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
+// we can still get the shared memory unmapped.
+static void BufferNoLongerNeeded(
+ const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
+ base::Closure buffer_no_longer_needed_cb) {
+ ppb_buffer->Unmap();
+ buffer_no_longer_needed_cb.Run();
+}
+
+// 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) {
+ EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
+ if (!enter.succeeded())
+ return NULL;
+
+ uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
+ if (!enter.object()->IsMapped() || !mapped_data)
+ return NULL;
+
+ uint32_t mapped_size = 0;
+ if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
+ enter.object()->Unmap();
+ return NULL;
+ }
+
+ *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
+
+ return mapped_data;
+}
+
+void ContentDecryptorDelegate::DeliverFrame(
+ PP_Resource decrypted_frame,
+ const PP_DecryptedFrameInfo* frame_info) {
+ DCHECK(frame_info);
+
+ const uint32_t request_id = frame_info->tracking_info.request_id;
+ DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
+
+ // If the request ID is not valid or does not match what's saved, do nothing.
+ if (request_id == 0 || request_id != pending_video_decode_request_id_) {
+ DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
+ FreeBuffer(frame_info->tracking_info.buffer_id);
+ return;
+ }
+
+ TRACE_EVENT_ASYNC_END0(
+ "eme", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
+
+ DCHECK(!pending_video_decode_cb_.is_null());
+ pending_video_decode_request_id_ = 0;
+ media::Decryptor::VideoDecodeCB video_decode_cb =
+ base::ResetAndReturn(&pending_video_decode_cb_);
+
+ media::Decryptor::Status status =
+ PpDecryptResultToMediaDecryptorStatus(frame_info->result);
+ if (status != media::Decryptor::kSuccess) {
+ DCHECK(!frame_info->tracking_info.buffer_id);
+ video_decode_cb.Run(status, NULL);
+ return;
+ }
+
+ scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
+ uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
+ if (!frame_data) {
+ FreeBuffer(frame_info->tracking_info.buffer_id);
+ video_decode_cb.Run(media::Decryptor::kError, NULL);
+ return;
+ }
+
+ gfx::Size frame_size(frame_info->width, frame_info->height);
+ DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
+
+ scoped_refptr<media::VideoFrame> decoded_frame =
+ media::VideoFrame::WrapExternalYuvData(
+ media::VideoFrame::YV12,
+ frame_size, gfx::Rect(frame_size), natural_size_,
+ frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
+ frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
+ frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
+ frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
+ frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
+ frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
+ base::TimeDelta::FromMicroseconds(
+ frame_info->tracking_info.timestamp),
+ ppb_buffer->shared_memory()->handle(),
+ media::BindToLoop(
+ base::MessageLoopProxy::current(),
+ base::Bind(&BufferNoLongerNeeded, ppb_buffer,
+ base::Bind(&ContentDecryptorDelegate::FreeBuffer,
+ weak_this_,
+ frame_info->tracking_info.buffer_id))));
+
+ video_decode_cb.Run(media::Decryptor::kSuccess, decoded_frame);
+}
+
+void ContentDecryptorDelegate::DeliverSamples(
+ PP_Resource audio_frames,
+ const PP_DecryptedBlockInfo* block_info) {
+ DCHECK(block_info);
+
+ FreeBuffer(block_info->tracking_info.buffer_id);
+
+ const uint32_t request_id = block_info->tracking_info.request_id;
+ DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
+
+ // If the request ID is not valid or does not match what's saved, do nothing.
+ if (request_id == 0 || request_id != pending_audio_decode_request_id_) {
+ DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
+ return;
+ }
+
+ DCHECK(!pending_audio_decode_cb_.is_null());
+ pending_audio_decode_request_id_ = 0;
+ media::Decryptor::AudioDecodeCB audio_decode_cb =
+ base::ResetAndReturn(&pending_audio_decode_cb_);
+
+ const media::Decryptor::AudioBuffers empty_frames;
+
+ media::Decryptor::Status status =
+ PpDecryptResultToMediaDecryptorStatus(block_info->result);
+ if (status != media::Decryptor::kSuccess) {
+ audio_decode_cb.Run(status, empty_frames);
+ return;
+ }
+
+ media::Decryptor::AudioBuffers audio_frame_list;
+ if (!DeserializeAudioFrames(audio_frames,
+ block_info->data_size,
+ &audio_frame_list)) {
+ NOTREACHED() << "CDM did not serialize the buffer correctly.";
+ audio_decode_cb.Run(media::Decryptor::kError, empty_frames);
+ return;
+ }
+
+ audio_decode_cb.Run(media::Decryptor::kSuccess, audio_frame_list);
+}
+
+// TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
+void ContentDecryptorDelegate::CancelDecode(
+ media::Decryptor::StreamType stream_type) {
+ switch (stream_type) {
+ case media::Decryptor::kAudio:
+ // Release the shared memory as it can still be in use by the plugin.
+ // The next DecryptAndDecode() call will need to allocate a new shared
+ // memory buffer.
+ audio_input_resource_ = NULL;
+ pending_audio_decode_request_id_ = 0;
+ if (!pending_audio_decode_cb_.is_null())
+ base::ResetAndReturn(&pending_audio_decode_cb_).Run(
+ media::Decryptor::kSuccess, media::Decryptor::AudioBuffers());
+ break;
+ case media::Decryptor::kVideo:
+ // Release the shared memory as it can still be in use by the plugin.
+ // The next DecryptAndDecode() call will need to allocate a new shared
+ // memory buffer.
+ video_input_resource_ = NULL;
+ pending_video_decode_request_id_ = 0;
+ if (!pending_video_decode_cb_.is_null())
+ base::ResetAndReturn(&pending_video_decode_cb_).Run(
+ media::Decryptor::kSuccess, NULL);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+bool ContentDecryptorDelegate::MakeMediaBufferResource(
+ media::Decryptor::StreamType stream_type,
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ scoped_refptr<PPB_Buffer_Impl>* resource) {
+ TRACE_EVENT0("eme", "ContentDecryptorDelegate::MakeMediaBufferResource");
+
+ // End of stream buffers are represented as null resources.
+ if (encrypted_buffer->end_of_stream()) {
+ *resource = NULL;
+ return true;
+ }
+
+ DCHECK(stream_type == media::Decryptor::kAudio ||
+ stream_type == media::Decryptor::kVideo);
+ scoped_refptr<PPB_Buffer_Impl>& media_resource =
+ (stream_type == media::Decryptor::kAudio) ? audio_input_resource_ :
+ video_input_resource_;
+
+ const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
+ if (!media_resource.get() || media_resource->size() < data_size) {
+ // Either the buffer hasn't been created yet, or we have one that isn't big
+ // enough to fit |size| bytes.
+
+ // Media resource size starts from |kMinimumMediaBufferSize| and grows
+ // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
+ // which is usually expensive. Since input media buffers are compressed,
+ // they are usually small (compared to outputs). The over-allocated memory
+ // should be negligible.
+ const uint32_t kMinimumMediaBufferSize = 1024;
+ uint32_t media_resource_size =
+ media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
+ while (media_resource_size < data_size)
+ media_resource_size *= 2;
+
+ DVLOG(2) << "Size of media buffer for "
+ << ((stream_type == media::Decryptor::kAudio) ? "audio" : "video")
+ << " stream bumped to " << media_resource_size
+ << " bytes to fit input.";
+ media_resource = PPB_Buffer_Impl::CreateResource(pp_instance_,
+ media_resource_size);
+ if (!media_resource.get())
+ return false;
+ }
+
+ BufferAutoMapper mapper(media_resource.get());
+ if (!mapper.data() || mapper.size() < data_size) {
+ media_resource = NULL;
+ return false;
+ }
+ memcpy(mapper.data(), encrypted_buffer->data(), data_size);
+
+ *resource = media_resource;
+ return true;
+}
+
+void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
+ if (buffer_id)
+ free_buffers_.push(buffer_id);
+}
+
+void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
+ PP_DecryptTrackingInfo* tracking_info) {
+ DCHECK_EQ(tracking_info->buffer_id, 0u);
+
+ if (free_buffers_.empty())
+ return;
+
+ tracking_info->buffer_id = free_buffers_.front();
+ free_buffers_.pop();
+}
+
+bool ContentDecryptorDelegate::DeserializeAudioFrames(
+ PP_Resource audio_frames,
+ size_t data_size,
+ media::Decryptor::AudioBuffers* frames) {
+ DCHECK(frames);
+ EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
+ if (!enter.succeeded())
+ return false;
+
+ BufferAutoMapper mapper(enter.object());
+ if (!mapper.data() || !mapper.size() ||
+ mapper.size() < static_cast<uint32_t>(data_size))
+ return false;
+
+ // 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());
+ size_t bytes_left = data_size;
+
+ do {
+ int64 timestamp = 0;
+ int64 frame_size = -1;
+ const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
+
+ if (bytes_left < kHeaderSize)
+ return false;
+
+ memcpy(&timestamp, cur, sizeof(timestamp));
+ cur += sizeof(timestamp);
+ bytes_left -= sizeof(timestamp);
+
+ memcpy(&frame_size, cur, sizeof(frame_size));
+ cur += sizeof(frame_size);
+ bytes_left -= sizeof(frame_size);
+
+ // We should *not* have empty frames in the list.
+ if (frame_size <= 0 ||
+ bytes_left < base::checked_numeric_cast<size_t>(frame_size)) {
+ return false;
+ }
+
+ const uint8* data[] = {cur};
+ int frame_count = frame_size / audio_bytes_per_frame_;
+ scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
+ audio_sample_format_,
+ audio_channel_count_,
+ frame_count,
+ data,
+ base::TimeDelta::FromMicroseconds(timestamp),
+ base::TimeDelta::FromMicroseconds(audio_samples_per_second_ /
+ frame_count));
+ frames->push_back(frame);
+
+ cur += frame_size;
+ bytes_left -= frame_size;
+ } while (bytes_left > 0);
+
+ return true;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/content_decryptor_delegate.h b/content/renderer/pepper/content_decryptor_delegate.h
new file mode 100644
index 0000000..8f7ad31
--- /dev/null
+++ b/content/renderer/pepper/content_decryptor_delegate.h
@@ -0,0 +1,195 @@
+// 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_CONTENT_DECRYPTOR_DELEGATE_H_
+#define CONTENT_RENDERER_PEPPER_CONTENT_DECRYPTOR_DELEGATE_H_
+
+#include <queue>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "media/base/decryptor.h"
+#include "media/base/media_keys.h"
+#include "media/base/sample_format.h"
+#include "ppapi/c/private/pp_content_decryptor.h"
+#include "ppapi/c/private/ppp_content_decryptor_private.h"
+#include "ui/gfx/size.h"
+
+namespace media {
+class AudioDecoderConfig;
+class DecoderBuffer;
+class VideoDecoderConfig;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Buffer_Impl;
+
+class ContentDecryptorDelegate {
+ public:
+ // ContentDecryptorDelegate does not take ownership of
+ // |plugin_decryption_interface|. Therefore |plugin_decryption_interface|
+ // must outlive this object.
+ ContentDecryptorDelegate(
+ PP_Instance pp_instance,
+ const PPP_ContentDecryptor_Private* plugin_decryption_interface);
+ ~ContentDecryptorDelegate();
+
+ void Initialize(const std::string& key_system);
+
+ void SetKeyEventCallbacks(const media::KeyAddedCB& key_added_cb,
+ const media::KeyErrorCB& key_error_cb,
+ const media::KeyMessageCB& key_message_cb);
+
+ // Provides access to PPP_ContentDecryptor_Private.
+ bool GenerateKeyRequest(const std::string& type,
+ const uint8* init_data,
+ int init_data_length);
+ bool AddKey(const std::string& session_id,
+ const uint8* key,
+ int key_length,
+ const uint8* init_data,
+ int init_data_length);
+ bool CancelKeyRequest(const std::string& session_id);
+ bool Decrypt(media::Decryptor::StreamType stream_type,
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ const media::Decryptor::DecryptCB& decrypt_cb);
+ bool CancelDecrypt(media::Decryptor::StreamType stream_type);
+ bool InitializeAudioDecoder(
+ const media::AudioDecoderConfig& decoder_config,
+ const media::Decryptor::DecoderInitCB& decoder_init_cb);
+ bool InitializeVideoDecoder(
+ const media::VideoDecoderConfig& decoder_config,
+ const media::Decryptor::DecoderInitCB& decoder_init_cb);
+ // TODO(tomfinegan): Add callback args for DeinitializeDecoder() and
+ // ResetDecoder()
+ bool DeinitializeDecoder(media::Decryptor::StreamType stream_type);
+ bool ResetDecoder(media::Decryptor::StreamType stream_type);
+ // Note: These methods can be used with unencrypted data.
+ bool DecryptAndDecodeAudio(
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ const media::Decryptor::AudioDecodeCB& audio_decode_cb);
+ bool DecryptAndDecodeVideo(
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ const media::Decryptor::VideoDecodeCB& video_decode_cb);
+
+ // PPB_ContentDecryptor_Private dispatching methods.
+ // TODO(ddorwin): Remove this method.
+ void NeedKey(PP_Var key_system, PP_Var session_id, PP_Var init_data);
+ // TODO(ddorwin): Remove key_system_var parameter from these methods.
+ void KeyAdded(PP_Var key_system, PP_Var session_id);
+ void KeyMessage(PP_Var key_system,
+ PP_Var session_id,
+ PP_Var message,
+ PP_Var default_url);
+ void KeyError(PP_Var key_system,
+ PP_Var session_id,
+ int32_t media_error,
+ int32_t system_code);
+ void DeliverBlock(PP_Resource decrypted_block,
+ const PP_DecryptedBlockInfo* block_info);
+ void DecoderInitializeDone(PP_DecryptorStreamType decoder_type,
+ uint32_t request_id,
+ PP_Bool success);
+ void DecoderDeinitializeDone(PP_DecryptorStreamType decoder_type,
+ uint32_t request_id);
+ void DecoderResetDone(PP_DecryptorStreamType decoder_type,
+ uint32_t request_id);
+ void DeliverFrame(PP_Resource decrypted_frame,
+ const PP_DecryptedFrameInfo* frame_info);
+ void DeliverSamples(PP_Resource audio_frames,
+ const PP_DecryptedBlockInfo* block_info);
+
+ private:
+ // Cancels the pending decrypt-and-decode callback for |stream_type|.
+ void CancelDecode(media::Decryptor::StreamType stream_type);
+
+ // Fills |resource| with a PPB_Buffer_Impl and copies the data from
+ // |encrypted_buffer| into the buffer resource. This method reuses
+ // |audio_input_resource_| and |video_input_resource_| to reduce the latency
+ // in requesting new PPB_Buffer_Impl resources. The caller must make sure that
+ // |audio_input_resource_| or |video_input_resource_| is available before
+ // calling this method.
+ //
+ // An end of stream |encrypted_buffer| is represented as a null |resource|.
+ //
+ // Returns true upon success and false if any error happened.
+ bool MakeMediaBufferResource(
+ media::Decryptor::StreamType stream_type,
+ const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
+ scoped_refptr<PPB_Buffer_Impl>* resource);
+
+ void FreeBuffer(uint32_t buffer_id);
+
+ void SetBufferToFreeInTrackingInfo(PP_DecryptTrackingInfo* tracking_info);
+
+ // Deserializes audio data stored in |audio_frames| into individual audio
+ // buffers in |frames|. Returns true upon success.
+ bool DeserializeAudioFrames(PP_Resource audio_frames,
+ size_t data_size,
+ media::Decryptor::AudioBuffers* frames);
+
+ const PP_Instance pp_instance_;
+ const PPP_ContentDecryptor_Private* const plugin_decryption_interface_;
+
+ // TODO(ddorwin): Remove after updating the Pepper API to not use key system.
+ std::string key_system_;
+
+ // Callbacks for firing key events.
+ media::KeyAddedCB key_added_cb_;
+ media::KeyErrorCB key_error_cb_;
+ media::KeyMessageCB key_message_cb_;
+
+ gfx::Size natural_size_;
+
+ // Request ID for tracking pending content decryption callbacks.
+ // Note that zero indicates an invalid request ID.
+ // TODO(xhwang): Add completion callbacks for Reset/Stop and remove the use
+ // of request IDs.
+ uint32_t next_decryption_request_id_;
+
+ uint32_t pending_audio_decrypt_request_id_;
+ media::Decryptor::DecryptCB pending_audio_decrypt_cb_;
+
+ uint32_t pending_video_decrypt_request_id_;
+ media::Decryptor::DecryptCB pending_video_decrypt_cb_;
+
+ uint32_t pending_audio_decoder_init_request_id_;
+ media::Decryptor::DecoderInitCB pending_audio_decoder_init_cb_;
+
+ uint32_t pending_video_decoder_init_request_id_;
+ media::Decryptor::DecoderInitCB pending_video_decoder_init_cb_;
+
+ uint32_t pending_audio_decode_request_id_;
+ media::Decryptor::AudioDecodeCB pending_audio_decode_cb_;
+
+ uint32_t pending_video_decode_request_id_;
+ media::Decryptor::VideoDecodeCB pending_video_decode_cb_;
+
+ // Cached audio and video input buffers. See MakeMediaBufferResource.
+ scoped_refptr<PPB_Buffer_Impl> audio_input_resource_;
+ scoped_refptr<PPB_Buffer_Impl> video_input_resource_;
+
+ std::queue<uint32_t> free_buffers_;
+
+ base::WeakPtrFactory<ContentDecryptorDelegate> weak_ptr_factory_;
+ base::WeakPtr<ContentDecryptorDelegate> weak_this_;
+
+ // Keep track of audio parameters.
+ media::SampleFormat audio_sample_format_;
+ int audio_samples_per_second_;
+ int audio_channel_count_;
+ int audio_bytes_per_frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentDecryptorDelegate);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_CONTENT_DECRYPTOR_DELEGATE_H_
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc
new file mode 100644
index 0000000..f912ae5
--- /dev/null
+++ b/content/renderer/pepper/event_conversion.cc
@@ -0,0 +1,735 @@
+// 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/event_conversion.h"
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/i18n/char_iterator.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/pepper/common.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"
+
+using ppapi::EventTimeToPPTimeTicks;
+using ppapi::InputEventData;
+using ppapi::PPTimeTicksToEventTime;
+using WebKit::WebInputEvent;
+using WebKit::WebKeyboardEvent;
+using WebKit::WebMouseEvent;
+using WebKit::WebMouseWheelEvent;
+using WebKit::WebString;
+using WebKit::WebTouchEvent;
+using WebKit::WebTouchPoint;
+using WebKit::WebUChar;
+
+namespace webkit {
+namespace ppapi {
+
+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);
+
+PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) {
+ switch (wetype) {
+ case WebInputEvent::MouseDown:
+ return PP_INPUTEVENT_TYPE_MOUSEDOWN;
+ case WebInputEvent::MouseUp:
+ return PP_INPUTEVENT_TYPE_MOUSEUP;
+ case WebInputEvent::MouseMove:
+ return PP_INPUTEVENT_TYPE_MOUSEMOVE;
+ case WebInputEvent::MouseEnter:
+ return PP_INPUTEVENT_TYPE_MOUSEENTER;
+ case WebInputEvent::MouseLeave:
+ return PP_INPUTEVENT_TYPE_MOUSELEAVE;
+ case WebInputEvent::ContextMenu:
+ return PP_INPUTEVENT_TYPE_CONTEXTMENU;
+ case WebInputEvent::MouseWheel:
+ return PP_INPUTEVENT_TYPE_WHEEL;
+ case WebInputEvent::RawKeyDown:
+ return PP_INPUTEVENT_TYPE_RAWKEYDOWN;
+ case WebInputEvent::KeyDown:
+ return PP_INPUTEVENT_TYPE_KEYDOWN;
+ case WebInputEvent::KeyUp:
+ return PP_INPUTEVENT_TYPE_KEYUP;
+ case WebInputEvent::Char:
+ return PP_INPUTEVENT_TYPE_CHAR;
+ case WebInputEvent::TouchStart:
+ return PP_INPUTEVENT_TYPE_TOUCHSTART;
+ case WebInputEvent::TouchMove:
+ return PP_INPUTEVENT_TYPE_TOUCHMOVE;
+ case WebInputEvent::TouchEnd:
+ return PP_INPUTEVENT_TYPE_TOUCHEND;
+ case WebInputEvent::TouchCancel:
+ return PP_INPUTEVENT_TYPE_TOUCHCANCEL;
+ case WebInputEvent::Undefined:
+ default:
+ return PP_INPUTEVENT_TYPE_UNDEFINED;
+ }
+}
+
+// Generates a PP_InputEvent with the fields common to all events, as well as
+// the event type from the given web event. Event-specific fields will be zero
+// initialized.
+InputEventData GetEventWithCommonFieldsAndType(const WebInputEvent& web_event) {
+ InputEventData result;
+ result.event_type = ConvertEventTypes(web_event.type);
+ result.event_time_stamp = EventTimeToPPTimeTicks(web_event.timeStampSeconds);
+ result.usb_key_code = 0;
+ return result;
+}
+
+void AppendKeyEvent(const WebInputEvent& event,
+ std::vector<InputEventData>* result_events) {
+ const WebKeyboardEvent& key_event =
+ static_cast<const WebKeyboardEvent&>(event);
+ InputEventData result = GetEventWithCommonFieldsAndType(event);
+ result.event_modifiers = key_event.modifiers;
+ result.key_code = key_event.windowsKeyCode;
+ result.usb_key_code = UsbKeyCodeForKeyboardEvent(key_event);
+ result_events->push_back(result);
+}
+
+void AppendCharEvent(const WebInputEvent& event,
+ std::vector<InputEventData>* result_events) {
+ const WebKeyboardEvent& key_event =
+ static_cast<const WebKeyboardEvent&>(event);
+
+ // This is a bit complex, the input event will normally just have one 16-bit
+ // character in it, but may be zero or more than one. The text array is
+ // just padded with 0 values for the unused ones, but is not necessarily
+ // null-terminated.
+ //
+ // Here we see how many UTF-16 characters we have.
+ size_t utf16_char_count = 0;
+ while (utf16_char_count < WebKeyboardEvent::textLengthCap &&
+ key_event.text[utf16_char_count])
+ utf16_char_count++;
+
+ // Make a separate InputEventData for each Unicode character in the input.
+ base::i18n::UTF16CharIterator iter(key_event.text, utf16_char_count);
+ while (!iter.end()) {
+ InputEventData result = GetEventWithCommonFieldsAndType(event);
+ result.event_modifiers = key_event.modifiers;
+ base::WriteUnicodeCharacter(iter.get(), &result.character_text);
+
+ result_events->push_back(result);
+ iter.Advance();
+ }
+}
+
+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);
+
+ const WebMouseEvent& mouse_event =
+ static_cast<const WebMouseEvent&>(event);
+ InputEventData result = GetEventWithCommonFieldsAndType(event);
+ result.event_modifiers = mouse_event.modifiers;
+ if (mouse_event.type == WebInputEvent::MouseDown ||
+ mouse_event.type == WebInputEvent::MouseMove ||
+ mouse_event.type == WebInputEvent::MouseUp) {
+ result.mouse_button =
+ static_cast<PP_InputEvent_MouseButton>(mouse_event.button);
+ }
+ result.mouse_position.x = mouse_event.x;
+ result.mouse_position.y = mouse_event.y;
+ result.mouse_click_count = mouse_event.clickCount;
+ result.mouse_movement.x = mouse_event.movementX;
+ result.mouse_movement.y = mouse_event.movementY;
+ result_events->push_back(result);
+}
+
+void AppendMouseWheelEvent(const WebInputEvent& event,
+ std::vector<InputEventData>* result_events) {
+ const WebMouseWheelEvent& mouse_wheel_event =
+ static_cast<const WebMouseWheelEvent&>(event);
+ InputEventData result = GetEventWithCommonFieldsAndType(event);
+ result.event_modifiers = mouse_wheel_event.modifiers;
+ result.wheel_delta.x = mouse_wheel_event.deltaX;
+ result.wheel_delta.y = mouse_wheel_event.deltaY;
+ result.wheel_ticks.x = mouse_wheel_event.wheelTicksX;
+ result.wheel_ticks.y = mouse_wheel_event.wheelTicksY;
+ result.wheel_scroll_by_page = !!mouse_wheel_event.scrollByPage;
+ result_events->push_back(result);
+}
+
+void SetPPTouchPoints(const WebTouchPoint* touches, uint32_t touches_length,
+ std::vector<PP_TouchPoint>* result) {
+ for (uint32_t i = 0; i < touches_length; i++) {
+ const WebTouchPoint& touch_point = touches[i];
+ PP_TouchPoint pp_pt;
+ pp_pt.id = touch_point.id;
+ pp_pt.position.x = touch_point.position.x;
+ pp_pt.position.y = touch_point.position.y;
+ pp_pt.radius.x = touch_point.radiusX;
+ pp_pt.radius.y = touch_point.radiusY;
+ pp_pt.rotation_angle = touch_point.rotationAngle;
+ pp_pt.pressure = touch_point.force;
+ result->push_back(pp_pt);
+ }
+}
+
+void AppendTouchEvent(const WebInputEvent& event,
+ std::vector<InputEventData>* result_events) {
+ const WebTouchEvent& touch_event =
+ reinterpret_cast<const WebTouchEvent&>(event);
+
+ InputEventData result = GetEventWithCommonFieldsAndType(event);
+ SetPPTouchPoints(touch_event.touches, touch_event.touchesLength,
+ &result.touches);
+ SetPPTouchPoints(touch_event.changedTouches, touch_event.changedTouchesLength,
+ &result.changed_touches);
+ SetPPTouchPoints(touch_event.targetTouches, touch_event.targetTouchesLength,
+ &result.target_touches);
+
+ result_events->push_back(result);
+}
+
+// Structure used to map touch point id's to touch states. Since the pepper
+// touch event structure does not have states for individual touch points and
+// instead relies on the event type in combination with the set of touch lists,
+// we have to set the state for the changed touches to be the same as the event
+// type and all others to be 'stationary.'
+typedef std::map<uint32_t, WebTouchPoint::State> TouchStateMap;
+
+void SetWebTouchPoints(const std::vector<PP_TouchPoint>& pp_touches,
+ const TouchStateMap& states_map,
+ WebTouchPoint* web_touches,
+ uint32_t* web_touches_length) {
+
+ for (uint32_t i = 0; i < pp_touches.size() &&
+ i < WebTouchEvent::touchesLengthCap; i++) {
+ WebTouchPoint pt;
+ const PP_TouchPoint& pp_pt = pp_touches[i];
+ pt.id = pp_pt.id;
+
+ if (states_map.find(pt.id) == states_map.end())
+ pt.state = WebTouchPoint::StateStationary;
+ else
+ pt.state = states_map.find(pt.id)->second;
+
+ pt.position.x = pp_pt.position.x;
+ pt.position.y = pp_pt.position.y;
+ // TODO bug:http://code.google.com/p/chromium/issues/detail?id=93902
+ pt.screenPosition.x = 0;
+ pt.screenPosition.y = 0;
+ pt.force = pp_pt.pressure;
+ pt.radiusX = pp_pt.radius.x;
+ pt.radiusY = pp_pt.radius.y;
+ pt.rotationAngle = pp_pt.rotation_angle;
+ web_touches[i] = pt;
+ (*web_touches_length)++;
+ }
+}
+
+WebTouchEvent* BuildTouchEvent(const InputEventData& event) {
+ WebTouchEvent* web_event = new WebTouchEvent();
+ WebTouchPoint::State state = WebTouchPoint::StateUndefined;
+ switch (event.event_type) {
+ case PP_INPUTEVENT_TYPE_TOUCHSTART:
+ web_event->type = WebInputEvent::TouchStart;
+ state = WebTouchPoint::StatePressed;
+ break;
+ case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+ web_event->type = WebInputEvent::TouchMove;
+ state = WebTouchPoint::StateMoved;
+ break;
+ case PP_INPUTEVENT_TYPE_TOUCHEND:
+ web_event->type = WebInputEvent::TouchEnd;
+ state = WebTouchPoint::StateReleased;
+ break;
+ case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
+ web_event->type = WebInputEvent::TouchCancel;
+ state = WebTouchPoint::StateCancelled;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ TouchStateMap states_map;
+ for (uint32_t i = 0; i < event.changed_touches.size(); i++)
+ states_map[event.changed_touches[i].id] = state;
+
+ web_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp);
+
+ SetWebTouchPoints(event.changed_touches, states_map,
+ web_event->changedTouches,
+ &web_event->changedTouchesLength);
+
+ SetWebTouchPoints(event.touches, states_map, web_event->touches,
+ &web_event->touchesLength);
+
+ SetWebTouchPoints(event.target_touches, states_map, web_event->targetTouches,
+ &web_event->targetTouchesLength);
+
+ if (web_event->type == WebInputEvent::TouchEnd ||
+ web_event->type == WebInputEvent::TouchCancel) {
+ SetWebTouchPoints(event.changed_touches, states_map,
+ web_event->touches, &web_event->touchesLength);
+ SetWebTouchPoints(event.changed_touches, states_map,
+ web_event->targetTouches,
+ &web_event->targetTouchesLength);
+ }
+
+ return web_event;
+}
+
+WebKeyboardEvent* BuildKeyEvent(const InputEventData& event) {
+ WebKeyboardEvent* key_event = new WebKeyboardEvent();
+ switch (event.event_type) {
+ case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
+ key_event->type = WebInputEvent::RawKeyDown;
+ break;
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ key_event->type = WebInputEvent::KeyDown;
+ break;
+ case PP_INPUTEVENT_TYPE_KEYUP:
+ key_event->type = WebInputEvent::KeyUp;
+ break;
+ default:
+ NOTREACHED();
+ }
+ key_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp);
+ key_event->modifiers = event.event_modifiers;
+ key_event->windowsKeyCode = event.key_code;
+ key_event->setKeyIdentifierFromWindowsKeyCode();
+ return key_event;
+}
+
+WebKeyboardEvent* BuildCharEvent(const InputEventData& event) {
+ WebKeyboardEvent* key_event = new WebKeyboardEvent();
+ key_event->type = WebInputEvent::Char;
+ key_event->timeStampSeconds = PPTimeTicksToEventTime(event.event_time_stamp);
+ key_event->modifiers = event.event_modifiers;
+
+ // Make sure to not read beyond the buffer in case some bad code doesn't
+ // NULL-terminate it (this is called from plugins).
+ size_t text_length_cap = WebKeyboardEvent::textLengthCap;
+ base::string16 text16 = UTF8ToUTF16(event.character_text);
+
+ memset(key_event->text, 0, text_length_cap);
+ memset(key_event->unmodifiedText, 0, text_length_cap);
+ for (size_t i = 0;
+ i < std::min(text_length_cap, text16.size());
+ ++i)
+ key_event->text[i] = text16[i];
+ return key_event;
+}
+
+WebMouseEvent* BuildMouseEvent(const InputEventData& event) {
+ WebMouseEvent* mouse_event = new WebMouseEvent();
+ switch (event.event_type) {
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ mouse_event->type = WebInputEvent::MouseDown;
+ break;
+ case PP_INPUTEVENT_TYPE_MOUSEUP:
+ mouse_event->type = WebInputEvent::MouseUp;
+ break;
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE:
+ mouse_event->type = WebInputEvent::MouseMove;
+ break;
+ case PP_INPUTEVENT_TYPE_MOUSEENTER:
+ mouse_event->type = WebInputEvent::MouseEnter;
+ break;
+ case PP_INPUTEVENT_TYPE_MOUSELEAVE:
+ mouse_event->type = WebInputEvent::MouseLeave;
+ break;
+ case PP_INPUTEVENT_TYPE_CONTEXTMENU:
+ mouse_event->type = WebInputEvent::ContextMenu;
+ break;
+ default:
+ NOTREACHED();
+ }
+ mouse_event->timeStampSeconds =
+ PPTimeTicksToEventTime(event.event_time_stamp);
+ mouse_event->modifiers = event.event_modifiers;
+ mouse_event->button =
+ static_cast<WebMouseEvent::Button>(event.mouse_button);
+ if (mouse_event->type == WebInputEvent::MouseMove) {
+ if (mouse_event->modifiers & WebInputEvent::LeftButtonDown)
+ mouse_event->button = WebMouseEvent::ButtonLeft;
+ else if (mouse_event->modifiers & WebInputEvent::MiddleButtonDown)
+ mouse_event->button = WebMouseEvent::ButtonMiddle;
+ else if (mouse_event->modifiers & WebInputEvent::RightButtonDown)
+ mouse_event->button = WebMouseEvent::ButtonRight;
+ }
+ mouse_event->x = event.mouse_position.x;
+ mouse_event->y = event.mouse_position.y;
+ mouse_event->clickCount = event.mouse_click_count;
+ mouse_event->movementX = event.mouse_movement.x;
+ mouse_event->movementY = event.mouse_movement.y;
+ return mouse_event;
+}
+
+WebMouseWheelEvent* BuildMouseWheelEvent(const InputEventData& event) {
+ WebMouseWheelEvent* mouse_wheel_event = new WebMouseWheelEvent();
+ mouse_wheel_event->type = WebInputEvent::MouseWheel;
+ mouse_wheel_event->timeStampSeconds =
+ PPTimeTicksToEventTime(event.event_time_stamp);
+ mouse_wheel_event->modifiers = event.event_modifiers;
+ mouse_wheel_event->deltaX = event.wheel_delta.x;
+ mouse_wheel_event->deltaY = event.wheel_delta.y;
+ mouse_wheel_event->wheelTicksX = event.wheel_ticks.x;
+ mouse_wheel_event->wheelTicksY = event.wheel_ticks.y;
+ mouse_wheel_event->scrollByPage = event.wheel_scroll_by_page;
+ return mouse_wheel_event;
+}
+
+#if !defined(OS_WIN)
+#define VK_RETURN 0x0D
+
+#define VK_PRIOR 0x21
+#define VK_NEXT 0x22
+#define VK_END 0x23
+#define VK_HOME 0x24
+#define VK_LEFT 0x25
+#define VK_UP 0x26
+#define VK_RIGHT 0x27
+#define VK_DOWN 0x28
+#define VK_SNAPSHOT 0x2C
+#define VK_INSERT 0x2D
+#define VK_DELETE 0x2E
+
+#define VK_APPS 0x5D
+
+#define VK_F1 0x70
+#endif
+
+// Convert a character string to a Windows virtual key code. Adapted from
+// src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp. This
+// is used by CreateSimulatedWebInputEvents to convert keyboard events.
+void GetKeyCode(const std::string& char_text,
+ WebUChar* code,
+ WebUChar* text,
+ bool* needs_shift_modifier,
+ bool* generate_char) {
+ WebUChar vk_code = 0;
+ WebUChar vk_text = 0;
+ *needs_shift_modifier = false;
+ *generate_char = false;
+ if ("\n" == char_text) {
+ vk_text = vk_code = VK_RETURN;
+ *generate_char = true;
+ } else if ("rightArrow" == char_text) {
+ vk_code = VK_RIGHT;
+ } else if ("downArrow" == char_text) {
+ vk_code = VK_DOWN;
+ } else if ("leftArrow" == char_text) {
+ vk_code = VK_LEFT;
+ } else if ("upArrow" == char_text) {
+ vk_code = VK_UP;
+ } else if ("insert" == char_text) {
+ vk_code = VK_INSERT;
+ } else if ("delete" == char_text) {
+ vk_code = VK_DELETE;
+ } else if ("pageUp" == char_text) {
+ vk_code = VK_PRIOR;
+ } else if ("pageDown" == char_text) {
+ vk_code = VK_NEXT;
+ } else if ("home" == char_text) {
+ vk_code = VK_HOME;
+ } else if ("end" == char_text) {
+ vk_code = VK_END;
+ } else if ("printScreen" == char_text) {
+ vk_code = VK_SNAPSHOT;
+ } else if ("menu" == char_text) {
+ vk_code = VK_APPS;
+ } else {
+ // Compare the input string with the function-key names defined by the
+ // DOM spec (i.e. "F1",...,"F24").
+ for (int i = 1; i <= 24; ++i) {
+ std::string functionKeyName = base::StringPrintf("F%d", i);
+ if (functionKeyName == char_text) {
+ vk_code = VK_F1 + (i - 1);
+ break;
+ }
+ }
+ if (!vk_code) {
+ WebString web_char_text =
+ WebString::fromUTF8(char_text.data(), char_text.size());
+ DCHECK_EQ(web_char_text.length(), 1U);
+ vk_text = vk_code = web_char_text.at(0);
+ *needs_shift_modifier =
+ (vk_code & 0xFF) >= 'A' && (vk_code & 0xFF) <= 'Z';
+ if ((vk_code & 0xFF) >= 'a' && (vk_code & 0xFF) <= 'z')
+ vk_code -= 'a' - 'A';
+ *generate_char = true;
+ }
+ }
+
+ *code = vk_code;
+ *text = vk_text;
+}
+
+} // namespace
+
+void CreateInputEventData(const WebInputEvent& event,
+ std::vector<InputEventData>* result) {
+ result->clear();
+
+ switch (event.type) {
+ case WebInputEvent::MouseDown:
+ case WebInputEvent::MouseUp:
+ case WebInputEvent::MouseMove:
+ case WebInputEvent::MouseEnter:
+ case WebInputEvent::MouseLeave:
+ case WebInputEvent::ContextMenu:
+ AppendMouseEvent(event, result);
+ break;
+ case WebInputEvent::MouseWheel:
+ AppendMouseWheelEvent(event, result);
+ break;
+ case WebInputEvent::RawKeyDown:
+ case WebInputEvent::KeyDown:
+ case WebInputEvent::KeyUp:
+ AppendKeyEvent(event, result);
+ break;
+ case WebInputEvent::Char:
+ AppendCharEvent(event, result);
+ break;
+ case WebInputEvent::TouchStart:
+ case WebInputEvent::TouchMove:
+ case WebInputEvent::TouchEnd:
+ case WebInputEvent::TouchCancel:
+ AppendTouchEvent(event, result);
+ break;
+ case WebInputEvent::Undefined:
+ default:
+ break;
+ }
+}
+
+WebInputEvent* CreateWebInputEvent(const InputEventData& event) {
+ scoped_ptr<WebInputEvent> web_input_event;
+ switch (event.event_type) {
+ case PP_INPUTEVENT_TYPE_UNDEFINED:
+ return NULL;
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ case PP_INPUTEVENT_TYPE_MOUSEUP:
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE:
+ case PP_INPUTEVENT_TYPE_MOUSEENTER:
+ case PP_INPUTEVENT_TYPE_MOUSELEAVE:
+ case PP_INPUTEVENT_TYPE_CONTEXTMENU:
+ web_input_event.reset(BuildMouseEvent(event));
+ break;
+ case PP_INPUTEVENT_TYPE_WHEEL:
+ web_input_event.reset(BuildMouseWheelEvent(event));
+ break;
+ case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYUP:
+ web_input_event.reset(BuildKeyEvent(event));
+ break;
+ case PP_INPUTEVENT_TYPE_CHAR:
+ web_input_event.reset(BuildCharEvent(event));
+ break;
+ case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
+ case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
+ case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
+ case PP_INPUTEVENT_TYPE_IME_TEXT:
+ // TODO(kinaba) implement in WebKit an event structure to handle
+ // composition events.
+ NOTREACHED();
+ break;
+ case PP_INPUTEVENT_TYPE_TOUCHSTART:
+ case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+ case PP_INPUTEVENT_TYPE_TOUCHEND:
+ case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
+ web_input_event.reset(BuildTouchEvent(event));
+ break;
+ }
+
+ return web_input_event.release();
+}
+
+// Generate a coherent sequence of input events to simulate a user event.
+// From src/third_party/WebKit/Tools/DumpRenderTree/chromium/EventSender.cpp.
+std::vector<linked_ptr<WebInputEvent> > CreateSimulatedWebInputEvents(
+ const ::ppapi::InputEventData& event,
+ int plugin_x,
+ int plugin_y) {
+ std::vector<linked_ptr<WebInputEvent> > events;
+ linked_ptr<WebInputEvent> original_event(CreateWebInputEvent(event));
+
+ switch (event.event_type) {
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ case PP_INPUTEVENT_TYPE_MOUSEUP:
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE:
+ case PP_INPUTEVENT_TYPE_MOUSEENTER:
+ case PP_INPUTEVENT_TYPE_MOUSELEAVE:
+ case PP_INPUTEVENT_TYPE_TOUCHSTART:
+ case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+ case PP_INPUTEVENT_TYPE_TOUCHEND:
+ case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
+ events.push_back(original_event);
+ break;
+
+ case PP_INPUTEVENT_TYPE_WHEEL: {
+ WebMouseWheelEvent* web_mouse_wheel_event =
+ static_cast<WebMouseWheelEvent*>(original_event.get());
+ web_mouse_wheel_event->x = plugin_x;
+ web_mouse_wheel_event->y = plugin_y;
+ events.push_back(original_event);
+ break;
+ }
+
+ case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYUP: {
+ // Windows key down events should always be "raw" to avoid an ASSERT.
+#if defined(OS_WIN)
+ WebKeyboardEvent* web_keyboard_event =
+ static_cast<WebKeyboardEvent*>(original_event.get());
+ if (web_keyboard_event->type == WebInputEvent::KeyDown)
+ web_keyboard_event->type = WebInputEvent::RawKeyDown;
+#endif
+ events.push_back(original_event);
+ break;
+ }
+
+ case PP_INPUTEVENT_TYPE_CHAR: {
+ WebKeyboardEvent* web_char_event =
+ static_cast<WebKeyboardEvent*>(original_event.get());
+
+ WebUChar code = 0, text = 0;
+ bool needs_shift_modifier = false, generate_char = false;
+ GetKeyCode(event.character_text,
+ &code,
+ &text,
+ &needs_shift_modifier,
+ &generate_char);
+
+ // Synthesize key down and key up events in all cases.
+ scoped_ptr<WebKeyboardEvent> key_down_event(new WebKeyboardEvent());
+ scoped_ptr<WebKeyboardEvent> key_up_event(new WebKeyboardEvent());
+
+ key_down_event->type = WebInputEvent::RawKeyDown;
+ key_down_event->windowsKeyCode = code;
+ key_down_event->nativeKeyCode = code;
+ if (needs_shift_modifier)
+ key_down_event->modifiers |= WebInputEvent::ShiftKey;
+
+ // If a char event is needed, set the text fields.
+ if (generate_char) {
+ key_down_event->text[0] = text;
+ key_down_event->unmodifiedText[0] = text;
+ }
+ // Convert the key code to a string identifier.
+ key_down_event->setKeyIdentifierFromWindowsKeyCode();
+
+ *key_up_event = *web_char_event = *key_down_event;
+
+ events.push_back(linked_ptr<WebInputEvent>(key_down_event.release()));
+
+ if (generate_char) {
+ web_char_event->type = WebInputEvent::Char;
+ web_char_event->keyIdentifier[0] = '\0';
+ events.push_back(original_event);
+ }
+
+ key_up_event->type = WebInputEvent::KeyUp;
+ events.push_back(linked_ptr<WebInputEvent>(key_up_event.release()));
+ break;
+ }
+
+ default:
+ break;
+ }
+ return events;
+}
+
+PP_InputEvent_Class ClassifyInputEvent(WebInputEvent::Type type) {
+ switch (type) {
+ case WebInputEvent::MouseDown:
+ case WebInputEvent::MouseUp:
+ case WebInputEvent::MouseMove:
+ case WebInputEvent::MouseEnter:
+ case WebInputEvent::MouseLeave:
+ case WebInputEvent::ContextMenu:
+ return PP_INPUTEVENT_CLASS_MOUSE;
+ case WebInputEvent::MouseWheel:
+ return PP_INPUTEVENT_CLASS_WHEEL;
+ case WebInputEvent::RawKeyDown:
+ case WebInputEvent::KeyDown:
+ case WebInputEvent::KeyUp:
+ case WebInputEvent::Char:
+ return PP_INPUTEVENT_CLASS_KEYBOARD;
+ case WebInputEvent::TouchCancel:
+ case WebInputEvent::TouchEnd:
+ case WebInputEvent::TouchMove:
+ case WebInputEvent::TouchStart:
+ return PP_INPUTEVENT_CLASS_TOUCH;
+ case WebInputEvent::Undefined:
+ default:
+ NOTREACHED();
+ return PP_InputEvent_Class(0);
+ }
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/event_conversion.h b/content/renderer/pepper/event_conversion.h
new file mode 100644
index 0000000..0fa849c
--- /dev/null
+++ b/content/renderer/pepper/event_conversion.h
@@ -0,0 +1,54 @@
+// 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_EVENT_CONVERSION_H_
+#define CONTENT_RENDERER_PEPPER_EVENT_CONVERSION_H_
+
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "ppapi/c/ppb_input_event.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+struct PP_InputEvent;
+
+namespace ppapi {
+struct InputEventData;
+}
+
+namespace WebKit {
+class WebGamepads;
+class WebInputEvent;
+}
+
+namespace webkit {
+namespace ppapi {
+
+// Converts the given WebKit event to one or possibly multiple PP_InputEvents.
+// The generated events will be filled into the given vector. On failure, no
+// events will ge generated and the vector will be empty.
+void CreateInputEventData(const WebKit::WebInputEvent& event,
+ std::vector< ::ppapi::InputEventData >* pp_events);
+
+// Creates a WebInputEvent from the given PP_InputEvent. If it fails, returns
+// NULL. The caller owns the created object on success.
+WebKit::WebInputEvent* CreateWebInputEvent(
+ const ::ppapi::InputEventData& event);
+
+// Creates an array of WebInputEvents to make the given event look like a user
+// input event on all platforms. |plugin_x| and |plugin_y| should be the
+// coordinates of a point within the plugin's area on the page.
+std::vector<linked_ptr<WebKit::WebInputEvent> > CreateSimulatedWebInputEvents(
+ const ::ppapi::InputEventData& event,
+ int plugin_x,
+ int plugin_y);
+
+// Returns the PPAPI event class for the given WebKit event type. The given
+// type should not be "Undefined" since there's no corresponding PPAPI class.
+PP_InputEvent_Class ClassifyInputEvent(WebKit::WebInputEvent::Type type);
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_EVENT_CONVERSION_H_
diff --git a/content/renderer/pepper/fullscreen_container.h b/content/renderer/pepper/fullscreen_container.h
new file mode 100644
index 0000000..805c187
--- /dev/null
+++ b/content/renderer/pepper/fullscreen_container.h
@@ -0,0 +1,48 @@
+// 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_PPB_FULLSCREEN_CONTAINER_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_FULLSCREEN_CONTAINER_IMPL_H_
+
+#include "content/renderer/pepper/plugin_delegate.h"
+
+namespace WebKit {
+class WebLayer;
+struct WebCursorInfo;
+struct WebRect;
+} // namespace WebKit
+
+namespace webkit {
+namespace ppapi {
+
+// This class is like a lightweight WebPluginContainer for fullscreen PPAPI
+// plugins, that only handles painting.
+class FullscreenContainer {
+ public:
+ // Invalidates the full plugin region.
+ virtual void Invalidate() = 0;
+
+ // Invalidates a partial region of the plugin.
+ virtual void InvalidateRect(const WebKit::WebRect&) = 0;
+
+ // Scrolls a partial region of the plugin in the given direction.
+ virtual void ScrollRect(int dx, int dy, const WebKit::WebRect&) = 0;
+
+ // Destroys the fullscreen window. This also destroys the FullscreenContainer
+ // instance.
+ virtual void Destroy() = 0;
+
+ // Notifies the container that the mouse cursor has changed.
+ virtual void DidChangeCursor(const WebKit::WebCursorInfo& cursor) = 0;
+
+ virtual void SetLayer(WebKit::WebLayer* layer) = 0;
+
+ protected:
+ virtual ~FullscreenContainer() {}
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_FULLSCREEN_CONTAINER_IMPL_H_
diff --git a/content/renderer/pepper/gfx_conversion.h b/content/renderer/pepper/gfx_conversion.h
new file mode 100644
index 0000000..77e7001
--- /dev/null
+++ b/content/renderer/pepper/gfx_conversion.h
@@ -0,0 +1,48 @@
+// 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_PEPPER_GFX_CONVERSION_H_
+#define CONTENT_RENDERER_PEPPER_GFX_CONVERSION_H_
+
+#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/size.h"
+
+// Conversions for graphics types between our gfx library and PPAPI.
+// The style of naming is to match the PP_Bool conversions.
+
+namespace webkit {
+namespace ppapi {
+
+inline gfx::Point PP_ToGfxPoint(const PP_Point& p) {
+ return gfx::Point(p.x, p.y);
+}
+
+inline PP_Point PP_FromGfxPoint(const gfx::Point& p) {
+ return PP_MakePoint(p.x(), p.y());
+}
+
+inline gfx::Rect PP_ToGfxRect(const PP_Rect& r) {
+ return gfx::Rect(r.point.x, r.point.y, r.size.width, r.size.height);
+}
+
+inline PP_Rect PP_FromGfxRect(const gfx::Rect& r) {
+ return PP_MakeRectFromXYWH(r.x(), r.y(), r.width(), r.height());
+}
+
+inline gfx::Size PP_ToGfxSize(const PP_Size& s) {
+ return gfx::Size(s.width, s.height);
+}
+
+inline PP_Size PP_FromGfxSize(const gfx::Size& s) {
+ return PP_MakeSize(s.width(), s.height());
+}
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_GFX_CONVERSION_H_
diff --git a/content/renderer/pepper/host_array_buffer_var.cc b/content/renderer/pepper/host_array_buffer_var.cc
new file mode 100644
index 0000000..565db42
--- /dev/null
+++ b/content/renderer/pepper/host_array_buffer_var.cc
@@ -0,0 +1,103 @@
+// 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/host_array_buffer_var.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/pp_instance.h"
+
+using ppapi::ArrayBufferVar;
+using WebKit::WebArrayBuffer;
+
+namespace webkit {
+namespace ppapi {
+
+HostArrayBufferVar::HostArrayBufferVar(uint32 size_in_bytes)
+ : buffer_(WebArrayBuffer::create(size_in_bytes, 1 /* element_size */)),
+ valid_(true) {
+}
+
+HostArrayBufferVar::HostArrayBufferVar(const WebArrayBuffer& buffer)
+ : buffer_(buffer),
+ valid_(true) {
+}
+
+HostArrayBufferVar::HostArrayBufferVar(uint32 size_in_bytes,
+ base::SharedMemoryHandle handle)
+ : buffer_(WebArrayBuffer::create(size_in_bytes, 1 /* element_size */)) {
+ base::SharedMemory s(handle, true);
+ valid_ = s.Map(size_in_bytes);
+ if (valid_) {
+ memcpy(buffer_.data(), s.memory(), size_in_bytes);
+ s.Unmap();
+ }
+}
+
+HostArrayBufferVar::~HostArrayBufferVar() {
+}
+
+void* HostArrayBufferVar::Map() {
+ if (!valid_)
+ return NULL;
+ return buffer_.data();
+}
+
+void HostArrayBufferVar::Unmap() {
+ // We do not used shared memory on the host side. Nothing to do.
+}
+
+uint32 HostArrayBufferVar::ByteLength() {
+ return buffer_.byteLength();
+}
+
+bool HostArrayBufferVar::CopyToNewShmem(
+ PP_Instance instance,
+ int* host_shm_handle_id,
+ base::SharedMemoryHandle* plugin_shm_handle) {
+ webkit::ppapi::PluginInstanceImpl* i =
+ webkit::ppapi::HostGlobals::Get()->GetInstance(instance);
+ scoped_ptr<base::SharedMemory> shm(i->delegate()->CreateAnonymousSharedMemory(
+ ByteLength()));
+ if (!shm)
+ return false;
+
+ shm->Map(ByteLength());
+ memcpy(shm->memory(), Map(), ByteLength());
+ shm->Unmap();
+
+ // Duplicate the handle here; the SharedMemory destructor closes
+ // its handle on us.
+ HostGlobals* hg = HostGlobals::Get();
+ PluginModule* pm = hg->GetModule(hg->GetModuleForInstance(instance));
+ base::ProcessId p = pm->GetPeerProcessId();
+ if (p == base::kNullProcessId) {
+ // In-process, clone for ourselves.
+ p = base::GetCurrentProcId();
+ }
+
+ base::PlatformFile platform_file =
+#if defined(OS_WIN)
+ shm->handle();
+#elif defined(OS_POSIX)
+ shm->handle().fd;
+#else
+#error Not implemented.
+#endif
+
+ *plugin_shm_handle =
+ i->delegate()->ShareHandleWithRemote(platform_file, p, false);
+ *host_shm_handle_id = -1;
+ return true;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/host_array_buffer_var.h b/content/renderer/pepper/host_array_buffer_var.h
new file mode 100644
index 0000000..b1bd16a
--- /dev/null
+++ b/content/renderer/pepper/host_array_buffer_var.h
@@ -0,0 +1,49 @@
+// 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 PPAPI_CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
+#define PPAPI_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"
+
+namespace webkit {
+namespace ppapi {
+
+// Represents a host-side ArrayBufferVar.
+class HostArrayBufferVar : public ::ppapi::ArrayBufferVar {
+ public:
+ explicit HostArrayBufferVar(uint32 size_in_bytes);
+ explicit HostArrayBufferVar(const WebKit::WebArrayBuffer& buffer);
+ explicit HostArrayBufferVar(uint32 size_in_bytes,
+ base::SharedMemoryHandle handle);
+
+ // ArrayBufferVar implementation.
+ virtual void* Map() OVERRIDE;
+ virtual void Unmap() OVERRIDE;
+ virtual uint32 ByteLength() OVERRIDE;
+ virtual bool CopyToNewShmem(
+ PP_Instance instance,
+ int* host_shm_handle_id,
+ base::SharedMemoryHandle* plugin_shm_handle) OVERRIDE;
+
+ WebKit::WebArrayBuffer& webkit_buffer() { return buffer_; }
+
+ private:
+ virtual ~HostArrayBufferVar();
+
+ WebKit::WebArrayBuffer buffer_;
+ // Tracks whether the data in the buffer is valid.
+ bool valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostArrayBufferVar);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // PPAPI_CONTENT_RENDERER_PEPPER_HOST_ARRAY_BUFFER_VAR_H_
diff --git a/content/renderer/pepper/host_globals.cc b/content/renderer/pepper/host_globals.cc
new file mode 100644
index 0000000..ccc9f84
--- /dev/null
+++ b/content/renderer/pepper/host_globals.cc
@@ -0,0 +1,285 @@
+// 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/host_globals.h"
+
+#include <limits>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/shared_impl/api_id.h"
+#include "ppapi/shared_impl/id_assignment.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "webkit/plugins/plugin_switches.h"
+
+using ppapi::CheckIdType;
+using ppapi::MakeTypedId;
+using ppapi::PPIdType;
+using ppapi::ResourceTracker;
+using WebKit::WebConsoleMessage;
+using WebKit::WebString;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+typedef std::set<WebKit::WebPluginContainer*> ContainerSet;
+
+// Adds all WebPluginContainers associated with the given module to the set.
+void GetAllContainersForModule(PluginModule* module,
+ ContainerSet* containers) {
+ const PluginModule::PluginInstanceSet& instances =
+ module->GetAllInstances();
+ for (PluginModule::PluginInstanceSet::const_iterator i = instances.begin();
+ i != instances.end(); ++i)
+ containers->insert((*i)->container());
+}
+
+WebConsoleMessage::Level LogLevelToWebLogLevel(PP_LogLevel level) {
+ switch (level) {
+ case PP_LOGLEVEL_TIP:
+ return WebConsoleMessage::LevelDebug;
+ case PP_LOGLEVEL_LOG:
+ return WebConsoleMessage::LevelLog;
+ case PP_LOGLEVEL_WARNING:
+ return WebConsoleMessage::LevelWarning;
+ case PP_LOGLEVEL_ERROR:
+ default:
+ return WebConsoleMessage::LevelError;
+ }
+}
+
+WebConsoleMessage MakeLogMessage(PP_LogLevel level,
+ const std::string& source,
+ const std::string& message) {
+ std::string result = source;
+ if (!result.empty())
+ result.append(": ");
+ result.append(message);
+ return WebConsoleMessage(LogLevelToWebLogLevel(level),
+ WebString(UTF8ToUTF16(result)));
+}
+
+} // namespace
+
+HostGlobals* HostGlobals::host_globals_ = NULL;
+
+HostGlobals::HostGlobals()
+ : ::ppapi::PpapiGlobals(),
+ resource_tracker_(ResourceTracker::SINGLE_THREADED) {
+ DCHECK(!host_globals_);
+ host_globals_ = this;
+}
+
+HostGlobals::HostGlobals(
+ ::ppapi::PpapiGlobals::PerThreadForTest per_thread_for_test)
+ : ::ppapi::PpapiGlobals(per_thread_for_test),
+ resource_tracker_(ResourceTracker::SINGLE_THREADED) {
+ DCHECK(!host_globals_);
+}
+
+HostGlobals::~HostGlobals() {
+ DCHECK(host_globals_ == this || !host_globals_);
+ host_globals_ = NULL;
+}
+
+::ppapi::ResourceTracker* HostGlobals::GetResourceTracker() {
+ return &resource_tracker_;
+}
+
+::ppapi::VarTracker* HostGlobals::GetVarTracker() {
+ return &host_var_tracker_;
+}
+
+::ppapi::CallbackTracker* HostGlobals::GetCallbackTrackerForInstance(
+ PP_Instance instance) {
+ InstanceMap::iterator found = instance_map_.find(instance);
+ if (found == instance_map_.end())
+ return NULL;
+ return found->second->module()->GetCallbackTracker().get();
+}
+
+::ppapi::thunk::PPB_Instance_API* HostGlobals::GetInstanceAPI(
+ PP_Instance instance) {
+ // The InstanceAPI is just implemented by the PluginInstance object.
+ return GetInstance(instance);
+}
+
+::ppapi::thunk::ResourceCreationAPI* HostGlobals::GetResourceCreationAPI(
+ PP_Instance pp_instance) {
+ PluginInstanceImpl* instance = GetInstance(pp_instance);
+ if (!instance)
+ return NULL;
+ return &instance->resource_creation();
+}
+
+PP_Module HostGlobals::GetModuleForInstance(PP_Instance instance) {
+ PluginInstanceImpl* inst = GetInstance(instance);
+ if (!inst)
+ return 0;
+ return inst->module()->pp_module();
+}
+
+std::string HostGlobals::GetCmdLine() {
+ return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kPpapiFlashArgs);
+}
+
+void HostGlobals::PreCacheFontForFlash(const void* logfontw) {
+ // Not implemented in-process.
+}
+
+base::Lock* HostGlobals::GetProxyLock() {
+ // We do not lock on the host side.
+ return NULL;
+}
+
+void HostGlobals::LogWithSource(PP_Instance instance,
+ PP_LogLevel level,
+ const std::string& source,
+ const std::string& value) {
+ PluginInstanceImpl* instance_object =
+ HostGlobals::Get()->GetInstance(instance);
+ if (instance_object) {
+ instance_object->container()->element().document().frame()->
+ addMessageToConsole(MakeLogMessage(level, source, value));
+ } else {
+ BroadcastLogWithSource(0, level, source, value);
+ }
+}
+
+void HostGlobals::BroadcastLogWithSource(PP_Module pp_module,
+ PP_LogLevel level,
+ const std::string& source,
+ const std::string& value) {
+ // Get the unique containers associated with the broadcast. This prevents us
+ // from sending the same message to the same console when there are two
+ // instances on the page.
+ ContainerSet containers;
+ PluginModule* module = GetModule(pp_module);
+ if (module) {
+ GetAllContainersForModule(module, &containers);
+ } else {
+ // Unknown module, get containers for all modules.
+ for (ModuleMap::const_iterator i = module_map_.begin();
+ i != module_map_.end(); ++i) {
+ GetAllContainersForModule(i->second, &containers);
+ }
+ }
+
+ WebConsoleMessage message = MakeLogMessage(level, source, value);
+ for (ContainerSet::iterator i = containers.begin();
+ i != containers.end(); ++i)
+ (*i)->element().document().frame()->addMessageToConsole(message);
+}
+
+base::TaskRunner* HostGlobals::GetFileTaskRunner(PP_Instance instance) {
+ scoped_refptr<PluginInstanceImpl> plugin_instance = GetInstance(instance);
+ DCHECK(plugin_instance.get());
+ scoped_refptr<base::MessageLoopProxy> message_loop =
+ plugin_instance->delegate()->GetFileThreadMessageLoopProxy();
+ return message_loop.get();
+}
+
+::ppapi::MessageLoopShared* HostGlobals::GetCurrentMessageLoop() {
+ return NULL;
+}
+
+PP_Module HostGlobals::AddModule(PluginModule* module) {
+#ifndef NDEBUG
+ // Make sure we're not adding one more than once.
+ for (ModuleMap::const_iterator i = module_map_.begin();
+ i != module_map_.end(); ++i)
+ DCHECK(i->second != module);
+#endif
+
+ // See AddInstance.
+ PP_Module new_module;
+ do {
+ new_module = MakeTypedId(static_cast<PP_Module>(base::RandUint64()),
+ ::ppapi::PP_ID_TYPE_MODULE);
+ } while (!new_module ||
+ module_map_.find(new_module) != module_map_.end());
+ module_map_[new_module] = module;
+ return new_module;
+}
+
+void HostGlobals::ModuleDeleted(PP_Module module) {
+ DLOG_IF(ERROR, !CheckIdType(module, ::ppapi::PP_ID_TYPE_MODULE))
+ << module << " is not a PP_Module.";
+ ModuleMap::iterator found = module_map_.find(module);
+ if (found == module_map_.end()) {
+ NOTREACHED();
+ return;
+ }
+ module_map_.erase(found);
+}
+
+PluginModule* HostGlobals::GetModule(PP_Module module) {
+ DLOG_IF(ERROR, !CheckIdType(module, ::ppapi::PP_ID_TYPE_MODULE))
+ << module << " is not a PP_Module.";
+ ModuleMap::iterator found = module_map_.find(module);
+ if (found == module_map_.end())
+ return NULL;
+ return found->second;
+}
+
+PP_Instance HostGlobals::AddInstance(PluginInstanceImpl* instance) {
+ DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end());
+
+ // Use a random number for the instance ID. This helps prevent some
+ // accidents. See also AddModule below.
+ //
+ // Need to make sure the random number isn't a duplicate or 0.
+ PP_Instance new_instance;
+ do {
+ new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()),
+ ::ppapi::PP_ID_TYPE_INSTANCE);
+ } while (!new_instance ||
+ instance_map_.find(new_instance) != instance_map_.end() ||
+ !instance->module()->ReserveInstanceID(new_instance));
+
+ instance_map_[new_instance] = instance;
+
+ resource_tracker_.DidCreateInstance(new_instance);
+ return new_instance;
+}
+
+void HostGlobals::InstanceDeleted(PP_Instance instance) {
+ resource_tracker_.DidDeleteInstance(instance);
+ host_var_tracker_.DidDeleteInstance(instance);
+ instance_map_.erase(instance);
+}
+
+void HostGlobals::InstanceCrashed(PP_Instance instance) {
+ resource_tracker_.DidDeleteInstance(instance);
+ host_var_tracker_.DidDeleteInstance(instance);
+}
+
+PluginInstanceImpl* HostGlobals::GetInstance(PP_Instance instance) {
+ DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE))
+ << instance << " is not a PP_Instance.";
+ InstanceMap::iterator found = instance_map_.find(instance);
+ if (found == instance_map_.end())
+ return NULL;
+ return found->second;
+}
+
+bool HostGlobals::IsHostGlobals() const {
+ return true;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/host_globals.h b/content/renderer/pepper/host_globals.h
new file mode 100644
index 0000000..1689259
--- /dev/null
+++ b/content/renderer/pepper/host_globals.h
@@ -0,0 +1,118 @@
+// 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_HOST_GLOBALS_H_
+#define CONTENT_RENDERER_PEPPER_HOST_GLOBALS_H_
+
+#include "base/compiler_specific.h"
+#include "content/renderer/pepper/host_var_tracker.h"
+#include "ppapi/shared_impl/callback_tracker.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/shared_impl/var_tracker.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstanceImpl;
+class PluginModule;
+
+class HostGlobals : public ::ppapi::PpapiGlobals {
+ public:
+ HostGlobals();
+ explicit HostGlobals(::ppapi::PpapiGlobals::PerThreadForTest);
+ virtual ~HostGlobals();
+
+ // Getter for the global singleton. Generally, you should use
+ // PpapiGlobals::Get() when possible. Use this only when you need some
+ // host-specific functionality.
+ inline static HostGlobals* Get() {
+ DCHECK(PpapiGlobals::Get()->IsHostGlobals());
+ return static_cast<HostGlobals*>(PpapiGlobals::Get());
+ }
+
+ // PpapiGlobals implementation.
+ virtual ::ppapi::ResourceTracker* GetResourceTracker() OVERRIDE;
+ virtual ::ppapi::VarTracker* GetVarTracker() OVERRIDE;
+ virtual ::ppapi::CallbackTracker* GetCallbackTrackerForInstance(
+ PP_Instance instance) OVERRIDE;
+ virtual ::ppapi::thunk::PPB_Instance_API* GetInstanceAPI(
+ PP_Instance instance) OVERRIDE;
+ virtual ::ppapi::thunk::ResourceCreationAPI* GetResourceCreationAPI(
+ PP_Instance instance) OVERRIDE;
+ virtual PP_Module GetModuleForInstance(PP_Instance instance) OVERRIDE;
+ virtual std::string GetCmdLine() OVERRIDE;
+ virtual void PreCacheFontForFlash(const void* logfontw) OVERRIDE;
+ virtual base::Lock* GetProxyLock() OVERRIDE;
+ virtual void LogWithSource(PP_Instance instance,
+ PP_LogLevel level,
+ const std::string& source,
+ const std::string& value) OVERRIDE;
+ virtual void BroadcastLogWithSource(PP_Module module,
+ PP_LogLevel level,
+ const std::string& source,
+ const std::string& value) OVERRIDE;
+ virtual ::ppapi::MessageLoopShared* GetCurrentMessageLoop() OVERRIDE;
+ virtual base::TaskRunner* GetFileTaskRunner(PP_Instance instance) OVERRIDE;
+
+ HostVarTracker* host_var_tracker() {
+ return &host_var_tracker_;
+ }
+
+ // PP_Modules ----------------------------------------------------------------
+
+ // Adds a new plugin module to the list of tracked module, and returns a new
+ // module handle to identify it.
+ PP_Module AddModule(PluginModule* module);
+
+ // Called when a plugin modulde was deleted and should no longer be tracked.
+ // The given handle should be one generated by AddModule.
+ void ModuleDeleted(PP_Module module);
+
+ // Returns a pointer to the plugin modulde object associated with the given
+ // modulde handle. The return value will be NULL if the handle is invalid.
+ PluginModule* GetModule(PP_Module module);
+
+ // PP_Instances --------------------------------------------------------------
+
+ // Adds a new plugin instance to the list of tracked instances, and returns a
+ // new instance handle to identify it.
+ PP_Instance AddInstance(PluginInstanceImpl* instance);
+
+ // Called when a plugin instance was deleted and should no longer be tracked.
+ // The given handle should be one generated by AddInstance.
+ void InstanceDeleted(PP_Instance instance);
+
+ void InstanceCrashed(PP_Instance instance);
+
+ // Returns a pointer to the plugin instance object associated with the given
+ // instance handle. The return value will be NULL if the handle is invalid or
+ // if the instance has crashed.
+ PluginInstanceImpl* GetInstance(PP_Instance instance);
+
+ private:
+ // PpapiGlobals overrides.
+ virtual bool IsHostGlobals() const OVERRIDE;
+
+ static HostGlobals* host_globals_;
+
+ ::ppapi::ResourceTracker resource_tracker_;
+ HostVarTracker host_var_tracker_;
+
+ // Tracks all live instances and their associated object.
+ typedef std::map<PP_Instance, PluginInstanceImpl*> InstanceMap;
+ InstanceMap instance_map_;
+
+ // Tracks all live modules. The pointers are non-owning, the PluginModule
+ // destructor will notify us when the module is deleted.
+ typedef std::map<PP_Module, PluginModule*> ModuleMap;
+ ModuleMap module_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostGlobals);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_HOST_GLOBALS_H_
diff --git a/content/renderer/pepper/host_var_tracker.cc b/content/renderer/pepper/host_var_tracker.cc
new file mode 100644
index 0000000..b61af73
--- /dev/null
+++ b/content/renderer/pepper/host_var_tracker.cc
@@ -0,0 +1,173 @@
+// 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/host_var_tracker.h"
+
+#include "base/logging.h"
+#include "content/renderer/pepper/host_array_buffer_var.h"
+#include "content/renderer/pepper/npobject_var.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/pp_var.h"
+
+using ppapi::ArrayBufferVar;
+using ppapi::NPObjectVar;
+
+namespace webkit {
+namespace ppapi {
+
+HostVarTracker::HostVarTracker()
+ : VarTracker(SINGLE_THREADED),
+ last_shared_memory_map_id_(0) {
+}
+
+HostVarTracker::~HostVarTracker() {
+}
+
+ArrayBufferVar* HostVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
+ return new HostArrayBufferVar(size_in_bytes);
+}
+
+ArrayBufferVar* HostVarTracker::CreateShmArrayBuffer(
+ uint32 size_in_bytes,
+ base::SharedMemoryHandle handle) {
+ return new HostArrayBufferVar(size_in_bytes, handle);
+}
+
+void HostVarTracker::AddNPObjectVar(NPObjectVar* object_var) {
+ CheckThreadingPreconditions();
+
+ InstanceMap::iterator found_instance = instance_map_.find(
+ object_var->pp_instance());
+ if (found_instance == instance_map_.end()) {
+ // Lazily create the instance map.
+ DCHECK(object_var->pp_instance() != 0);
+ found_instance = instance_map_.insert(std::make_pair(
+ object_var->pp_instance(),
+ linked_ptr<NPObjectToNPObjectVarMap>(new NPObjectToNPObjectVarMap))).
+ first;
+ }
+ NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
+
+ DCHECK(np_object_map->find(object_var->np_object()) ==
+ np_object_map->end()) << "NPObjectVar already in map";
+ np_object_map->insert(std::make_pair(object_var->np_object(), object_var));
+}
+
+void HostVarTracker::RemoveNPObjectVar(NPObjectVar* object_var) {
+ CheckThreadingPreconditions();
+
+ InstanceMap::iterator found_instance = instance_map_.find(
+ object_var->pp_instance());
+ if (found_instance == instance_map_.end()) {
+ NOTREACHED() << "NPObjectVar has invalid instance.";
+ return;
+ }
+ NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
+
+ NPObjectToNPObjectVarMap::iterator found_object =
+ np_object_map->find(object_var->np_object());
+ if (found_object == np_object_map->end()) {
+ NOTREACHED() << "NPObjectVar not registered.";
+ return;
+ }
+ if (found_object->second != object_var) {
+ NOTREACHED() << "NPObjectVar doesn't match.";
+ return;
+ }
+ np_object_map->erase(found_object);
+}
+
+NPObjectVar* HostVarTracker::NPObjectVarForNPObject(PP_Instance instance,
+ NPObject* np_object) {
+ CheckThreadingPreconditions();
+
+ InstanceMap::iterator found_instance = instance_map_.find(instance);
+ if (found_instance == instance_map_.end())
+ return NULL; // No such instance.
+ NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
+
+ NPObjectToNPObjectVarMap::iterator found_object =
+ np_object_map->find(np_object);
+ if (found_object == np_object_map->end())
+ return NULL; // No such object.
+ return found_object->second;
+}
+
+int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const {
+ CheckThreadingPreconditions();
+
+ InstanceMap::const_iterator found = instance_map_.find(instance);
+ if (found == instance_map_.end())
+ return 0;
+ return static_cast<int>(found->second->size());
+}
+
+void HostVarTracker::DidDeleteInstance(PP_Instance instance) {
+ CheckThreadingPreconditions();
+
+ InstanceMap::iterator found_instance = instance_map_.find(instance);
+ if (found_instance == instance_map_.end())
+ return; // Nothing to do.
+ NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
+
+ // Force delete all var references. ForceReleaseNPObject() will cause
+ // this object, and potentially others it references, to be removed from
+ // |np_object_map|.
+ while (!np_object_map->empty()) {
+ ForceReleaseNPObject(np_object_map->begin()->second);
+ }
+
+ // Remove the record for this instance since it should be empty.
+ DCHECK(np_object_map->empty());
+ instance_map_.erase(found_instance);
+}
+
+void HostVarTracker::ForceReleaseNPObject(::ppapi::NPObjectVar* object_var) {
+ object_var->InstanceDeleted();
+ VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID());
+ if (iter == live_vars_.end()) {
+ NOTREACHED();
+ return;
+ }
+ iter->second.ref_count = 0;
+ DCHECK(iter->second.track_with_no_reference_count == 0);
+ DeleteObjectInfoIfNecessary(iter);
+}
+
+int HostVarTracker::TrackSharedMemoryHandle(PP_Instance instance,
+ base::SharedMemoryHandle handle,
+ uint32 size_in_bytes) {
+ SharedMemoryMapEntry entry;
+ entry.instance = instance;
+ entry.handle = handle;
+ entry.size_in_bytes = size_in_bytes;
+
+ // Find a free id for our map.
+ while (shared_memory_map_.find(last_shared_memory_map_id_) !=
+ shared_memory_map_.end()) {
+ ++last_shared_memory_map_id_;
+ }
+ shared_memory_map_[last_shared_memory_map_id_] = entry;
+ return last_shared_memory_map_id_;
+}
+
+bool HostVarTracker::StopTrackingSharedMemoryHandle(
+ int id,
+ PP_Instance instance,
+ base::SharedMemoryHandle* handle,
+ uint32* size_in_bytes) {
+ SharedMemoryMap::iterator it = shared_memory_map_.find(id);
+ if (it == shared_memory_map_.end())
+ return false;
+ if (it->second.instance != instance)
+ return false;
+
+ *handle = it->second.handle;
+ *size_in_bytes = it->second.size_in_bytes;
+ shared_memory_map_.erase(it);
+ return true;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/host_var_tracker.h b/content/renderer/pepper/host_var_tracker.h
new file mode 100644
index 0000000..9ff0dbd
--- /dev/null
+++ b/content/renderer/pepper/host_var_tracker.h
@@ -0,0 +1,110 @@
+// 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_HOST_VAR_TRACKER_H_
+#define CONTENT_RENDERER_PEPPER_HOST_VAR_TRACKER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/shared_impl/host_resource.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/shared_impl/var_tracker.h"
+
+typedef struct NPObject NPObject;
+
+namespace ppapi {
+class ArrayBufferVar;
+class NPObjectVar;
+class Var;
+}
+
+namespace webkit {
+namespace ppapi {
+
+// Adds NPObject var tracking to the standard PPAPI VarTracker for use in the
+// renderer.
+class HostVarTracker : public ::ppapi::VarTracker {
+ public:
+ HostVarTracker();
+ virtual ~HostVarTracker();
+
+ // Tracks all live NPObjectVar. This is so we can map between instance +
+ // NPObject and get the NPObjectVar corresponding to it. This Add/Remove
+ // function is called by the NPObjectVar when it is created and
+ // destroyed.
+ void AddNPObjectVar(::ppapi::NPObjectVar* object_var);
+ void RemoveNPObjectVar(::ppapi::NPObjectVar* object_var);
+
+ // Looks up a previously registered NPObjectVar for the given NPObject and
+ // instance. Returns NULL if there is no NPObjectVar corresponding to the
+ // given NPObject for the given instance. See AddNPObjectVar above.
+ ::ppapi::NPObjectVar* NPObjectVarForNPObject(PP_Instance instance,
+ NPObject* np_object);
+
+ // Returns the number of NPObjectVar's associated with the given instance.
+ // Returns 0 if the instance isn't known.
+ CONTENT_EXPORT int GetLiveNPObjectVarsForInstance(
+ PP_Instance instance) const;
+
+ // VarTracker public implementation.
+ virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE;
+
+ virtual int TrackSharedMemoryHandle(PP_Instance instance,
+ base::SharedMemoryHandle file,
+ uint32 size_in_bytes) OVERRIDE;
+ virtual bool StopTrackingSharedMemoryHandle(int id,
+ PP_Instance instance,
+ base::SharedMemoryHandle* handle,
+ uint32* size_in_bytes) OVERRIDE;
+
+ private:
+ // VarTracker private implementation.
+ virtual ::ppapi::ArrayBufferVar* CreateArrayBuffer(
+ uint32 size_in_bytes) OVERRIDE;
+ virtual ::ppapi::ArrayBufferVar* CreateShmArrayBuffer(
+ uint32 size_in_bytes, base::SharedMemoryHandle handle) OVERRIDE;
+
+ // Clear the reference count of the given object and remove it from
+ // live_vars_.
+ void ForceReleaseNPObject(::ppapi::NPObjectVar* object_var);
+
+ typedef std::map<NPObject*, ::ppapi::NPObjectVar*>
+ NPObjectToNPObjectVarMap;
+
+ // Lists all known NPObjects, first indexed by the corresponding instance,
+ // then by the NPObject*. This allows us to look up an NPObjectVar given
+ // these two pieces of information.
+ //
+ // The instance map is lazily managed, so we'll add the
+ // NPObjectToNPObjectVarMap lazily when the first NPObject var is created,
+ // and delete it when it's empty.
+ typedef std::map<PP_Instance, linked_ptr<NPObjectToNPObjectVarMap> >
+ InstanceMap;
+ InstanceMap instance_map_;
+
+ // Tracks all shared memory handles used for transmitting array buffers.
+ struct SharedMemoryMapEntry {
+ PP_Instance instance;
+ base::SharedMemoryHandle handle;
+ uint32 size_in_bytes;
+ };
+ typedef std::map<int, SharedMemoryMapEntry> SharedMemoryMap;
+ SharedMemoryMap shared_memory_map_;
+ uint32_t last_shared_memory_map_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostVarTracker);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_HOST_VAR_TRACKER_H_
diff --git a/content/renderer/pepper/host_var_tracker_unittest.cc b/content/renderer/pepper/host_var_tracker_unittest.cc
new file mode 100644
index 0000000..037f059e
--- /dev/null
+++ b/content/renderer/pepper/host_var_tracker_unittest.cc
@@ -0,0 +1,138 @@
+// 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/ppapi_unittest.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/host_var_tracker.h"
+#include "content/renderer/pepper/mock_plugin_delegate.h"
+#include "content/renderer/pepper/mock_resource.h"
+#include "content/renderer/pepper/npapi_glue.h"
+#include "content/renderer/pepper/npobject_var.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppp_instance.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+
+using ppapi::NPObjectVar;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+// Tracked NPObjects -----------------------------------------------------------
+
+int g_npobjects_alive = 0;
+
+void TrackedClassDeallocate(NPObject* npobject) {
+ g_npobjects_alive--;
+ delete npobject;
+}
+
+NPClass g_tracked_npclass = {
+ NP_CLASS_STRUCT_VERSION,
+ NULL,
+ &TrackedClassDeallocate,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+// Returns a new tracked NPObject with a refcount of 1. You'll want to put this
+// in a NPObjectReleaser to free this ref when the test completes.
+NPObject* NewTrackedNPObject() {
+ NPObject* object = new NPObject;
+ object->_class = &g_tracked_npclass;
+ object->referenceCount = 1;
+
+ g_npobjects_alive++;
+ return object;
+}
+
+class ReleaseNPObject {
+ public:
+ void operator()(NPObject* o) const {
+ WebKit::WebBindings::releaseObject(o);
+ }
+};
+
+// Handles automatically releasing a reference to the NPObject on destruction.
+// It's assumed the input has a ref already taken.
+typedef scoped_ptr_malloc<NPObject, ReleaseNPObject> NPObjectReleaser;
+
+} // namespace
+
+class HostVarTrackerTest : public PpapiUnittest {
+ public:
+ HostVarTrackerTest() {
+ }
+
+ HostVarTracker& tracker() {
+ return *HostGlobals::Get()->host_var_tracker();
+ }
+};
+
+TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) {
+ // Make a second instance (the test harness already creates & manages one).
+ scoped_refptr<PluginInstanceImpl> instance2(
+ PluginInstanceImpl::Create(delegate(), NULL, module(), NULL, GURL()));
+ PP_Instance pp_instance2 = instance2->pp_instance();
+
+ // Make an object var.
+ NPObjectReleaser npobject(NewTrackedNPObject());
+ NPObjectToPPVarForTest(instance2.get(), npobject.get());
+
+ EXPECT_EQ(1, g_npobjects_alive);
+ EXPECT_EQ(1, tracker().GetLiveNPObjectVarsForInstance(pp_instance2));
+
+ // Free the instance, this should release the ObjectVar.
+ instance2 = NULL;
+ EXPECT_EQ(0, tracker().GetLiveNPObjectVarsForInstance(pp_instance2));
+}
+
+// Make sure that using the same NPObject should give the same PP_Var
+// each time.
+TEST_F(HostVarTrackerTest, ReuseVar) {
+ NPObjectReleaser npobject(NewTrackedNPObject());
+
+ PP_Var pp_object1 = NPObjectToPPVarForTest(instance(), npobject.get());
+ PP_Var pp_object2 = NPObjectToPPVarForTest(instance(), npobject.get());
+
+ // The two results should be the same.
+ EXPECT_EQ(pp_object1.value.as_id, pp_object2.value.as_id);
+
+ // The objects should be able to get us back to the associated NPObject.
+ // This ObjectVar must be released before we do NPObjectToPPVarForTest again
+ // below so it gets freed and we get a new identifier.
+ {
+ scoped_refptr<NPObjectVar> check_object(NPObjectVar::FromPPVar(pp_object1));
+ ASSERT_TRUE(check_object.get());
+ EXPECT_EQ(instance()->pp_instance(), check_object->pp_instance());
+ EXPECT_EQ(npobject.get(), check_object->np_object());
+ }
+
+ // Remove both of the refs we made above.
+ ::ppapi::VarTracker* var_tracker =
+ ::ppapi::PpapiGlobals::Get()->GetVarTracker();
+ var_tracker->ReleaseVar(static_cast<int32_t>(pp_object2.value.as_id));
+ var_tracker->ReleaseVar(static_cast<int32_t>(pp_object1.value.as_id));
+
+ // Releasing the resource should free the internal ref, and so making a new
+ // one now should generate a new ID.
+ PP_Var pp_object3 = NPObjectToPPVarForTest(instance(), npobject.get());
+ EXPECT_NE(pp_object1.value.as_id, pp_object3.value.as_id);
+ var_tracker->ReleaseVar(static_cast<int32_t>(pp_object3.value.as_id));
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc
new file mode 100644
index 0000000..ea3bdf5
--- /dev/null
+++ b/content/renderer/pepper/message_channel.cc
@@ -0,0 +1,520 @@
+// 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/message_channel.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/host_array_buffer_var.h"
+#include "content/renderer/pepper/npapi_glue.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/v8_var_converter.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebDOMMessageEvent.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebNode.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
+#include "v8/include/v8.h"
+
+using ppapi::ArrayBufferVar;
+using ppapi::PpapiGlobals;
+using ppapi::StringVar;
+using WebKit::WebBindings;
+using WebKit::WebElement;
+using WebKit::WebDOMEvent;
+using WebKit::WebDOMMessageEvent;
+using WebKit::WebPluginContainer;
+using WebKit::WebSerializedScriptValue;
+
+namespace webkit {
+
+namespace ppapi {
+
+namespace {
+
+const char kPostMessage[] = "postMessage";
+const char kV8ToVarConversionError[] = "Failed to convert a PostMessage "
+ "argument from a JavaScript value to a PP_Var. It may have cycles or be of "
+ "an unsupported type.";
+const char kVarToV8ConversionError[] = "Failed to convert a PostMessage "
+ "argument from a PP_Var to a Javascript value. It may have cycles or be of "
+ "an unsupported type.";
+
+// Helper function to get the MessageChannel that is associated with an
+// NPObject*.
+MessageChannel* ToMessageChannel(NPObject* object) {
+ return static_cast<MessageChannel::MessageChannelNPObject*>(object)->
+ message_channel.get();
+}
+
+NPObject* ToPassThroughObject(NPObject* object) {
+ MessageChannel* channel = ToMessageChannel(object);
+ return channel ? channel->passthrough_object() : NULL;
+}
+
+// Helper function to determine if a given identifier is equal to kPostMessage.
+bool IdentifierIsPostMessage(NPIdentifier identifier) {
+ return WebBindings::getStringIdentifier(kPostMessage) == identifier;
+}
+
+bool NPVariantToPPVar(const NPVariant* variant, PP_Var* result) {
+ switch (variant->type) {
+ case NPVariantType_Void:
+ *result = PP_MakeUndefined();
+ return true;
+ case NPVariantType_Null:
+ *result = PP_MakeNull();
+ return true;
+ case NPVariantType_Bool:
+ *result = PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant)));
+ return true;
+ case NPVariantType_Int32:
+ *result = PP_MakeInt32(NPVARIANT_TO_INT32(*variant));
+ return true;
+ case NPVariantType_Double:
+ *result = PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant));
+ return true;
+ case NPVariantType_String:
+ *result = StringVar::StringToPPVar(
+ NPVARIANT_TO_STRING(*variant).UTF8Characters,
+ NPVARIANT_TO_STRING(*variant).UTF8Length);
+ return true;
+ case NPVariantType_Object: {
+ // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it
+ // shouldn't result in a deep copy.
+ v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant);
+ if (!V8VarConverter::FromV8Value(v8_value, v8::Context::GetCurrent(),
+ result)) {
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+// Copy a PP_Var in to a PP_Var that is appropriate for sending via postMessage.
+// This currently just copies the value. For a string Var, the result is a
+// PP_Var with the a copy of |var|'s string contents and a reference count of 1.
+PP_Var CopyPPVar(const PP_Var& var) {
+ switch (var.type) {
+ case PP_VARTYPE_UNDEFINED:
+ case PP_VARTYPE_NULL:
+ case PP_VARTYPE_BOOL:
+ case PP_VARTYPE_INT32:
+ case PP_VARTYPE_DOUBLE:
+ return var;
+ case PP_VARTYPE_STRING: {
+ StringVar* string = StringVar::FromPPVar(var);
+ if (!string)
+ return PP_MakeUndefined();
+ return StringVar::StringToPPVar(string->value());
+ }
+ case PP_VARTYPE_ARRAY_BUFFER: {
+ ArrayBufferVar* buffer = ArrayBufferVar::FromPPVar(var);
+ if (!buffer)
+ return PP_MakeUndefined();
+ PP_Var new_buffer_var = PpapiGlobals::Get()->GetVarTracker()->
+ MakeArrayBufferPPVar(buffer->ByteLength());
+ DCHECK(new_buffer_var.type == PP_VARTYPE_ARRAY_BUFFER);
+ if (new_buffer_var.type != PP_VARTYPE_ARRAY_BUFFER)
+ return PP_MakeUndefined();
+ ArrayBufferVar* new_buffer = ArrayBufferVar::FromPPVar(new_buffer_var);
+ DCHECK(new_buffer);
+ if (!new_buffer)
+ return PP_MakeUndefined();
+ memcpy(new_buffer->Map(), buffer->Map(), buffer->ByteLength());
+ return new_buffer_var;
+ }
+ case PP_VARTYPE_OBJECT:
+ case PP_VARTYPE_ARRAY:
+ case PP_VARTYPE_DICTIONARY:
+ // Objects/Arrays/Dictionaries not supported by PostMessage in-process.
+ NOTREACHED();
+ return PP_MakeUndefined();
+ }
+ NOTREACHED();
+ return PP_MakeUndefined();
+}
+
+//------------------------------------------------------------------------------
+// Implementations of NPClass functions. These are here to:
+// - Implement postMessage behavior.
+// - Forward calls to the 'passthrough' object to allow backwards-compatibility
+// with GetInstanceObject() objects.
+//------------------------------------------------------------------------------
+NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) {
+ return new MessageChannel::MessageChannelNPObject;
+}
+
+void MessageChannelDeallocate(NPObject* object) {
+ MessageChannel::MessageChannelNPObject* instance =
+ static_cast<MessageChannel::MessageChannelNPObject*>(object);
+ delete instance;
+}
+
+bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
+ if (!np_obj)
+ return false;
+
+ // We only handle a function called postMessage.
+ if (IdentifierIsPostMessage(name))
+ return true;
+
+ // Other method names we will pass to the passthrough object, if we have one.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough)
+ return WebBindings::hasMethod(NULL, passthrough, name);
+ return false;
+}
+
+bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* args, uint32 arg_count,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ // We only handle a function called postMessage.
+ if (IdentifierIsPostMessage(name) && (arg_count == 1)) {
+ MessageChannel* message_channel = ToMessageChannel(np_obj);
+ if (message_channel) {
+ PP_Var argument = PP_MakeUndefined();
+ if (!NPVariantToPPVar(&args[0], &argument)) {
+ PpapiGlobals::Get()->LogWithSource(
+ message_channel->instance()->pp_instance(),
+ PP_LOGLEVEL_ERROR, std::string(), kV8ToVarConversionError);
+ return false;
+ }
+ message_channel->PostMessageToNative(argument);
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(argument);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // Other method calls we will pass to the passthrough object, if we have one.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough) {
+ return WebBindings::invoke(NULL, passthrough, name, args, arg_count,
+ result);
+ }
+ return false;
+}
+
+bool MessageChannelInvokeDefault(NPObject* np_obj,
+ const NPVariant* args,
+ uint32 arg_count,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough) {
+ return WebBindings::invokeDefault(NULL, passthrough, args, arg_count,
+ result);
+ }
+ return false;
+}
+
+bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) {
+ if (!np_obj)
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough)
+ return WebBindings::hasProperty(NULL, passthrough, name);
+ return false;
+}
+
+bool MessageChannelGetProperty(NPObject* np_obj, NPIdentifier name,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ // Don't allow getting the postMessage function.
+ if (IdentifierIsPostMessage(name))
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough)
+ return WebBindings::getProperty(NULL, passthrough, name, result);
+ return false;
+}
+
+bool MessageChannelSetProperty(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* variant) {
+ if (!np_obj)
+ return false;
+
+ // Don't allow setting the postMessage function.
+ if (IdentifierIsPostMessage(name))
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough)
+ return WebBindings::setProperty(NULL, passthrough, name, variant);
+ return false;
+}
+
+bool MessageChannelEnumerate(NPObject *np_obj, NPIdentifier **value,
+ uint32_t *count) {
+ if (!np_obj)
+ return false;
+
+ // Invoke on the passthrough object, if we have one, to enumerate its
+ // properties.
+ NPObject* passthrough = ToPassThroughObject(np_obj);
+ if (passthrough) {
+ bool success = WebBindings::enumerate(NULL, passthrough, value, count);
+ if (success) {
+ // Add postMessage to the list and return it.
+ if (std::numeric_limits<size_t>::max() / sizeof(NPIdentifier) <=
+ static_cast<size_t>(*count) + 1) // Else, "always false" x64 warning.
+ return false;
+ NPIdentifier* new_array = static_cast<NPIdentifier*>(
+ std::malloc(sizeof(NPIdentifier) * (*count + 1)));
+ std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count));
+ new_array[*count] = WebBindings::getStringIdentifier(kPostMessage);
+ std::free(*value);
+ *value = new_array;
+ ++(*count);
+ return true;
+ }
+ }
+
+ // Otherwise, build an array that includes only postMessage.
+ *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier)));
+ (*value)[0] = WebBindings::getStringIdentifier(kPostMessage);
+ *count = 1;
+ return true;
+}
+
+NPClass message_channel_class = {
+ NP_CLASS_STRUCT_VERSION,
+ &MessageChannelAllocate,
+ &MessageChannelDeallocate,
+ NULL,
+ &MessageChannelHasMethod,
+ &MessageChannelInvoke,
+ &MessageChannelInvokeDefault,
+ &MessageChannelHasProperty,
+ &MessageChannelGetProperty,
+ &MessageChannelSetProperty,
+ NULL,
+ &MessageChannelEnumerate,
+};
+
+} // namespace
+
+// MessageChannel --------------------------------------------------------------
+MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {
+}
+
+MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {}
+
+MessageChannel::MessageChannel(PluginInstanceImpl* instance)
+ : instance_(instance),
+ passthrough_object_(NULL),
+ np_object_(NULL),
+ weak_ptr_factory_(this),
+ early_message_queue_state_(QUEUE_MESSAGES) {
+ // Now create an NPObject for receiving calls to postMessage. This sets the
+ // reference count to 1. We release it in the destructor.
+ NPObject* obj = WebBindings::createObject(instance_->instanceNPP(),
+ &message_channel_class);
+ DCHECK(obj);
+ np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj);
+ np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
+}
+
+void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
+ v8::HandleScope scope;
+
+ // Because V8 is probably not on the stack for Native->JS calls, we need to
+ // enter the appropriate context for the plugin.
+ WebPluginContainer* container = instance_->container();
+ // It's possible that container() is NULL if the plugin has been removed from
+ // the DOM (but the PluginInstance is not destroyed yet).
+ if (!container)
+ return;
+
+ v8::Local<v8::Context> context =
+ container->element().document().frame()->mainWorldScriptContext();
+ // If the page is being destroyed, the context may be empty.
+ if (context.IsEmpty())
+ return;
+ v8::Context::Scope context_scope(context);
+
+ v8::Handle<v8::Value> v8_val;
+ if (!V8VarConverter::ToV8Value(message_data, context, &v8_val)) {
+ PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(),
+ PP_LOGLEVEL_ERROR, std::string(), kVarToV8ConversionError);
+ return;
+ }
+
+ // This is for backward compatibility. It usually makes sense for us to return
+ // a string object rather than a string primitive because it allows multiple
+ // references to the same string (as with PP_Var strings). However, prior to
+ // implementing dictionary and array, vars we would return a string primitive
+ // here. Changing it to an object now will break existing code that uses
+ // strict comparisons for strings returned from PostMessage. e.g. x === "123"
+ // will no longer return true. So if the only value to return is a string
+ // object, just return the string primitive.
+ if (v8_val->IsStringObject())
+ v8_val = v8_val->ToString();
+
+ WebSerializedScriptValue serialized_val =
+ WebSerializedScriptValue::serialize(v8_val);
+
+ if (instance_->module()->IsProxied()) {
+ if (early_message_queue_state_ != SEND_DIRECTLY) {
+ // We can't just PostTask here; the messages would arrive out of
+ // order. Instead, we queue them up until we're ready to post
+ // them.
+ early_message_queue_.push_back(serialized_val);
+ } else {
+ // The proxy sent an asynchronous message, so the plugin is already
+ // unblocked. Therefore, there's no need to PostTask.
+ DCHECK(early_message_queue_.size() == 0);
+ PostMessageToJavaScriptImpl(serialized_val);
+ }
+ } else {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MessageChannel::PostMessageToJavaScriptImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ serialized_val));
+ }
+}
+
+void MessageChannel::StopQueueingJavaScriptMessages() {
+ // We PostTask here instead of draining the message queue directly
+ // since we haven't finished initializing the WebPluginImpl yet, so
+ // the plugin isn't available in the DOM.
+ early_message_queue_state_ = DRAIN_PENDING;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MessageChannel::DrainEarlyMessageQueue,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MessageChannel::QueueJavaScriptMessages() {
+ if (early_message_queue_state_ == DRAIN_PENDING)
+ early_message_queue_state_ = DRAIN_CANCELLED;
+ else
+ early_message_queue_state_ = QUEUE_MESSAGES;
+}
+
+void MessageChannel::DrainEarlyMessageQueue() {
+ // Take a reference on the PluginInstance. This is because JavaScript code
+ // may delete the plugin, which would destroy the PluginInstance and its
+ // corresponding MessageChannel.
+ scoped_refptr<PluginInstanceImpl> instance_ref(instance_);
+
+ if (early_message_queue_state_ == DRAIN_CANCELLED) {
+ early_message_queue_state_ = QUEUE_MESSAGES;
+ return;
+ }
+ DCHECK(early_message_queue_state_ == DRAIN_PENDING);
+
+ while (!early_message_queue_.empty()) {
+ PostMessageToJavaScriptImpl(early_message_queue_.front());
+ early_message_queue_.pop_front();
+ }
+ early_message_queue_state_ = SEND_DIRECTLY;
+}
+
+void MessageChannel::PostMessageToJavaScriptImpl(
+ const WebSerializedScriptValue& message_data) {
+ DCHECK(instance_);
+
+ WebPluginContainer* container = instance_->container();
+ // It's possible that container() is NULL if the plugin has been removed from
+ // the DOM (but the PluginInstance is not destroyed yet).
+ if (!container)
+ return;
+
+ WebDOMEvent event =
+ container->element().document().createEvent("MessageEvent");
+ WebDOMMessageEvent msg_event = event.to<WebDOMMessageEvent>();
+ msg_event.initMessageEvent("message", // type
+ false, // canBubble
+ false, // cancelable
+ message_data, // data
+ "", // origin [*]
+ NULL, // source [*]
+ ""); // lastEventId
+ // [*] Note that the |origin| is only specified for cross-document and server-
+ // sent messages, while |source| is only specified for cross-document
+ // messages:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html
+ // This currently behaves like Web Workers. On Firefox, Chrome, and Safari
+ // at least, postMessage on Workers does not provide the origin or source.
+ // TODO(dmichael): Add origin if we change to a more iframe-like origin
+ // policy (see crbug.com/81537)
+
+ container->element().dispatchEvent(msg_event);
+}
+
+void MessageChannel::PostMessageToNative(PP_Var message_data) {
+ if (instance_->module()->IsProxied()) {
+ // In the proxied case, the copy will happen via serializiation, and the
+ // message is asynchronous. Therefore there's no need to copy the Var, nor
+ // to PostTask.
+ PostMessageToNativeImpl(message_data);
+ } else {
+ // Make a copy of the message data for the Task we will run.
+ PP_Var var_copy(CopyPPVar(message_data));
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MessageChannel::PostMessageToNativeImpl,
+ weak_ptr_factory_.GetWeakPtr(),
+ var_copy));
+ }
+}
+
+void MessageChannel::PostMessageToNativeImpl(PP_Var message_data) {
+ instance_->HandleMessage(message_data);
+}
+
+MessageChannel::~MessageChannel() {
+ WebBindings::releaseObject(np_object_);
+ if (passthrough_object_)
+ WebBindings::releaseObject(passthrough_object_);
+}
+
+void MessageChannel::SetPassthroughObject(NPObject* passthrough) {
+ // Retain the passthrough object; We need to ensure it lives as long as this
+ // MessageChannel.
+ if (passthrough)
+ WebBindings::retainObject(passthrough);
+
+ // If we had a passthrough set already, release it. Note that we retain the
+ // incoming passthrough object first, so that we behave correctly if anyone
+ // invokes:
+ // SetPassthroughObject(passthrough_object());
+ if (passthrough_object_)
+ WebBindings::releaseObject(passthrough_object_);
+
+ passthrough_object_ = passthrough;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/message_channel.h b/content/renderer/pepper/message_channel.h
new file mode 100644
index 0000000..322c4b4
--- /dev/null
+++ b/content/renderer/pepper/message_channel.h
@@ -0,0 +1,123 @@
+// 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_MESSAGE_CHANNEL_H_
+#define CONTENT_RENDERER_PEPPER_MESSAGE_CHANNEL_H_
+
+#include <deque>
+
+#include "base/memory/weak_ptr.h"
+#include "ppapi/shared_impl/resource.h"
+#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+struct PP_Var;
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstanceImpl;
+
+// MessageChannel implements bidirectional postMessage functionality, allowing
+// calls from JavaScript to plugins and vice-versa. See
+// PPB_Messaging::PostMessage and PPP_Messaging::HandleMessage for more
+// information.
+//
+// Currently, only 1 MessageChannel can exist, to implement postMessage
+// functionality for the instance interfaces. In the future, when we create a
+// MessagePort type in PPAPI, those may be implemented here as well with some
+// refactoring.
+// - Separate message ports won't require the passthrough object.
+// - The message target won't be limited to instance, and should support
+// either plugin-provided or JS objects.
+// TODO(dmichael): Add support for separate MessagePorts.
+class MessageChannel {
+ public:
+ // MessageChannelNPObject is a simple struct that adds a pointer back to a
+ // MessageChannel instance. This way, we can use an NPObject to allow
+ // JavaScript interactions without forcing MessageChannel to inherit from
+ // NPObject.
+ struct MessageChannelNPObject : public NPObject {
+ MessageChannelNPObject();
+ ~MessageChannelNPObject();
+
+ base::WeakPtr<MessageChannel> message_channel;
+ };
+
+ explicit MessageChannel(PluginInstanceImpl* instance);
+ ~MessageChannel();
+
+ // Post a message to the onmessage handler for this channel's instance
+ // asynchronously.
+ void PostMessageToJavaScript(PP_Var message_data);
+ // Post a message to the PPP_Instance HandleMessage function for this
+ // channel's instance.
+ void PostMessageToNative(PP_Var message_data);
+
+ // Return the NPObject* to which we should forward any calls which aren't
+ // related to postMessage. Note that this can be NULL; it only gets set if
+ // there is a scriptable 'InstanceObject' associated with this channel's
+ // instance.
+ NPObject* passthrough_object() {
+ return passthrough_object_;
+ }
+ void SetPassthroughObject(NPObject* passthrough);
+
+ NPObject* np_object() { return np_object_; }
+
+ PluginInstanceImpl* instance() {
+ return instance_;
+ }
+
+ // Messages sent to JavaScript are queued by default. After the DOM is
+ // set up for the plugin, users of MessageChannel should call
+ // StopQueueingJavaScriptMessages to start dispatching messages to JavaScript.
+ void QueueJavaScriptMessages();
+ void StopQueueingJavaScriptMessages();
+
+ private:
+ PluginInstanceImpl* instance_;
+
+ // We pass all non-postMessage calls through to the passthrough_object_.
+ // This way, a plugin can use PPB_Class or PPP_Class_Deprecated and also
+ // postMessage. This is necessary to support backwards-compatibility, and
+ // also trusted plugins for which we will continue to support synchronous
+ // scripting.
+ NPObject* passthrough_object_;
+
+ // The NPObject we use to expose postMessage to JavaScript.
+ MessageChannelNPObject* np_object_;
+
+ // Post a message to the onmessage handler for this channel's instance
+ // synchronously. This is used by PostMessageToJavaScript.
+ void PostMessageToJavaScriptImpl(
+ const WebKit::WebSerializedScriptValue& message_data);
+ // Post a message to the PPP_Instance HandleMessage function for this
+ // channel's instance. This is used by PostMessageToNative.
+ void PostMessageToNativeImpl(PP_Var message_data);
+
+ void DrainEarlyMessageQueue();
+
+ // This is used to ensure pending tasks will not fire after this object is
+ // destroyed.
+ base::WeakPtrFactory<MessageChannel> weak_ptr_factory_;
+
+ // TODO(teravest): Remove all the tricky DRAIN_CANCELLED logic once
+ // webkit::ppapi::PluginInstance::ResetAsProxied() is gone.
+ std::deque<WebKit::WebSerializedScriptValue> early_message_queue_;
+ enum EarlyMessageQueueState {
+ QUEUE_MESSAGES, // Queue JS messages.
+ SEND_DIRECTLY, // Post JS messages directly.
+ DRAIN_PENDING, // Drain queue, then transition to DIRECT.
+ DRAIN_CANCELLED // Preempt drain, go back to QUEUE.
+ };
+ EarlyMessageQueueState early_message_queue_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageChannel);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_MESSAGE_CHANNEL_H_
diff --git a/content/renderer/pepper/mock_platform_image_2d.cc b/content/renderer/pepper/mock_platform_image_2d.cc
new file mode 100644
index 0000000..2aba190
--- /dev/null
+++ b/content/renderer/pepper/mock_platform_image_2d.cc
@@ -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.
+
+#include "content/renderer/pepper/mock_platform_image_2d.h"
+
+#include "skia/ext/platform_canvas.h"
+
+namespace webkit {
+namespace ppapi {
+
+MockPlatformImage2D::MockPlatformImage2D(int width, int height)
+ : width_(width),
+ height_(height) {
+}
+
+MockPlatformImage2D::~MockPlatformImage2D() {
+}
+
+skia::PlatformCanvas* MockPlatformImage2D::Map() {
+ return skia::CreatePlatformCanvas(width_, height_, true);
+}
+
+intptr_t MockPlatformImage2D::GetSharedMemoryHandle(uint32* byte_count) const {
+ *byte_count = 0;
+ return 0;
+}
+
+TransportDIB* MockPlatformImage2D::GetTransportDIB() const {
+ return NULL;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/mock_platform_image_2d.h b/content/renderer/pepper/mock_platform_image_2d.h
new file mode 100644
index 0000000..eedd4af
--- /dev/null
+++ b/content/renderer/pepper/mock_platform_image_2d.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.
+
+#ifndef CONTENT_RENDERER_PEPPER_MOCK_PLATFORM_IMAGE_2D_H_
+#define CONTENT_RENDERER_PEPPER_MOCK_PLATFORM_IMAGE_2D_H_
+
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace webkit {
+namespace ppapi {
+
+class MockPlatformImage2D : public PluginDelegate::PlatformImage2D {
+ public:
+ MockPlatformImage2D(int width, int height);
+ virtual ~MockPlatformImage2D();
+
+ // PlatformImage2D implementation.
+ virtual skia::PlatformCanvas* Map() OVERRIDE;
+ virtual intptr_t GetSharedMemoryHandle(uint32* byte_count) const OVERRIDE;
+ virtual TransportDIB* GetTransportDIB() const OVERRIDE;
+
+ private:
+ int width_;
+ int height_;
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_MOCK_PLATFORM_IMAGE_2D_H_
diff --git a/content/renderer/pepper/mock_plugin_delegate.cc b/content/renderer/pepper/mock_plugin_delegate.cc
new file mode 100644
index 0000000..aae195e
--- /dev/null
+++ b/content/renderer/pepper/mock_plugin_delegate.cc
@@ -0,0 +1,415 @@
+// 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/mock_plugin_delegate.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/renderer/pepper/mock_platform_image_2d.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
+#include "ppapi/shared_impl/ppapi_preferences.h"
+#include "third_party/WebKit/public/platform/WebGamepads.h"
+
+namespace webkit {
+namespace ppapi {
+
+MockPluginDelegate::MockPluginDelegate() {
+}
+
+MockPluginDelegate::~MockPluginDelegate() {
+}
+
+void MockPluginDelegate::PluginFocusChanged(PluginInstanceImpl* instance,
+ bool focused) {
+}
+
+void MockPluginDelegate::PluginTextInputTypeChanged(
+ PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::PluginCaretPositionChanged(
+ PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::PluginRequestedCancelComposition(
+ PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::PluginSelectionChanged(PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::SimulateImeSetComposition(
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end) {
+}
+
+void MockPluginDelegate::SimulateImeConfirmComposition(
+ const base::string16& text) {
+}
+
+void MockPluginDelegate::PluginCrashed(PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::InstanceCreated(PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::InstanceDeleted(PluginInstanceImpl* instance) {
+}
+
+scoped_ptr< ::ppapi::thunk::ResourceCreationAPI>
+MockPluginDelegate::CreateResourceCreationAPI(PluginInstanceImpl* instance) {
+ return scoped_ptr< ::ppapi::thunk::ResourceCreationAPI>();
+}
+
+SkBitmap* MockPluginDelegate::GetSadPluginBitmap() {
+ return NULL;
+}
+
+WebKit::WebPlugin* MockPluginDelegate::CreatePluginReplacement(
+ const base::FilePath& file_path) {
+ return NULL;
+}
+
+MockPluginDelegate::PlatformImage2D* MockPluginDelegate::CreateImage2D(
+ int width,
+ int height) {
+ return new MockPlatformImage2D(width, height);
+}
+
+PluginDelegate::PlatformGraphics2D* MockPluginDelegate::GetGraphics2D(
+ PluginInstanceImpl* instance,
+ PP_Resource graphics_2d) {
+ return NULL;
+}
+
+MockPluginDelegate::PlatformContext3D* MockPluginDelegate::CreateContext3D() {
+ return NULL;
+}
+
+MockPluginDelegate::PlatformVideoDecoder*
+MockPluginDelegate::CreateVideoDecoder(
+ media::VideoDecodeAccelerator::Client* client,
+ int32 command_buffer_route_id) {
+ return NULL;
+}
+
+MockPluginDelegate::PlatformVideoCapture*
+MockPluginDelegate::CreateVideoCapture(
+ const std::string& device_id,
+ const GURL& document_url,
+ PlatformVideoCaptureEventHandler* handler){
+ return NULL;
+}
+
+uint32_t MockPluginDelegate::GetAudioHardwareOutputSampleRate() {
+ return 0;
+}
+
+uint32_t MockPluginDelegate::GetAudioHardwareOutputBufferSize() {
+ return 0;
+}
+
+MockPluginDelegate::PlatformAudioOutput* MockPluginDelegate::CreateAudioOutput(
+ uint32_t sample_rate,
+ uint32_t sample_count,
+ PlatformAudioOutputClient* client) {
+ return NULL;
+}
+
+MockPluginDelegate::PlatformAudioInput* MockPluginDelegate::CreateAudioInput(
+ const std::string& device_id,
+ const GURL& document_url,
+ uint32_t sample_rate,
+ uint32_t sample_count,
+ PlatformAudioInputClient* client) {
+ return NULL;
+}
+
+MockPluginDelegate::Broker* MockPluginDelegate::ConnectToBroker(
+ PPB_Broker_Impl* client) {
+ return NULL;
+}
+
+void MockPluginDelegate::NumberOfFindResultsChanged(int identifier,
+ int total,
+ bool final_result) {
+}
+
+void MockPluginDelegate::SelectedFindResultChanged(int identifier, int index) {
+}
+
+bool MockPluginDelegate::AsyncOpenFile(const base::FilePath& path,
+ int flags,
+ const AsyncOpenFileCallback& callback) {
+ return false;
+}
+
+void MockPluginDelegate::AsyncOpenFileSystemURL(
+ const GURL& path,
+ int flags,
+ const AsyncOpenFileSystemURLCallback& callback) {
+}
+
+bool MockPluginDelegate::IsFileSystemOpened(
+ PP_Instance instance,
+ PP_Resource resource) const {
+ return false;
+}
+
+PP_FileSystemType MockPluginDelegate::GetFileSystemType(
+ PP_Instance instance,
+ PP_Resource resource) const {
+ return PP_FILESYSTEMTYPE_INVALID;
+}
+
+GURL MockPluginDelegate::GetFileSystemRootUrl(
+ PP_Instance instance,
+ PP_Resource resource) const {
+ return GURL();
+}
+
+void MockPluginDelegate::MakeDirectory(
+ const GURL& path,
+ bool recursive,
+ const StatusCallback& callback) {
+}
+
+void MockPluginDelegate::Query(
+ const GURL& path,
+ const MetadataCallback& success_callback,
+ const StatusCallback& error_callback) {
+}
+
+void MockPluginDelegate::ReadDirectoryEntries(
+ const GURL& path,
+ const ReadDirectoryCallback& success_callback,
+ const StatusCallback& error_callback) {
+}
+
+void MockPluginDelegate::Touch(
+ const GURL& path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) {
+}
+
+void MockPluginDelegate::SetLength(
+ const GURL& path,
+ int64_t length,
+ const StatusCallback& callback) {
+}
+
+void MockPluginDelegate::Delete(
+ const GURL& path,
+ const StatusCallback& callback) {
+}
+
+void MockPluginDelegate::Rename(
+ const GURL& file_path,
+ const GURL& new_file_path,
+ const StatusCallback& callback) {
+}
+
+void MockPluginDelegate::ReadDirectory(
+ const GURL& directory_path,
+ const ReadDirectoryCallback& success_callback,
+ const StatusCallback& error_callback) {
+}
+
+void MockPluginDelegate::QueryAvailableSpace(
+ const GURL& origin, quota::StorageType type,
+ const AvailableSpaceCallback& callback) {
+}
+
+void MockPluginDelegate::WillUpdateFile(const GURL& file_path) {
+}
+
+void MockPluginDelegate::DidUpdateFile(const GURL& file_path, int64_t delta) {
+}
+
+void MockPluginDelegate::SyncGetFileSystemPlatformPath(
+ const GURL& url,
+ base::FilePath* platform_path) {
+ DCHECK(platform_path);
+ *platform_path = base::FilePath();
+}
+
+scoped_refptr<base::MessageLoopProxy>
+MockPluginDelegate::GetFileThreadMessageLoopProxy() {
+ return scoped_refptr<base::MessageLoopProxy>();
+}
+
+uint32 MockPluginDelegate::TCPSocketCreate() {
+ return 0;
+}
+
+void MockPluginDelegate::TCPSocketConnect(PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id,
+ const std::string& host,
+ uint16_t port) {
+}
+
+void MockPluginDelegate::TCPSocketConnectWithNetAddress(
+ PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id,
+ const PP_NetAddress_Private& addr) {
+}
+
+void MockPluginDelegate::TCPSocketSSLHandshake(
+ uint32 socket_id,
+ const std::string& server_name,
+ uint16_t server_port,
+ const std::vector<std::vector<char> >& trusted_certs,
+ const std::vector<std::vector<char> >& untrusted_certs) {
+}
+
+void MockPluginDelegate::TCPSocketRead(uint32 socket_id,
+ int32_t bytes_to_read) {
+}
+
+void MockPluginDelegate::TCPSocketWrite(uint32 socket_id,
+ const std::string& buffer) {
+}
+
+void MockPluginDelegate::TCPSocketSetOption(
+ uint32 socket_id,
+ PP_TCPSocket_Option name,
+ const ::ppapi::SocketOptionData& value) {
+}
+
+void MockPluginDelegate::TCPSocketDisconnect(uint32 socket_id) {
+}
+
+void MockPluginDelegate::RegisterTCPSocket(PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id) {
+}
+
+void MockPluginDelegate::TCPServerSocketListen(
+ PP_Resource socket_resource,
+ const PP_NetAddress_Private& addr,
+ int32_t backlog) {
+}
+
+void MockPluginDelegate::TCPServerSocketAccept(uint32 server_socket_id) {
+}
+
+void MockPluginDelegate::TCPServerSocketStopListening(
+ PP_Resource socket_resource,
+ uint32 socket_id) {
+}
+
+bool MockPluginDelegate::AddNetworkListObserver(
+ webkit_glue::NetworkListObserver* observer) {
+ return false;
+}
+
+void MockPluginDelegate::RemoveNetworkListObserver(
+ webkit_glue::NetworkListObserver* observer) {
+}
+
+bool MockPluginDelegate::X509CertificateParseDER(
+ const std::vector<char>& der,
+ ::ppapi::PPB_X509Certificate_Fields* fields) {
+ return false;
+}
+
+FullscreenContainer* MockPluginDelegate::CreateFullscreenContainer(
+ PluginInstanceImpl* instance) {
+ return NULL;
+}
+
+gfx::Size MockPluginDelegate::GetScreenSize() {
+ return gfx::Size(1024, 768);
+}
+
+std::string MockPluginDelegate::GetDefaultEncoding() {
+ return "iso-8859-1";
+}
+
+void MockPluginDelegate::ZoomLimitsChanged(double minimum_factor,
+ double maximum_factor) {
+}
+
+base::SharedMemory* MockPluginDelegate::CreateAnonymousSharedMemory(
+ size_t size) {
+ return NULL;
+}
+
+::ppapi::Preferences MockPluginDelegate::GetPreferences() {
+ return ::ppapi::Preferences();
+}
+
+bool MockPluginDelegate::LockMouse(PluginInstanceImpl* instance) {
+ return false;
+}
+
+void MockPluginDelegate::UnlockMouse(PluginInstanceImpl* instance) {
+}
+
+bool MockPluginDelegate::IsMouseLocked(PluginInstanceImpl* instance) {
+ return false;
+}
+
+void MockPluginDelegate::DidChangeCursor(PluginInstanceImpl* instance,
+ const WebKit::WebCursorInfo& cursor) {
+}
+
+void MockPluginDelegate::DidReceiveMouseEvent(PluginInstanceImpl* instance) {
+}
+
+void MockPluginDelegate::SampleGamepads(WebKit::WebGamepads* data) {
+ data->length = 0;
+}
+
+bool MockPluginDelegate::IsInFullscreenMode() {
+ return false;
+}
+
+bool MockPluginDelegate::IsPageVisible() const {
+ return true;
+}
+
+int MockPluginDelegate::EnumerateDevices(
+ PP_DeviceType_Dev type,
+ const EnumerateDevicesCallback& callback) {
+ return -1;
+}
+
+void MockPluginDelegate::StopEnumerateDevices(int request_id) {
+}
+
+IPC::PlatformFileForTransit MockPluginDelegate::ShareHandleWithRemote(
+ base::PlatformFile handle,
+ base::ProcessId target_process_id,
+ bool should_close_source) const {
+ return IPC::InvalidPlatformFileForTransit();
+}
+
+bool MockPluginDelegate::IsRunningInProcess(PP_Instance instance) const {
+ return false;
+}
+
+void MockPluginDelegate::HandleDocumentLoad(
+ PluginInstanceImpl* instance,
+ const WebKit::WebURLResponse& response) {
+}
+
+content::RendererPpapiHost* MockPluginDelegate::CreateExternalPluginModule(
+ scoped_refptr<PluginModule> module,
+ const base::FilePath& path,
+ ::ppapi::PpapiPermissions permissions,
+ const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) {
+ return NULL;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/mock_plugin_delegate.h b/content/renderer/pepper/mock_plugin_delegate.h
new file mode 100644
index 0000000..8631dd7
--- /dev/null
+++ b/content/renderer/pepper/mock_plugin_delegate.h
@@ -0,0 +1,205 @@
+// 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_MOCK_PLUGIN_DELEGATE_H_
+#define CONTENT_RENDERER_PEPPER_MOCK_PLUGIN_DELEGATE_H_
+
+#include "content/renderer/pepper/plugin_delegate.h"
+
+struct PP_NetAddress_Private;
+namespace ppapi { class PPB_X509Certificate_Fields; }
+
+namespace webkit {
+namespace ppapi {
+
+class MockPluginDelegate : public PluginDelegate {
+ public:
+ MockPluginDelegate();
+ virtual ~MockPluginDelegate();
+
+ virtual void PluginFocusChanged(PluginInstanceImpl* instance,
+ bool focused) OVERRIDE;
+ virtual void PluginTextInputTypeChanged(
+ PluginInstanceImpl* instance) OVERRIDE;
+ virtual void PluginCaretPositionChanged(
+ PluginInstanceImpl* instance) OVERRIDE;
+ virtual void PluginRequestedCancelComposition(
+ PluginInstanceImpl* instance) OVERRIDE;
+ virtual void PluginSelectionChanged(PluginInstanceImpl* instance) OVERRIDE;
+ virtual void SimulateImeSetComposition(
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end) OVERRIDE;
+ virtual void SimulateImeConfirmComposition(
+ const base::string16& text) OVERRIDE;
+ virtual void PluginCrashed(PluginInstanceImpl* instance) OVERRIDE;
+ virtual void InstanceCreated(PluginInstanceImpl* instance) OVERRIDE;
+ virtual void InstanceDeleted(PluginInstanceImpl* instance) OVERRIDE;
+ virtual scoped_ptr< ::ppapi::thunk::ResourceCreationAPI>
+ CreateResourceCreationAPI(PluginInstanceImpl* instance) OVERRIDE;
+ virtual SkBitmap* GetSadPluginBitmap() OVERRIDE;
+ virtual WebKit::WebPlugin* CreatePluginReplacement(
+ const base::FilePath& file_path) OVERRIDE;
+ virtual PlatformImage2D* CreateImage2D(int width, int height) OVERRIDE;
+ virtual PlatformGraphics2D* GetGraphics2D(PluginInstanceImpl* instance,
+ PP_Resource graphics_2d) OVERRIDE;
+ virtual PlatformContext3D* CreateContext3D() OVERRIDE;
+ virtual PlatformVideoDecoder* CreateVideoDecoder(
+ media::VideoDecodeAccelerator::Client* client,
+ int32 command_buffer_route_id) OVERRIDE;
+ virtual PlatformVideoCapture* CreateVideoCapture(
+ const std::string& device_id,
+ const GURL& document_url,
+ PlatformVideoCaptureEventHandler* handler) OVERRIDE;
+ virtual uint32_t GetAudioHardwareOutputSampleRate() OVERRIDE;
+ virtual uint32_t GetAudioHardwareOutputBufferSize() OVERRIDE;
+ virtual PlatformAudioOutput* CreateAudioOutput(
+ uint32_t sample_rate,
+ uint32_t sample_count,
+ PlatformAudioOutputClient* client) OVERRIDE;
+ virtual PlatformAudioInput* CreateAudioInput(
+ const std::string& device_id,
+ const GURL& document_url,
+ uint32_t sample_rate,
+ uint32_t sample_count,
+ PlatformAudioInputClient* client) OVERRIDE;
+ virtual Broker* ConnectToBroker(PPB_Broker_Impl* client) OVERRIDE;
+ virtual void NumberOfFindResultsChanged(int identifier,
+ int total,
+ bool final_result) OVERRIDE;
+ virtual void SelectedFindResultChanged(int identifier, int index) OVERRIDE;
+ virtual bool AsyncOpenFile(const base::FilePath& path,
+ int flags,
+ const AsyncOpenFileCallback& callback) OVERRIDE;
+ virtual void AsyncOpenFileSystemURL(
+ const GURL& path,
+ int flags,
+ const AsyncOpenFileSystemURLCallback& callback) OVERRIDE;
+ virtual bool IsFileSystemOpened(PP_Instance instance,
+ PP_Resource resource) const OVERRIDE;
+ virtual PP_FileSystemType GetFileSystemType(
+ PP_Instance instance,
+ PP_Resource resource) const OVERRIDE;
+ virtual GURL GetFileSystemRootUrl(PP_Instance instance,
+ PP_Resource resource) const OVERRIDE;
+ virtual void MakeDirectory(
+ const GURL& path,
+ bool recursive,
+ const StatusCallback& callback) OVERRIDE;
+ virtual void Query(const GURL& path,
+ const MetadataCallback& success_callback,
+ const StatusCallback& error_callback) OVERRIDE;
+ virtual void ReadDirectoryEntries(
+ const GURL& path,
+ const ReadDirectoryCallback& success_callback,
+ const StatusCallback& error_callback) OVERRIDE;
+ virtual void Touch(const GURL& path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) OVERRIDE;
+ virtual void SetLength(const GURL& path,
+ int64_t length,
+ const StatusCallback& callback) OVERRIDE;
+ virtual void Delete(const GURL& path,
+ const StatusCallback& callback) OVERRIDE;
+ virtual void Rename(const GURL& file_path,
+ const GURL& new_file_path,
+ const StatusCallback& callback) OVERRIDE;
+ virtual void ReadDirectory(
+ const GURL& directory_path,
+ const ReadDirectoryCallback& success_callback,
+ const StatusCallback& error_callback) OVERRIDE;
+ virtual void QueryAvailableSpace(
+ const GURL& origin,
+ quota::StorageType type,
+ const AvailableSpaceCallback& callback) OVERRIDE;
+ virtual void WillUpdateFile(const GURL& file_path) OVERRIDE;
+ virtual void DidUpdateFile(const GURL& file_path, int64_t delta) OVERRIDE;
+ virtual void SyncGetFileSystemPlatformPath(
+ const GURL& url,
+ base::FilePath* platform_path) OVERRIDE;
+ virtual scoped_refptr<base::MessageLoopProxy>
+ GetFileThreadMessageLoopProxy() OVERRIDE;
+ virtual uint32 TCPSocketCreate() OVERRIDE;
+ virtual void TCPSocketConnect(PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id,
+ const std::string& host,
+ uint16_t port) OVERRIDE;
+ virtual void TCPSocketConnectWithNetAddress(
+ PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id,
+ const PP_NetAddress_Private& addr) OVERRIDE;
+ virtual void TCPSocketSSLHandshake(
+ uint32 socket_id,
+ const std::string& server_name,
+ uint16_t server_port,
+ const std::vector<std::vector<char> >& trusted_certs,
+ const std::vector<std::vector<char> >& untrusted_certs) OVERRIDE;
+ virtual void TCPSocketRead(uint32 socket_id, int32_t bytes_to_read) OVERRIDE;
+ virtual void TCPSocketWrite(uint32 socket_id,
+ const std::string& buffer) OVERRIDE;
+ virtual void TCPSocketDisconnect(uint32 socket_id) OVERRIDE;
+ virtual void TCPSocketSetOption(
+ uint32 socket_id,
+ PP_TCPSocket_Option name,
+ const ::ppapi::SocketOptionData& value) OVERRIDE;
+ virtual void RegisterTCPSocket(PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id) OVERRIDE;
+ virtual void TCPServerSocketListen(PP_Resource socket_resource,
+ const PP_NetAddress_Private& addr,
+ int32_t backlog) OVERRIDE;
+ virtual void TCPServerSocketAccept(uint32 server_socket_id) OVERRIDE;
+ virtual void TCPServerSocketStopListening(PP_Resource socket_resource,
+ uint32 socket_id) OVERRIDE;
+ // Add/remove a network list observer.
+ virtual bool AddNetworkListObserver(
+ webkit_glue::NetworkListObserver* observer) OVERRIDE;
+ virtual void RemoveNetworkListObserver(
+ webkit_glue::NetworkListObserver* observer) OVERRIDE;
+ virtual bool X509CertificateParseDER(
+ const std::vector<char>& der,
+ ::ppapi::PPB_X509Certificate_Fields* fields) OVERRIDE;
+ virtual FullscreenContainer* CreateFullscreenContainer(
+ PluginInstanceImpl* instance) OVERRIDE;
+ virtual gfx::Size GetScreenSize() OVERRIDE;
+ virtual std::string GetDefaultEncoding() OVERRIDE;
+ virtual void ZoomLimitsChanged(double minimum_factor,
+ double maximum_factor) OVERRIDE;
+ virtual base::SharedMemory* CreateAnonymousSharedMemory(size_t size) OVERRIDE;
+ virtual ::ppapi::Preferences GetPreferences() OVERRIDE;
+ virtual bool LockMouse(PluginInstanceImpl* instance) OVERRIDE;
+ virtual void UnlockMouse(PluginInstanceImpl* instance) OVERRIDE;
+ virtual bool IsMouseLocked(PluginInstanceImpl* instance) OVERRIDE;
+ virtual void DidChangeCursor(PluginInstanceImpl* instance,
+ const WebKit::WebCursorInfo& cursor) OVERRIDE;
+ virtual void DidReceiveMouseEvent(PluginInstanceImpl* instance) OVERRIDE;
+ virtual void SampleGamepads(WebKit::WebGamepads* data) OVERRIDE;
+ virtual bool IsInFullscreenMode() OVERRIDE;
+ virtual bool IsPageVisible() const OVERRIDE;
+ virtual int EnumerateDevices(
+ PP_DeviceType_Dev type,
+ const EnumerateDevicesCallback& callback) OVERRIDE;
+ virtual void StopEnumerateDevices(int request_id) OVERRIDE;
+ virtual IPC::PlatformFileForTransit ShareHandleWithRemote(
+ base::PlatformFile handle,
+ base::ProcessId target_process_id,
+ bool should_close_source) const OVERRIDE;
+ virtual bool IsRunningInProcess(PP_Instance instance) const OVERRIDE;
+ virtual void HandleDocumentLoad(
+ PluginInstanceImpl* instance,
+ const WebKit::WebURLResponse& response) OVERRIDE;
+ virtual content::RendererPpapiHost* CreateExternalPluginModule(
+ scoped_refptr<PluginModule> module,
+ const base::FilePath& path,
+ ::ppapi::PpapiPermissions permissions,
+ const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) OVERRIDE;
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_MOCK_PLUGIN_DELEGATE_H_
diff --git a/content/renderer/pepper/mock_resource.h b/content/renderer/pepper/mock_resource.h
new file mode 100644
index 0000000..60531f0
--- /dev/null
+++ b/content/renderer/pepper/mock_resource.h
@@ -0,0 +1,28 @@
+// 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_MOCK_RESOURCE_H_
+#define CONTENT_RENDERER_PEPPER_MOCK_RESOURCE_H_
+
+#include "ppapi/shared_impl/resource.h"
+
+namespace webkit {
+namespace ppapi {
+
+// Tests can derive from this to implement special test-specific resources.
+// It's assumed that a test will only need one mock resource, so it can
+// static_cast to get its own implementation.
+class MockResource : public ::ppapi::Resource {
+ public:
+ MockResource(PP_Instance instance)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance) {}
+
+ private:
+ virtual ~MockResource() {}
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_MOCK_RESOURCE_H_
diff --git a/content/renderer/pepper/npapi_glue.cc b/content/renderer/pepper/npapi_glue.cc
new file mode 100644
index 0000000..f8b0c52
--- /dev/null
+++ b/content/renderer/pepper/npapi_glue.cc
@@ -0,0 +1,357 @@
+// 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/pepper/npapi_glue.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_util.h"
+#include "content/renderer/pepper/host_array_buffer_var.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/host_var_tracker.h"
+#include "content/renderer/pepper/npobject_var.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/plugin_object.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/pp_var.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "v8/include/v8.h"
+
+using ppapi::NPObjectVar;
+using ppapi::PpapiGlobals;
+using ppapi::StringVar;
+using ppapi::Var;
+using WebKit::WebArrayBuffer;
+using WebKit::WebBindings;
+using WebKit::WebPluginContainer;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+const char kInvalidPluginValue[] = "Error: Plugin returned invalid value.";
+
+PP_Var NPObjectToPPVarImpl(PluginInstanceImpl* instance,
+ NPObject* object,
+ v8::Local<v8::Context> context) {
+ DCHECK(object);
+ if (context.IsEmpty())
+ return PP_MakeUndefined();
+ v8::Context::Scope context_scope(context);
+
+ WebArrayBuffer buffer;
+ // TODO(dmichael): Should I protect against duplicate Vars representing the
+ // same array buffer? It's probably not worth the trouble, since it will only
+ // affect in-process plugins.
+ if (WebBindings::getArrayBuffer(object, &buffer)) {
+ scoped_refptr<HostArrayBufferVar> buffer_var(
+ new HostArrayBufferVar(buffer));
+ return buffer_var->GetPPVar();
+ }
+ scoped_refptr<NPObjectVar> object_var(
+ HostGlobals::Get()->host_var_tracker()->NPObjectVarForNPObject(
+ instance->pp_instance(), object));
+ if (!object_var.get()) { // No object for this module yet, make a new one.
+ object_var = new NPObjectVar(instance->pp_instance(), object);
+ }
+ return object_var->GetPPVar();
+}
+
+
+} // namespace
+
+// Utilities -------------------------------------------------------------------
+
+bool PPVarToNPVariant(PP_Var var, NPVariant* result) {
+ switch (var.type) {
+ case PP_VARTYPE_UNDEFINED:
+ VOID_TO_NPVARIANT(*result);
+ break;
+ case PP_VARTYPE_NULL:
+ NULL_TO_NPVARIANT(*result);
+ break;
+ case PP_VARTYPE_BOOL:
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
+ break;
+ case PP_VARTYPE_INT32:
+ INT32_TO_NPVARIANT(var.value.as_int, *result);
+ break;
+ case PP_VARTYPE_DOUBLE:
+ DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
+ break;
+ case PP_VARTYPE_STRING: {
+ StringVar* string = StringVar::FromPPVar(var);
+ if (!string) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ const std::string& value = string->value();
+ char* c_string = static_cast<char*>(malloc(value.size()));
+ memcpy(c_string, value.data(), value.size());
+ STRINGN_TO_NPVARIANT(c_string, value.size(), *result);
+ break;
+ }
+ case PP_VARTYPE_OBJECT: {
+ scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
+ if (!object.get()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ OBJECT_TO_NPVARIANT(WebBindings::retainObject(object->np_object()),
+ *result);
+ break;
+ }
+ // The following types are not supported for use with PPB_Var_Deprecated,
+ // because PPB_Var_Deprecated is only for trusted plugins, and the trusted
+ // plugins we have don't need these types. We can add support in the future
+ // if it becomes necessary.
+ case PP_VARTYPE_ARRAY:
+ case PP_VARTYPE_DICTIONARY:
+ case PP_VARTYPE_ARRAY_BUFFER:
+ VOID_TO_NPVARIANT(*result);
+ break;
+ }
+ return true;
+}
+
+PP_Var NPVariantToPPVar(PluginInstanceImpl* instance,
+ const NPVariant* variant) {
+ switch (variant->type) {
+ case NPVariantType_Void:
+ return PP_MakeUndefined();
+ case NPVariantType_Null:
+ return PP_MakeNull();
+ case NPVariantType_Bool:
+ return PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant)));
+ case NPVariantType_Int32:
+ return PP_MakeInt32(NPVARIANT_TO_INT32(*variant));
+ case NPVariantType_Double:
+ return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant));
+ case NPVariantType_String:
+ return StringVar::StringToPPVar(
+ NPVARIANT_TO_STRING(*variant).UTF8Characters,
+ NPVARIANT_TO_STRING(*variant).UTF8Length);
+ case NPVariantType_Object:
+ return NPObjectToPPVar(instance, NPVARIANT_TO_OBJECT(*variant));
+ }
+ NOTREACHED();
+ return PP_MakeUndefined();
+}
+
+NPIdentifier PPVarToNPIdentifier(PP_Var var) {
+ switch (var.type) {
+ case PP_VARTYPE_STRING: {
+ StringVar* string = StringVar::FromPPVar(var);
+ if (!string)
+ return NULL;
+ return WebBindings::getStringIdentifier(string->value().c_str());
+ }
+ case PP_VARTYPE_INT32:
+ return WebBindings::getIntIdentifier(var.value.as_int);
+ default:
+ return NULL;
+ }
+}
+
+PP_Var NPIdentifierToPPVar(NPIdentifier id) {
+ const NPUTF8* string_value = NULL;
+ int32_t int_value = 0;
+ bool is_string = false;
+ WebBindings::extractIdentifierData(id, string_value, int_value, is_string);
+ if (is_string)
+ return StringVar::StringToPPVar(string_value);
+
+ return PP_MakeInt32(int_value);
+}
+
+PP_Var NPObjectToPPVar(PluginInstanceImpl* instance, NPObject* object) {
+ WebPluginContainer* container = instance->container();
+ // It's possible that container() is NULL if the plugin has been removed from
+ // the DOM (but the PluginInstance is not destroyed yet).
+ if (!container)
+ return PP_MakeUndefined();
+ v8::HandleScope scope(instance->GetIsolate());
+ v8::Local<v8::Context> context =
+ container->element().document().frame()->mainWorldScriptContext();
+ return NPObjectToPPVarImpl(instance, object, context);
+}
+
+PP_Var NPObjectToPPVarForTest(PluginInstanceImpl* instance, NPObject* object) {
+ v8::Isolate* test_isolate = v8::Isolate::New();
+ PP_Var result = PP_MakeUndefined();
+ {
+ v8::HandleScope scope(test_isolate);
+ v8::Isolate::Scope isolate_scope(test_isolate);
+ v8::Local<v8::Context> context = v8::Context::New(test_isolate);
+ result = NPObjectToPPVarImpl(instance, object, context);
+ }
+ test_isolate->Dispose();
+ return result;
+}
+
+// PPResultAndExceptionToNPResult ----------------------------------------------
+
+PPResultAndExceptionToNPResult::PPResultAndExceptionToNPResult(
+ NPObject* object_var,
+ NPVariant* np_result)
+ : object_var_(object_var),
+ np_result_(np_result),
+ exception_(PP_MakeUndefined()),
+ success_(false),
+ checked_exception_(false) {
+}
+
+PPResultAndExceptionToNPResult::~PPResultAndExceptionToNPResult() {
+ // The user should have called SetResult or CheckExceptionForNoResult
+ // before letting this class go out of scope, or the exception will have
+ // been lost.
+ DCHECK(checked_exception_);
+
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
+}
+
+// Call this with the return value of the PPAPI function. It will convert
+// the result to the NPVariant output parameter and pass any exception on to
+// the JS engine. It will update the success flag and return it.
+bool PPResultAndExceptionToNPResult::SetResult(PP_Var result) {
+ DCHECK(!checked_exception_); // Don't call more than once.
+ DCHECK(np_result_); // Should be expecting a result.
+
+ checked_exception_ = true;
+
+ if (has_exception()) {
+ ThrowException();
+ success_ = false;
+ } else if (!PPVarToNPVariant(result, np_result_)) {
+ WebBindings::setException(object_var_, kInvalidPluginValue);
+ success_ = false;
+ } else {
+ success_ = true;
+ }
+
+ // No matter what happened, we need to release the reference to the
+ // value passed in. On success, a reference to this value will be in
+ // the np_result_.
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(result);
+ return success_;
+}
+
+// Call this after calling a PPAPI function that could have set the
+// exception. It will pass the exception on to the JS engine and update
+// the success flag.
+//
+// The success flag will be returned.
+bool PPResultAndExceptionToNPResult::CheckExceptionForNoResult() {
+ DCHECK(!checked_exception_); // Don't call more than once.
+ DCHECK(!np_result_); // Can't have a result when doing this.
+
+ checked_exception_ = true;
+
+ if (has_exception()) {
+ ThrowException();
+ success_ = false;
+ return false;
+ }
+ success_ = true;
+ return true;
+}
+
+// Call this to ignore any exception. This prevents the DCHECK from failing
+// in the destructor.
+void PPResultAndExceptionToNPResult::IgnoreException() {
+ checked_exception_ = true;
+}
+
+// Throws the current exception to JS. The exception must be set.
+void PPResultAndExceptionToNPResult::ThrowException() {
+ StringVar* string = StringVar::FromPPVar(exception_);
+ if (string)
+ WebBindings::setException(object_var_, string->value().c_str());
+}
+
+// PPVarArrayFromNPVariantArray ------------------------------------------------
+
+PPVarArrayFromNPVariantArray::PPVarArrayFromNPVariantArray(
+ PluginInstanceImpl* instance,
+ size_t size,
+ const NPVariant* variants)
+ : size_(size) {
+ if (size_ > 0) {
+ array_.reset(new PP_Var[size_]);
+ for (size_t i = 0; i < size_; i++)
+ array_[i] = NPVariantToPPVar(instance, &variants[i]);
+ }
+}
+
+PPVarArrayFromNPVariantArray::~PPVarArrayFromNPVariantArray() {
+ ::ppapi::VarTracker* var_tracker = PpapiGlobals::Get()->GetVarTracker();
+ for (size_t i = 0; i < size_; i++)
+ var_tracker->ReleaseVar(array_[i]);
+}
+
+// PPVarFromNPObject -----------------------------------------------------------
+
+PPVarFromNPObject::PPVarFromNPObject(PluginInstanceImpl* instance,
+ NPObject* object)
+ : var_(NPObjectToPPVar(instance, object)) {
+}
+
+PPVarFromNPObject::~PPVarFromNPObject() {
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var_);
+}
+
+// NPObjectAccessorWithIdentifier ----------------------------------------------
+
+NPObjectAccessorWithIdentifier::NPObjectAccessorWithIdentifier(
+ NPObject* object,
+ NPIdentifier identifier,
+ bool allow_integer_identifier)
+ : object_(PluginObject::FromNPObject(object)),
+ identifier_(PP_MakeUndefined()) {
+ if (object_) {
+ identifier_ = NPIdentifierToPPVar(identifier);
+ if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier)
+ identifier_.type = PP_VARTYPE_UNDEFINED; // Mark it invalid.
+ }
+}
+
+NPObjectAccessorWithIdentifier::~NPObjectAccessorWithIdentifier() {
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(identifier_);
+}
+
+// TryCatch --------------------------------------------------------------------
+
+TryCatch::TryCatch(PP_Var* exception)
+ : has_exception_(exception && exception->type != PP_VARTYPE_UNDEFINED),
+ exception_(exception) {
+ WebBindings::pushExceptionHandler(&TryCatch::Catch, this);
+}
+
+TryCatch::~TryCatch() {
+ WebBindings::popExceptionHandler();
+}
+
+void TryCatch::SetException(const char* message) {
+ if (!has_exception()) {
+ has_exception_ = true;
+ if (exception_) {
+ *exception_ = ::ppapi::StringVar::StringToPPVar(message, strlen(message));
+ }
+ }
+}
+
+// static
+void TryCatch::Catch(void* self, const char* message) {
+ static_cast<TryCatch*>(self)->SetException(message);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/npapi_glue.h b/content/renderer/pepper/npapi_glue.h
new file mode 100644
index 0000000..5cc745b
--- /dev/null
+++ b/content/renderer/pepper/npapi_glue.h
@@ -0,0 +1,265 @@
+// 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_PEPPER_NPAPI_GLUE_H_
+#define CONTENT_RENDERER_PEPPER_NPAPI_GLUE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "ppapi/c/pp_module.h"
+#include "ppapi/c/pp_var.h"
+
+struct NPObject;
+typedef struct _NPVariant NPVariant;
+typedef void* NPIdentifier;
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstanceImpl;
+class PluginObject;
+
+// Utilities -------------------------------------------------------------------
+
+// Converts the given PP_Var to an NPVariant, returning true on success.
+// False means that the given variant is invalid. In this case, the result
+// NPVariant will be set to a void one.
+//
+// The contents of the PP_Var will be copied unless the PP_Var corresponds to
+// an object.
+bool PPVarToNPVariant(PP_Var var, NPVariant* result);
+
+// Returns a PP_Var that corresponds to the given NPVariant. The contents of
+// the NPVariant will be copied unless the NPVariant corresponds to an
+// object. This will handle all Variant types including POD, strings, and
+// objects.
+//
+// The returned PP_Var will have a refcount of 1, this passing ownership of
+// the reference to the caller. This is suitable for returning to a plugin.
+PP_Var NPVariantToPPVar(PluginInstanceImpl* instance, const NPVariant* variant);
+
+// Returns a NPIdentifier that corresponds to the given PP_Var. The contents
+// of the PP_Var will be copied. Returns 0 if the given PP_Var is not a a
+// string or integer type.
+NPIdentifier PPVarToNPIdentifier(PP_Var var);
+
+// Returns a PP_Var corresponding to the given identifier. In the case of
+// a string identifier, the returned string will have a reference count of 1.
+PP_Var NPIdentifierToPPVar(NPIdentifier id);
+
+// Helper function to create a PP_Var of type object that contains the given
+// NPObject for use byt he given module. Calling this function multiple times
+// given the same module + NPObject results in the same PP_Var, assuming that
+// there is still a PP_Var with a reference open to it from the previous
+// call.
+//
+// The instance is necessary because we can have different instances pointing to
+// the same NPObject, and we want to keep their refs separate.
+//
+// If no ObjectVar currently exists corresponding to the NPObject, one is
+// created associated with the given module.
+//
+// Note: this could easily be changed to take a PP_Instance instead if that
+// makes certain calls in the future easier. Currently all callers have a
+// PluginInstance so that's what we use here.
+CONTENT_EXPORT PP_Var NPObjectToPPVar(PluginInstanceImpl* instance,
+ NPObject* object);
+
+// This version creates a default v8::Context rather than using the one from
+// the container of |instance|. It is only for use in unit tests, where we don't
+// have a real container for |instance|.
+CONTENT_EXPORT PP_Var NPObjectToPPVarForTest(PluginInstanceImpl* instance,
+ NPObject* object);
+
+// PPResultAndExceptionToNPResult ----------------------------------------------
+
+// Convenience object for converting a PPAPI call that can throw an exception
+// and optionally return a value, back to the NPAPI layer which expects a
+// NPVariant as a result.
+//
+// Normal usage is that you will pass the result of exception() to the
+// PPAPI function as the exception output parameter. Then you will either
+// call SetResult with the result of the PPAPI call, or
+// CheckExceptionForNoResult if the PPAPI call doesn't return a PP_Var.
+//
+// Both SetResult and CheckExceptionForNoResult will throw an exception to
+// the JavaScript library if the plugin reported an exception. SetResult
+// will additionally convert the result to an NPVariant and write it to the
+// output parameter given in the constructor.
+class PPResultAndExceptionToNPResult {
+ public:
+ // The object_var parameter is the object to associate any exception with.
+ // It may not be NULL.
+ //
+ // The np_result parameter is the NPAPI result output parameter. This may be
+ // NULL if there is no NPVariant result (like for HasProperty). If this is
+ // specified, you must call SetResult() to set it. If it is not, you must
+ // call CheckExceptionForNoResult to do the exception checking with no result
+ // conversion.
+ PPResultAndExceptionToNPResult(NPObject* object_var, NPVariant* np_result);
+
+ ~PPResultAndExceptionToNPResult();
+
+ // Returns true if an exception has been set.
+ bool has_exception() const { return exception_.type != PP_VARTYPE_UNDEFINED; }
+
+ // Returns a pointer to the exception. You would pass this to the PPAPI
+ // function as the exception parameter. If it is set to non-void, this object
+ // will take ownership of destroying it.
+ PP_Var* exception() { return &exception_; }
+
+ // Returns true if everything succeeded with no exception. This is valid only
+ // after calling SetResult/CheckExceptionForNoResult.
+ bool success() const {
+ return success_;
+ }
+
+ // Call this with the return value of the PPAPI function. It will convert
+ // the result to the NPVariant output parameter and pass any exception on to
+ // the JS engine. It will update the success flag and return it.
+ bool SetResult(PP_Var result);
+
+ // Call this after calling a PPAPI function that could have set the
+ // exception. It will pass the exception on to the JS engine and update
+ // the success flag.
+ //
+ // The success flag will be returned.
+ bool CheckExceptionForNoResult();
+
+ // Call this to ignore any exception. This prevents the DCHECK from failing
+ // in the destructor.
+ void IgnoreException();
+
+ private:
+ // Throws the current exception to JS. The exception must be set.
+ void ThrowException();
+
+ NPObject* object_var_; // Non-owning ref (see constructor).
+ NPVariant* np_result_; // Output value, possibly NULL (see constructor).
+ PP_Var exception_; // Exception set by the PPAPI call. We own a ref to it.
+ bool success_; // See the success() function above.
+ bool checked_exception_; // SetResult/CheckExceptionForNoResult was called.
+
+ DISALLOW_COPY_AND_ASSIGN(PPResultAndExceptionToNPResult);
+};
+
+// PPVarArrayFromNPVariantArray ------------------------------------------------
+
+// Converts an array of NPVariants to an array of PP_Var, and scopes the
+// ownership of the PP_Var. This is used when converting argument lists from
+// WebKit to the plugin.
+class PPVarArrayFromNPVariantArray {
+ public:
+ PPVarArrayFromNPVariantArray(PluginInstanceImpl* instance,
+ size_t size,
+ const NPVariant* variants);
+ ~PPVarArrayFromNPVariantArray();
+
+ PP_Var* array() { return array_.get(); }
+
+ private:
+ size_t size_;
+ scoped_ptr<PP_Var[]> array_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray);
+};
+
+// PPVarFromNPObject -----------------------------------------------------------
+
+// Converts an NPObject tp PP_Var, and scopes the ownership of the PP_Var. This
+// is used when converting 'this' pointer from WebKit to the plugin.
+class PPVarFromNPObject {
+ public:
+ PPVarFromNPObject(PluginInstanceImpl* instance, NPObject* object);
+ ~PPVarFromNPObject();
+
+ PP_Var var() const { return var_; }
+
+ private:
+ const PP_Var var_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPVarFromNPObject);
+};
+
+// NPObjectAccessorWithIdentifier ----------------------------------------------
+
+// Helper class for our NPObject wrapper. This converts a call from WebKit
+// where it gives us an NPObject and an NPIdentifier to an easily-accessible
+// ObjectVar (corresponding to the NPObject) and PP_Var (corresponding to the
+// NPIdentifier).
+//
+// If the NPObject or identifier is invalid, we'll set is_valid() to false.
+// The caller should check is_valid() before doing anything with the class.
+//
+// JS can't have integer functions, so when dealing with these, we don't want
+// to allow integer identifiers. The calling code can decode if it wants to
+// allow integer identifiers (like for property access) or prohibit them
+// (like for method calling) by setting |allow_integer_identifier|. If this
+// is false and the identifier is an integer, we'll set is_valid() to false.
+//
+// Getting an integer identifier in this case should be impossible. V8
+// shouldn't be allowing this, and the Pepper Var calls from the plugin are
+// supposed to error out before calling into V8 (which will then call us back).
+// Aside from an egregious error, the only time this could happen is an NPAPI
+// plugin calling us.
+class NPObjectAccessorWithIdentifier {
+ public:
+ NPObjectAccessorWithIdentifier(NPObject* object,
+ NPIdentifier identifier,
+ bool allow_integer_identifier);
+ ~NPObjectAccessorWithIdentifier();
+
+ // Returns true if both the object and identifier are valid.
+ bool is_valid() const {
+ return object_ && identifier_.type != PP_VARTYPE_UNDEFINED;
+ }
+
+ PluginObject* object() { return object_; }
+ PP_Var identifier() const { return identifier_; }
+
+ private:
+ PluginObject* object_;
+ PP_Var identifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier);
+};
+
+// TryCatch --------------------------------------------------------------------
+
+// Instantiate this object on the stack to catch V8 exceptions and pass them
+// to an optional out parameter supplied by the plugin.
+class TryCatch {
+ public:
+ // The given exception may be NULL if the consumer isn't interested in
+ // catching exceptions. If non-NULL, the given var will be updated if any
+ // exception is thrown (so it must outlive the TryCatch object).
+ TryCatch(PP_Var* exception);
+ ~TryCatch();
+
+ // Returns true is an exception has been thrown. This can be true immediately
+ // after construction if the var passed to the constructor is non-void.
+ bool has_exception() const { return has_exception_; }
+
+ // Sets the given exception. If an exception has been previously set, this
+ // function will do nothing (normally you want only the first exception).
+ void SetException(const char* message);
+
+ private:
+ static void Catch(void* self, const char* message);
+
+ // True if an exception has been thrown. Since the exception itself may be
+ // NULL if the plugin isn't interested in getting the exception, this will
+ // always indicate if SetException has been called, regardless of whether
+ // the exception itself has been stored.
+ bool has_exception_;
+
+ // May be null if the consumer isn't interesting in catching exceptions.
+ PP_Var* exception_;
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_NPAPI_GLUE_H_
diff --git a/content/renderer/pepper/npobject_var.cc b/content/renderer/pepper/npobject_var.cc
new file mode 100644
index 0000000..0ab1755
--- /dev/null
+++ b/content/renderer/pepper/npobject_var.cc
@@ -0,0 +1,59 @@
+// 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/pepper/npobject_var.h"
+
+#include "base/logging.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/host_var_tracker.h"
+#include "ppapi/c/pp_var.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+
+using webkit::ppapi::HostGlobals;
+using WebKit::WebBindings;
+
+namespace ppapi {
+
+// NPObjectVar -----------------------------------------------------------------
+
+NPObjectVar::NPObjectVar(PP_Instance instance,
+ NPObject* np_object)
+ : pp_instance_(instance),
+ np_object_(np_object) {
+ WebBindings::retainObject(np_object_);
+ HostGlobals::Get()->host_var_tracker()->AddNPObjectVar(this);
+}
+
+NPObjectVar::~NPObjectVar() {
+ if (pp_instance())
+ HostGlobals::Get()->host_var_tracker()->RemoveNPObjectVar(this);
+ WebBindings::releaseObject(np_object_);
+}
+
+NPObjectVar* NPObjectVar::AsNPObjectVar() {
+ return this;
+}
+
+PP_VarType NPObjectVar::GetType() const {
+ return PP_VARTYPE_OBJECT;
+}
+
+void NPObjectVar::InstanceDeleted() {
+ DCHECK(pp_instance_);
+ HostGlobals::Get()->host_var_tracker()->RemoveNPObjectVar(this);
+ pp_instance_ = 0;
+}
+
+// static
+scoped_refptr<NPObjectVar> NPObjectVar::FromPPVar(PP_Var var) {
+ if (var.type != PP_VARTYPE_OBJECT)
+ return scoped_refptr<NPObjectVar>(NULL);
+ scoped_refptr<Var> var_object(
+ PpapiGlobals::Get()->GetVarTracker()->GetVar(var));
+ if (!var_object.get())
+ return scoped_refptr<NPObjectVar>();
+ return scoped_refptr<NPObjectVar>(var_object->AsNPObjectVar());
+}
+
+} // namespace ppapi
diff --git a/content/renderer/pepper/npobject_var.h b/content/renderer/pepper/npobject_var.h
new file mode 100644
index 0000000..6cafbb4
--- /dev/null
+++ b/content/renderer/pepper/npobject_var.h
@@ -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.
+
+#ifndef CONTENT_RENDERER_PEPPER_NPOBJECT_VAR_H_
+#define CONTENT_RENDERER_PEPPER_NPOBJECT_VAR_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/shared_impl/var.h"
+#include "content/common/content_export.h"
+
+typedef struct NPObject NPObject;
+typedef struct _NPVariant NPVariant;
+typedef void* NPIdentifier;
+
+namespace ppapi {
+
+// NPObjectVar -----------------------------------------------------------------
+
+// Represents a JavaScript object Var. By itself, this represents random
+// NPObjects that a given plugin (identified by the resource's module) wants to
+// reference. If two different modules reference the same NPObject (like the
+// "window" object), then there will be different NPObjectVar's (and hence
+// PP_Var IDs) for each module. This allows us to track all references owned by
+// a given module and free them when the plugin exits independently of other
+// plugins that may be running at the same time.
+class NPObjectVar : public Var {
+ public:
+ // You should always use FromNPObject to create an NPObjectVar. This function
+ // guarantees that we maintain the 1:1 mapping between NPObject and
+ // NPObjectVar.
+ NPObjectVar(PP_Instance instance, NPObject* np_object);
+
+ // Var overrides.
+ virtual NPObjectVar* AsNPObjectVar() OVERRIDE;
+ virtual PP_VarType GetType() const OVERRIDE;
+
+ // Returns the underlying NPObject corresponding to this NPObjectVar.
+ // Guaranteed non-NULL.
+ NPObject* np_object() const { return np_object_; }
+
+ // Notification that the instance was deleted, the internal reference will be
+ // zeroed out.
+ void InstanceDeleted();
+
+ // Possibly 0 if the object has outlived its instance.
+ PP_Instance pp_instance() const { return pp_instance_; }
+
+ // Helper function that converts a PP_Var to an object. This will return NULL
+ // if the PP_Var is not of object type or the object is invalid.
+ CONTENT_EXPORT static scoped_refptr<NPObjectVar> FromPPVar(PP_Var var);
+
+ private:
+ virtual ~NPObjectVar();
+
+ // Possibly 0 if the object has outlived its instance.
+ PP_Instance pp_instance_;
+
+ // Guaranteed non-NULL, this is the underlying object used by WebKit. We
+ // hold a reference to this object.
+ NPObject* np_object_;
+
+ DISALLOW_COPY_AND_ASSIGN(NPObjectVar);
+};
+
+} // namespace
+
+#endif // CONTENT_RENDERER_PEPPER_NPOBJECT_VAR_H_
diff --git a/content/renderer/pepper/pepper_audio_input_host.cc b/content/renderer/pepper/pepper_audio_input_host.cc
index 280d07e..6e74126 100644
--- a/content/renderer/pepper/pepper_audio_input_host.cc
+++ b/content/renderer/pepper/pepper_audio_input_host.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "build/build_config.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
#include "ipc/ipc_message.h"
#include "media/audio/shared_memory_util.h"
@@ -17,7 +18,6 @@
#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 "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_audio_input_host.h b/content/renderer/pepper/pepper_audio_input_host.h
index 97f9013..8316ec8 100644
--- a/content/renderer/pepper/pepper_audio_input_host.h
+++ b/content/renderer/pepper/pepper_audio_input_host.h
@@ -13,11 +13,11 @@
#include "base/memory/shared_memory.h"
#include "base/sync_socket.h"
#include "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "ipc/ipc_platform_file.h"
#include "ppapi/c/ppb_audio_config.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_broker_impl.cc b/content/renderer/pepper/pepper_broker_impl.cc
index 842c56f..aca9f32 100644
--- a/content/renderer/pepper/pepper_broker_impl.cc
+++ b/content/renderer/pepper/pepper_broker_impl.cc
@@ -8,12 +8,12 @@
#include "content/public/renderer/renderer_restrict_dispatch_group.h"
#include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
#include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppb_broker_impl.h"
#include "ipc/ipc_channel_handle.h"
#include "ppapi/proxy/broker_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/platform_file.h"
-#include "webkit/plugins/ppapi/plugin_module.h"
-#include "webkit/plugins/ppapi/ppb_broker_impl.h"
#if defined(OS_WIN)
#include <windows.h>
diff --git a/content/renderer/pepper/pepper_broker_impl.h b/content/renderer/pepper/pepper_broker_impl.h
index 26f5619..ce81d96 100644
--- a/content/renderer/pepper/pepper_broker_impl.h
+++ b/content/renderer/pepper/pepper_broker_impl.h
@@ -8,9 +8,9 @@
#include "base/memory/ref_counted.h"
#include "base/process/process.h"
#include "content/common/content_export.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppb_broker_impl.h"
#include "ppapi/proxy/proxy_channel.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
-#include "webkit/plugins/ppapi/ppb_broker_impl.h"
namespace IPC {
struct ChannelHandle;
diff --git a/content/renderer/pepper/pepper_device_enumeration_event_handler.h b/content/renderer/pepper/pepper_device_enumeration_event_handler.h
index b390c80..543bcdb 100644
--- a/content/renderer/pepper/pepper_device_enumeration_event_handler.h
+++ b/content/renderer/pepper/pepper_device_enumeration_event_handler.h
@@ -10,7 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "content/renderer/media/media_stream_dispatcher_eventhandler.h"
#include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
+#include "content/renderer/pepper/plugin_delegate.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_device_enumeration_host_helper.cc b/content/renderer/pepper/pepper_device_enumeration_host_helper.cc
index fca8ac5..136c946 100644
--- a/content/renderer/pepper/pepper_device_enumeration_host_helper.cc
+++ b/content/renderer/pepper/pepper_device_enumeration_host_helper.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "ipc/ipc_message.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -16,7 +17,6 @@
#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/ppb_device_ref_shared.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
using ppapi::host::HostMessageContext;
using webkit::ppapi::PluginDelegate;
diff --git a/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc b/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc
index c5616f5..f4e5714 100644
--- a/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc
+++ b/content/renderer/pepper/pepper_device_enumeration_host_helper_unittest.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "content/renderer/pepper/mock_plugin_delegate.h"
#include "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/host_message_context.h"
@@ -18,7 +19,6 @@
#include "ppapi/proxy/resource_message_test_sink.h"
#include "ppapi/shared_impl/ppapi_permissions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/plugins/ppapi/mock_plugin_delegate.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_file_chooser_host.cc b/content/renderer/pepper/pepper_file_chooser_host.cc
index 6f9b453..8eecb07 100644
--- a/content/renderer/pepper/pepper_file_chooser_host.cc
+++ b/content/renderer/pepper/pepper_file_chooser_host.cc
@@ -7,6 +7,7 @@
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/ppb_file_ref_impl.h"
#include "content/renderer/render_view_impl.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -18,7 +19,6 @@
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebFileChooserCompletion.h"
#include "third_party/WebKit/public/web/WebFileChooserParams.h"
-#include "webkit/plugins/ppapi/ppb_file_ref_impl.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_file_io_host.cc b/content/renderer/pepper/pepper_file_io_host.cc
index f5ef26e..96f0e82 100644
--- a/content/renderer/pepper/pepper_file_io_host.cc
+++ b/content/renderer/pepper/pepper_file_io_host.cc
@@ -11,6 +11,10 @@
#include "base/files/file_util_proxy.h"
#include "content/public/common/content_client.h"
#include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppb_file_ref_impl.h"
+#include "content/renderer/pepper/quota_file_io.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/ppapi_host.h"
@@ -19,10 +23,6 @@
#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/thunk/enter.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
-#include "webkit/plugins/ppapi/host_globals.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
-#include "webkit/plugins/ppapi/ppb_file_ref_impl.h"
-#include "webkit/plugins/ppapi/quota_file_io.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_file_io_host.h b/content/renderer/pepper/pepper_file_io_host.h
index 62e4356..89e70f7 100644
--- a/content/renderer/pepper/pepper_file_io_host.h
+++ b/content/renderer/pepper/pepper_file_io_host.h
@@ -11,11 +11,11 @@
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
#include "ppapi/shared_impl/file_io_state_manager.h"
#include "ppapi/thunk/ppb_file_ref_api.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
using ppapi::host::ReplyMessageContext;
using webkit::ppapi::PluginDelegate;
diff --git a/content/renderer/pepper/pepper_file_system_host.cc b/content/renderer/pepper/pepper_file_system_host.cc
index d710a7a..3e60dfe 100644
--- a/content/renderer/pepper/pepper_file_system_host.cc
+++ b/content/renderer/pepper/pepper_file_system_host.cc
@@ -10,6 +10,7 @@
#include "content/child/fileapi/file_system_dispatcher.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/ppapi_host.h"
@@ -21,7 +22,6 @@
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "webkit/common/fileapi/file_system_util.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_graphics_2d_host.cc b/content/renderer/pepper/pepper_graphics_2d_host.cc
index 528daca..ca4d524 100644
--- a/content/renderer/pepper/pepper_graphics_2d_host.cc
+++ b/content/renderer/pepper/pepper_graphics_2d_host.cc
@@ -9,6 +9,11 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
#include "ppapi/c/pp_bool.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_rect.h"
@@ -28,11 +33,6 @@
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
#include "ui/gfx/size_conversions.h"
#include "ui/gfx/skia_util.h"
-#include "webkit/plugins/ppapi/common.h"
-#include "webkit/plugins/ppapi/gfx_conversion.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
-#include "webkit/plugins/ppapi/ppb_image_data_impl.h"
-#include "webkit/plugins/ppapi/resource_helper.h"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
diff --git a/content/renderer/pepper/pepper_graphics_2d_host.h b/content/renderer/pepper/pepper_graphics_2d_host.h
index 9ce1fda..a582f2e 100644
--- a/content/renderer/pepper/pepper_graphics_2d_host.h
+++ b/content/renderer/pepper/pepper_graphics_2d_host.h
@@ -11,11 +11,11 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "ppapi/c/ppb_graphics_2d.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
#include "third_party/WebKit/public/platform/WebCanvas.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
namespace gfx {
class Point;
diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.cc b/content/renderer/pepper/pepper_in_process_resource_creation.cc
index 7cd2c70..f9713c4 100644
--- a/content/renderer/pepper/pepper_in_process_resource_creation.cc
+++ b/content/renderer/pepper/pepper_in_process_resource_creation.cc
@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "content/renderer/pepper/pepper_in_process_router.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
#include "content/renderer/render_view_impl.h"
#include "ipc/ipc_message.h"
@@ -30,7 +31,6 @@
#include "ppapi/shared_impl/ppapi_permissions.h"
#include "ppapi/shared_impl/resource_tracker.h"
#include "ppapi/shared_impl/var.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
// Note that the code in the creation functions in this file should generally
// be the same as that in ppapi/proxy/resource_creation_proxy.cc. See
diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.h b/content/renderer/pepper/pepper_in_process_resource_creation.h
index 2f36aa9..72a5943 100644
--- a/content/renderer/pepper/pepper_in_process_resource_creation.h
+++ b/content/renderer/pepper/pepper_in_process_resource_creation.h
@@ -7,8 +7,8 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/resource_creation_impl.h"
#include "ppapi/proxy/connection.h"
-#include "webkit/plugins/ppapi/resource_creation_impl.h"
namespace content {
@@ -20,7 +20,7 @@ class RendererPpapiHostImpl;
// (See pepper_in_process_router.h for more information.)
//
// This is a bit confusing. The "old-style" resources live in
-// webkit/plugins/ppapi and are created by the ResourceCreationImpl in that
+// content/renderer/pepper and are created by the ResourceCreationImpl in that
// directory. The "new-style" IPC-only resources are in ppapi/proxy and are
// created by the RessourceCreationProxy in that directory.
//
diff --git a/content/renderer/pepper/pepper_platform_audio_input_impl.h b/content/renderer/pepper/pepper_platform_audio_input_impl.h
index 975d921..c5b3fb0 100644
--- a/content/renderer/pepper/pepper_platform_audio_input_impl.h
+++ b/content/renderer/pepper/pepper_platform_audio_input_impl.h
@@ -12,9 +12,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "media/audio/audio_input_ipc.h"
#include "media/audio/audio_parameters.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
class GURL;
diff --git a/content/renderer/pepper/pepper_platform_audio_output_impl.h b/content/renderer/pepper/pepper_platform_audio_output_impl.h
index 4382bf2..d13aa62 100644
--- a/content/renderer/pepper/pepper_platform_audio_output_impl.h
+++ b/content/renderer/pepper/pepper_platform_audio_output_impl.h
@@ -8,8 +8,8 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "media/audio/audio_output_ipc.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
namespace media {
class AudioParameters;
diff --git a/content/renderer/pepper/pepper_platform_context_3d_impl.h b/content/renderer/pepper/pepper_platform_context_3d_impl.h
index 88496c2..c975453 100644
--- a/content/renderer/pepper/pepper_platform_context_3d_impl.h
+++ b/content/renderer/pepper/pepper_platform_context_3d_impl.h
@@ -10,8 +10,8 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "gpu/command_buffer/common/mailbox.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
#ifdef ENABLE_GPU
diff --git a/content/renderer/pepper/pepper_platform_image_2d_impl.h b/content/renderer/pepper/pepper_platform_image_2d_impl.h
index 099a428..5ad75e1 100644
--- a/content/renderer/pepper/pepper_platform_image_2d_impl.h
+++ b/content/renderer/pepper/pepper_platform_image_2d_impl.h
@@ -6,7 +6,7 @@
#define CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_IMAGE_2D_IMPL_H_
#include "base/basictypes.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
+#include "content/renderer/pepper/plugin_delegate.h"
namespace content {
diff --git a/content/renderer/pepper/pepper_platform_video_capture_impl.h b/content/renderer/pepper/pepper_platform_video_capture_impl.h
index 4e9c13b..58101e53 100644
--- a/content/renderer/pepper/pepper_platform_video_capture_impl.h
+++ b/content/renderer/pepper/pepper_platform_video_capture_impl.h
@@ -11,9 +11,9 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "media/video/capture/video_capture.h"
#include "media/video/capture/video_capture_types.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
class GURL;
diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc
index 69dee4e..7beb399 100644
--- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc
@@ -57,7 +57,13 @@
#include "content/renderer/pepper/pepper_platform_video_capture_impl.h"
#include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h"
#include "content/renderer/pepper/pepper_url_loader_host.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppapi_webplugin_impl.h"
+#include "content/renderer/pepper/ppb_tcp_server_socket_private_impl.h"
+#include "content/renderer/pepper/ppb_tcp_socket_private_impl.h"
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
#include "content/renderer/pepper/url_response_info_util.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/render_view_impl.h"
@@ -95,12 +101,6 @@
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/gfx/size.h"
#include "url/gurl.h"
-#include "webkit/plugins/ppapi/plugin_module.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
-#include "webkit/plugins/ppapi/ppapi_webplugin_impl.h"
-#include "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h"
-#include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h"
-#include "webkit/plugins/ppapi/resource_helper.h"
using WebKit::WebView;
using WebKit::WebFrame;
@@ -413,7 +413,6 @@ PepperPluginDelegateImpl::CreatePepperPluginModule(
// module's destructor will remove itself.
module = new webkit::ppapi::PluginModule(
info->name, path,
- PepperPluginRegistry::GetInstance(),
permissions);
PepperPluginRegistry::GetInstance()->AddLiveModule(path, module.get());
diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.h b/content/renderer/pepper/pepper_plugin_delegate_impl.h
index 2e311d5..5a0f977 100644
--- a/content/renderer/pepper/pepper_plugin_delegate_impl.h
+++ b/content/renderer/pepper/pepper_plugin_delegate_impl.h
@@ -19,12 +19,12 @@
#include "content/public/renderer/render_view_observer.h"
#include "content/renderer/mouse_lock_dispatcher.h"
#include "content/renderer/pepper/pepper_browser_connection.h"
+#include "content/renderer/pepper/plugin_delegate.h"
#include "content/renderer/render_view_pepper_helper.h"
#include "ppapi/c/pp_file_info.h"
#include "ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h"
#include "ppapi/shared_impl/private/tcp_socket_private_impl.h"
#include "ui/base/ime/text_input_type.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
namespace base {
class FilePath;
diff --git a/content/renderer/pepper/pepper_url_loader_host.cc b/content/renderer/pepper/pepper_url_loader_host.cc
index 6863606..3087ebc 100644
--- a/content/renderer/pepper/pepper_url_loader_host.cc
+++ b/content/renderer/pepper/pepper_url_loader_host.cc
@@ -4,7 +4,9 @@
#include "content/renderer/pepper/pepper_url_loader_host.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
+#include "content/renderer/pepper/url_request_info_util.h"
#include "content/renderer/pepper/url_response_info_util.h"
#include "net/base/net_errors.h"
#include "ppapi/c/pp_errors.h"
@@ -24,8 +26,6 @@
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
-#include "webkit/plugins/ppapi/url_request_info_util.h"
using WebKit::WebFrame;
using WebKit::WebString;
diff --git a/content/renderer/pepper/pepper_url_request_unittest.cc b/content/renderer/pepper/pepper_url_request_unittest.cc
index a242cee..08cae5a 100644
--- a/content/renderer/pepper/pepper_url_request_unittest.cc
+++ b/content/renderer/pepper/pepper_url_request_unittest.cc
@@ -4,6 +4,7 @@
#include "base/compiler_specific.h"
#include "content/public/test/render_view_test.h"
+#include "content/renderer/pepper/url_request_info_util.h"
#include "ppapi/proxy/connection.h"
#include "ppapi/proxy/url_request_info_resource.h"
#include "ppapi/shared_impl/test_globals.h"
@@ -16,7 +17,6 @@
#include "third_party/WebKit/public/web/WebView.h"
#include "webkit/common/user_agent/user_agent.h"
#include "webkit/common/user_agent/user_agent_util.h"
-#include "webkit/plugins/ppapi/url_request_info_util.h"
// This test is a end-to-end test from the resource to the WebKit request
// object. The actual resource implementation is so simple, it makes sense to
@@ -51,9 +51,6 @@ class TestWebFrameClient : public WebFrameClient {
using ppapi::proxy::URLRequestInfoResource;
using ppapi::URLRequestInfoData;
-// TODO(brettw) move to content namespace when url_request_info_util.h is moved
-// to this directory. This file used to be in webkit/plugins/ppapi and had to
-// be moved in advance of the rest of the files to make things compile.
namespace webkit {
namespace ppapi {
diff --git a/content/renderer/pepper/pepper_video_capture_host.cc b/content/renderer/pepper/pepper_video_capture_host.cc
index 6c6b933..cef1e88 100644
--- a/content/renderer/pepper/pepper_video_capture_host.cc
+++ b/content/renderer/pepper/pepper_video_capture_host.cc
@@ -4,6 +4,8 @@
#include "content/renderer/pepper/pepper_video_capture_host.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/ppapi_host.h"
@@ -15,8 +17,6 @@
#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 "webkit/plugins/ppapi/host_globals.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
using ppapi::HostResource;
using ppapi::TrackedCallback;
diff --git a/content/renderer/pepper/pepper_video_capture_host.h b/content/renderer/pepper/pepper_video_capture_host.h
index 9d0dd4e..9fdc299 100644
--- a/content/renderer/pepper/pepper_video_capture_host.h
+++ b/content/renderer/pepper/pepper_video_capture_host.h
@@ -9,13 +9,13 @@
#include "base/memory/ref_counted.h"
#include "content/public/renderer/renderer_ppapi_host.h"
#include "content/renderer/pepper/pepper_device_enumeration_host_helper.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppb_buffer_impl.h"
#include "media/video/capture/video_capture.h"
#include "media/video/capture/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"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
-#include "webkit/plugins/ppapi/ppb_buffer_impl.h"
namespace content {
class RendererPpapiHostImpl;
diff --git a/content/renderer/pepper/pepper_video_destination_host.cc b/content/renderer/pepper/pepper_video_destination_host.cc
index 67234d5..2ab0657 100644
--- a/content/renderer/pepper/pepper_video_destination_host.cc
+++ b/content/renderer/pepper/pepper_video_destination_host.cc
@@ -6,6 +6,7 @@
#include "base/time/time.h"
#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/host_message_context.h"
@@ -13,7 +14,6 @@
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_image_data_api.h"
-#include "webkit/plugins/ppapi/ppb_image_data_impl.h"
using ppapi::host::HostMessageContext;
using ppapi::host::ReplyMessageContext;
diff --git a/content/renderer/pepper/pepper_video_source_host.cc b/content/renderer/pepper/pepper_video_source_host.cc
index 8183113..165c5c0 100644
--- a/content/renderer/pepper/pepper_video_source_host.cc
+++ b/content/renderer/pepper/pepper_video_source_host.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/safe_numerics.h"
#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -19,7 +20,6 @@
#include "third_party/libjingle/source/talk/media/base/videocommon.h"
#include "third_party/libjingle/source/talk/media/base/videoframe.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/plugins/ppapi/ppb_image_data_impl.h"
using ppapi::host::HostMessageContext;
using ppapi::host::ReplyMessageContext;
diff --git a/content/renderer/pepper/plugin_delegate.h b/content/renderer/pepper/plugin_delegate.h
new file mode 100644
index 0000000..e5f2118
--- /dev/null
+++ b/content/renderer/pepper/plugin_delegate.h
@@ -0,0 +1,692 @@
+// 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_PLUGIN_DELEGATE_H_
+#define CONTENT_RENDERER_PEPPER_PLUGIN_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/platform_file.h"
+#include "base/process.h"
+#include "base/sync_socket.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_platform_file.h"
+#include "media/video/capture/video_capture.h"
+#include "media/video/video_decode_accelerator.h"
+#include "ppapi/c/dev/pp_video_dev.h"
+#include "ppapi/c/dev/ppb_device_ref_dev.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_file_info.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/c/ppb_tcp_socket.h"
+#include "ppapi/c/private/ppb_flash.h"
+#include "ppapi/c/private/ppb_tcp_socket_private.h"
+#include "ppapi/c/private/ppb_udp_socket_private.h"
+#include "ppapi/shared_impl/dir_contents.h"
+#include "ui/gfx/size.h"
+#include "url/gurl.h"
+#include "webkit/common/fileapi/file_system_types.h"
+#include "webkit/common/quota/quota_types.h"
+
+class GURL;
+class SkBitmap;
+class SkCanvas;
+class TransportDIB;
+struct PP_NetAddress_Private;
+
+namespace IPC {
+struct ChannelHandle;
+}
+
+namespace WebKit {
+class WebGraphicsContext3D;
+}
+
+namespace base {
+class MessageLoopProxy;
+class Time;
+}
+
+namespace content {
+class RendererPpapiHost;
+}
+
+namespace fileapi {
+struct DirectoryEntry;
+}
+
+namespace gfx {
+class Point;
+}
+
+namespace gpu {
+class CommandBuffer;
+struct Mailbox;
+}
+
+namespace ppapi {
+class PepperFilePath;
+class PpapiPermissions;
+class PPB_X509Certificate_Fields;
+class SocketOptionData;
+struct DeviceRefData;
+struct HostPortPair;
+struct Preferences;
+
+namespace thunk {
+class ResourceCreationAPI;
+}
+
+} // namespace ppapi
+
+namespace WebKit {
+typedef SkCanvas WebCanvas;
+class WebGamepads;
+class WebPlugin;
+struct WebCompositionUnderline;
+struct WebCursorInfo;
+struct WebURLError;
+class WebURLLoaderClient;
+class WebURLResponse;
+}
+
+namespace webkit_glue {
+class P2PTransport;
+class NetworkListObserver;
+} // namespace webkit_glue
+
+namespace webkit {
+
+namespace ppapi {
+
+class FileIO;
+class FullscreenContainer;
+class PluginInstanceImpl;
+class PluginModule;
+class PPB_Broker_Impl;
+class PPB_Flash_Menu_Impl;
+class PPB_ImageData_Impl;
+class PPB_TCPSocket_Private_Impl;
+
+// Virtual interface that the browser implements to implement features for
+// PPAPI plugins.
+class PluginDelegate {
+ public:
+ // This class is implemented by the PluginDelegate implementation and is
+ // designed to manage the lifetime and communication with the proxy's
+ // HostDispatcher for out-of-process PPAPI plugins.
+ //
+ // The point of this is to avoid having a relationship from the PPAPI plugin
+ // implementation to the ppapi proxy code. Otherwise, things like the IPC
+ // system will be dependencies of the webkit directory, which we don't want.
+ //
+ // The PluginModule will scope the lifetime of this object to its own
+ // lifetime, so the implementation can use this to manage the HostDispatcher
+ // lifetime without introducing the dependency.
+ class OutOfProcessProxy {
+ public:
+ virtual ~OutOfProcessProxy() {}
+
+ // Implements GetInterface for the proxied plugin.
+ virtual const void* GetProxiedInterface(const char* name) = 0;
+
+ // Notification to the out-of-process layer that the given plugin instance
+ // has been created. This will happen before the normal PPB_Instance method
+ // calls so the out-of-process code can set up the tracking information for
+ // the new instance.
+ virtual void AddInstance(PP_Instance instance) = 0;
+
+ // Like AddInstance but removes the given instance. This is called after
+ // regular instance shutdown so the out-of-process code can clean up its
+ // tracking information.
+ virtual void RemoveInstance(PP_Instance instance) = 0;
+
+ virtual base::ProcessId GetPeerProcessId() = 0;
+ virtual int GetPluginChildId() = 0;
+ };
+
+ // Represents an image. This is to allow the browser layer to supply a correct
+ // image representation. In Chrome, this will be a TransportDIB.
+ class PlatformImage2D {
+ public:
+ virtual ~PlatformImage2D() {}
+
+ // Caller will own the returned pointer, returns NULL on failure.
+ virtual SkCanvas* Map() = 0;
+
+ // Returns the platform-specific shared memory handle of the data backing
+ // this image. This is used by PPAPI proxying to send the image to the
+ // out-of-process plugin. On success, the size in bytes will be placed into
+ // |*bytes_count|. Returns 0 on failure.
+ virtual intptr_t GetSharedMemoryHandle(uint32* byte_count) const = 0;
+
+ virtual TransportDIB* GetTransportDIB() const = 0;
+ };
+
+ class CONTENT_EXPORT PlatformGraphics2D {
+ public:
+ virtual ~PlatformGraphics2D() {}
+
+ virtual bool ReadImageData(PP_Resource image, const PP_Point* top_left) = 0;
+
+ // Assciates this device with the given plugin instance. You can pass NULL
+ // to clear the existing device. Returns true on success. In this case, a
+ // repaint of the page will also be scheduled. Failure means that the device
+ // is already bound to a different instance, and nothing will happen.
+ virtual bool BindToInstance(PluginInstanceImpl* new_instance) = 0;
+
+ // Paints the current backing store to the web page.
+ virtual void Paint(WebKit::WebCanvas* canvas,
+ const gfx::Rect& plugin_rect,
+ const gfx::Rect& paint_rect) = 0;
+
+ // Notifications about the view's progress painting. See PluginInstance.
+ // These messages are used to send Flush callbacks to the plugin.
+ virtual void ViewWillInitiatePaint() = 0;
+ virtual void ViewInitiatedPaint() = 0;
+ virtual void ViewFlushedPaint() = 0;
+
+ virtual bool IsAlwaysOpaque() const = 0;
+ virtual void SetScale(float scale) = 0;
+ virtual float GetScale() const = 0;
+ virtual PPB_ImageData_Impl* ImageData() = 0;
+ };
+
+ class PlatformContext3D {
+ public:
+ virtual ~PlatformContext3D() {}
+
+ // Initialize the context.
+ virtual bool Init(const int32* attrib_list,
+ PlatformContext3D* share_context) = 0;
+
+ // Retrieves the mailbox name for the front buffer backing the context.
+ virtual void GetBackingMailbox(::gpu::Mailbox* mailbox) = 0;
+
+ // Returns true if the backing texture is always opaque.
+ virtual bool IsOpaque() = 0;
+
+ // This call will return the address of the command buffer for this context
+ // that is constructed in Initialize() and is valid until this context is
+ // destroyed.
+ virtual ::gpu::CommandBuffer* GetCommandBuffer() = 0;
+
+ // If the command buffer is routed in the GPU channel, return the route id.
+ // Otherwise return 0.
+ virtual int GetCommandBufferRouteId() = 0;
+
+ // Set an optional callback that will be invoked when the context is lost
+ // (e.g. gpu process crash). Takes ownership of the callback.
+ virtual void SetContextLostCallback(
+ const base::Callback<void()>& callback) = 0;
+
+ // Set an optional callback that will be invoked when the GPU process
+ // sends a console message.
+ typedef base::Callback<void(const std::string&, int)>
+ ConsoleMessageCallback;
+ virtual void SetOnConsoleMessageCallback(
+ const ConsoleMessageCallback& callback) = 0;
+
+ // Run the callback once the channel has been flushed.
+ virtual bool Echo(const base::Callback<void()>& callback) = 0;
+ };
+
+ // The base class of clients used by |PlatformAudioOutput| and
+ // |PlatformAudioInput|.
+ class PlatformAudioClientBase {
+ protected:
+ virtual ~PlatformAudioClientBase() {}
+
+ public:
+ // Called when the stream is created.
+ virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle,
+ size_t shared_memory_size,
+ base::SyncSocket::Handle socket) = 0;
+ };
+
+ class PlatformAudioOutputClient : public PlatformAudioClientBase {
+ protected:
+ virtual ~PlatformAudioOutputClient() {}
+ };
+
+ class PlatformAudioOutput {
+ public:
+ // Starts the playback. Returns false on error or if called before the
+ // stream is created or after the stream is closed.
+ virtual bool StartPlayback() = 0;
+
+ // Stops the playback. Returns false on error or if called before the stream
+ // is created or after the stream is closed.
+ virtual bool StopPlayback() = 0;
+
+ // Closes the stream. Make sure to call this before the object is
+ // destructed.
+ virtual void ShutDown() = 0;
+
+ protected:
+ virtual ~PlatformAudioOutput() {}
+ };
+
+ class PlatformAudioInputClient : public PlatformAudioClientBase {
+ public:
+ virtual void StreamCreationFailed() = 0;
+
+ protected:
+ virtual ~PlatformAudioInputClient() {}
+ };
+
+ class PlatformAudioInput {
+ public:
+ virtual void StartCapture() = 0;
+ virtual void StopCapture() = 0;
+
+ // Closes the stream. Make sure to call this before the object is
+ // destructed.
+ virtual void ShutDown() = 0;
+
+ protected:
+ virtual ~PlatformAudioInput() {}
+ };
+
+ // Interface for PlatformVideoDecoder is directly inherited from general media
+ // VideoDecodeAccelerator interface.
+ class PlatformVideoDecoder : public media::VideoDecodeAccelerator {
+ public:
+ virtual ~PlatformVideoDecoder() {}
+ };
+
+ class PlatformVideoCaptureEventHandler
+ : public media::VideoCapture::EventHandler {
+ public:
+ virtual ~PlatformVideoCaptureEventHandler() {}
+
+ virtual void OnInitialized(media::VideoCapture* capture,
+ bool succeeded) = 0;
+ };
+
+ class PlatformVideoCapture : public media::VideoCapture,
+ public base::RefCounted<PlatformVideoCapture> {
+ public:
+ // Detaches the event handler and stops sending notifications to it.
+ virtual void DetachEventHandler() = 0;
+
+ protected:
+ virtual ~PlatformVideoCapture() {}
+
+ private:
+ friend class base::RefCounted<PlatformVideoCapture>;
+ };
+
+ // Provides access to the ppapi broker.
+ class Broker {
+ public:
+ // Decrements the references to the broker.
+ // When there are no more references, this renderer's dispatcher is
+ // destroyed, allowing the broker to shutdown if appropriate.
+ // Callers should not reference this object after calling Disconnect().
+ virtual void Disconnect(webkit::ppapi::PPB_Broker_Impl* client) = 0;
+
+ protected:
+ virtual ~Broker() {}
+ };
+
+ // Notification that the given plugin is focused or unfocused.
+ virtual void PluginFocusChanged(webkit::ppapi::PluginInstanceImpl* instance,
+ bool focused) = 0;
+ // Notification that the text input status of the given plugin is changed.
+ virtual void PluginTextInputTypeChanged(
+ webkit::ppapi::PluginInstanceImpl* instance) = 0;
+ // Notification that the caret position in the given plugin is changed.
+ virtual void PluginCaretPositionChanged(
+ webkit::ppapi::PluginInstanceImpl* instance) = 0;
+ // Notification that the plugin requested to cancel the current composition.
+ virtual void PluginRequestedCancelComposition(
+ webkit::ppapi::PluginInstanceImpl* instance) = 0;
+ // Notification that the text selection in the given plugin is changed.
+ virtual void PluginSelectionChanged(
+ webkit::ppapi::PluginInstanceImpl* instance) = 0;
+ // Requests simulating IME events for testing purpose.
+ virtual void SimulateImeSetComposition(
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end) = 0;
+ virtual void SimulateImeConfirmComposition(const base::string16& text) = 0;
+
+ // Notification that the given plugin has crashed. When a plugin crashes, all
+ // instances associated with that plugin will notify that they've crashed via
+ // this function.
+ virtual void PluginCrashed(PluginInstanceImpl* instance) = 0;
+
+ // Indicates that the given instance has been created.
+ virtual void InstanceCreated(PluginInstanceImpl* instance) = 0;
+
+ // Indicates that the given instance is being destroyed. This is called from
+ // the destructor, so it's important that the instance is not dereferenced
+ // from this call.
+ virtual void InstanceDeleted(PluginInstanceImpl* instance) = 0;
+
+ // Creates the resource creation API for the given instance.
+ virtual scoped_ptr< ::ppapi::thunk::ResourceCreationAPI>
+ CreateResourceCreationAPI(PluginInstanceImpl* instance) = 0;
+
+ // Returns a pointer (ownership not transferred) to the bitmap to paint the
+ // sad plugin screen with. Returns NULL on failure.
+ virtual SkBitmap* GetSadPluginBitmap() = 0;
+
+ // Creates a replacement plug-in that is shown when the plug-in at |file_path|
+ // couldn't be loaded.
+ virtual WebKit::WebPlugin* CreatePluginReplacement(
+ const base::FilePath& file_path) = 0;
+
+ // The caller will own the pointer returned from this.
+ virtual PlatformImage2D* CreateImage2D(int width, int height) = 0;
+
+ // Returns the internal PlatformGraphics2D implementation.
+ virtual PlatformGraphics2D* GetGraphics2D(PluginInstanceImpl* instance,
+ PP_Resource graphics_2d) = 0;
+
+ // The caller will own the pointer returned from this.
+ virtual PlatformContext3D* CreateContext3D() = 0;
+
+ // If |device_id| is empty, the default video capture device will be used. The
+ // user can start using the returned object to capture video right away.
+ // Otherwise, the specified device will be used. The user needs to wait till
+ // |handler| gets an OnInitialized() notification to start using the returned
+ // object.
+ virtual PlatformVideoCapture* CreateVideoCapture(
+ const std::string& device_id,
+ const GURL& document_url,
+ PlatformVideoCaptureEventHandler* handler) = 0;
+
+ // The caller will own the pointer returned from this.
+ virtual PlatformVideoDecoder* CreateVideoDecoder(
+ media::VideoDecodeAccelerator::Client* client,
+ int32 command_buffer_route_id) = 0;
+
+ // Get audio hardware output sample rate.
+ virtual uint32_t GetAudioHardwareOutputSampleRate() = 0;
+
+ // Get audio hardware output buffer size.
+ virtual uint32_t GetAudioHardwareOutputBufferSize() = 0;
+
+ // The caller is responsible for calling Shutdown() on the returned pointer
+ // to clean up the corresponding resources allocated during this call.
+ virtual PlatformAudioOutput* CreateAudioOutput(
+ uint32_t sample_rate,
+ uint32_t sample_count,
+ PlatformAudioOutputClient* client) = 0;
+
+ // If |device_id| is empty, the default audio input device will be used.
+ // The caller is responsible for calling Shutdown() on the returned pointer
+ // to clean up the corresponding resources allocated during this call.
+ virtual PlatformAudioInput* CreateAudioInput(
+ const std::string& device_id,
+ const GURL& document_url,
+ uint32_t sample_rate,
+ uint32_t sample_count,
+ PlatformAudioInputClient* client) = 0;
+
+ // A pointer is returned immediately, but it is not ready to be used until
+ // BrokerConnected has been called.
+ // The caller is responsible for calling Disconnect() on the returned pointer
+ // to clean up the corresponding resources allocated during this call.
+ virtual Broker* ConnectToBroker(webkit::ppapi::PPB_Broker_Impl* client) = 0;
+
+ // Notifies that the number of find results has changed.
+ virtual void NumberOfFindResultsChanged(int identifier,
+ int total,
+ bool final_result) = 0;
+
+ // Notifies that the index of the currently selected item has been updated.
+ virtual void SelectedFindResultChanged(int identifier, int index) = 0;
+
+ // Sends an async IPC to open a local file.
+ typedef base::Callback<void (base::PlatformFileError, base::PassPlatformFile)>
+ AsyncOpenFileCallback;
+ virtual bool AsyncOpenFile(const base::FilePath& path,
+ int flags,
+ const AsyncOpenFileCallback& callback) = 0;
+
+ // These functions expose some of PepperFileSystemHost methods for
+ // PPB_FileRef_Impl (which is in webkit) to access. Once we migrate FileRef
+ // to the new design in content/, we won't need this delegation.
+ // TODO(victorhsieh): remove these delegation.
+ virtual bool IsFileSystemOpened(PP_Instance instance,
+ PP_Resource resource) const = 0;
+ virtual PP_FileSystemType GetFileSystemType(PP_Instance instance,
+ PP_Resource resource) const = 0;
+ virtual GURL GetFileSystemRootUrl(PP_Instance instance,
+ PP_Resource resource) const = 0;
+
+ // Sends an async IPC to open a file through filesystem API.
+ // When a file is successfully opened, |callback| is invoked with
+ // PLATFORM_FILE_OK, the opened file handle, and a callback function for
+ // notifying that the file is closed. When the users of this function
+ // finished using the file, they must close the file handle and then must call
+ // the supplied callback function.
+ typedef base::Callback<void (base::PlatformFileError)>
+ NotifyCloseFileCallback;
+ typedef base::Callback<
+ void (base::PlatformFileError error,
+ base::PassPlatformFile file,
+ quota::QuotaLimitType quota_policy,
+ const NotifyCloseFileCallback& close_file_callback)>
+ AsyncOpenFileSystemURLCallback;
+ virtual void AsyncOpenFileSystemURL(
+ const GURL& path,
+ int flags,
+ const AsyncOpenFileSystemURLCallback& callback) = 0;
+
+ // Callback typedefs for FileSystem related methods.
+ typedef base::Callback<void (base::PlatformFileError)> StatusCallback;
+ typedef base::Callback<void(
+ const std::vector<fileapi::DirectoryEntry>& entries,
+ bool has_more)> ReadDirectoryCallback;
+ typedef base::Callback<void(
+ const base::PlatformFileInfo& file_info)> MetadataCallback;
+
+ virtual void MakeDirectory(
+ const GURL& path,
+ bool recursive,
+ const StatusCallback& callback) = 0;
+ virtual void Query(const GURL& path,
+ const MetadataCallback& success_callback,
+ const StatusCallback& error_callback) = 0;
+ virtual void ReadDirectoryEntries(
+ const GURL& path,
+ const ReadDirectoryCallback& success_callback,
+ const StatusCallback& error_callback) = 0;
+ virtual void Touch(const GURL& path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) = 0;
+ virtual void SetLength(const GURL& path,
+ int64_t length,
+ const StatusCallback& callback) = 0;
+ virtual void Delete(const GURL& path,
+ const StatusCallback& callback) = 0;
+ virtual void Rename(const GURL& file_path,
+ const GURL& new_file_path,
+ const StatusCallback& callback) = 0;
+ virtual void ReadDirectory(
+ const GURL& directory_path,
+ const ReadDirectoryCallback& success_callback,
+ const StatusCallback& error_callback) = 0;
+
+ // For quota handlings for FileIO API.
+ typedef base::Callback<void (int64)> AvailableSpaceCallback;
+ virtual void QueryAvailableSpace(const GURL& origin,
+ quota::StorageType type,
+ const AvailableSpaceCallback& callback) = 0;
+ virtual void WillUpdateFile(const GURL& file_path) = 0;
+ virtual void DidUpdateFile(const GURL& file_path, int64_t delta) = 0;
+
+ // Synchronously returns the platform file path for a filesystem URL.
+ virtual void SyncGetFileSystemPlatformPath(const GURL& url,
+ base::FilePath* platform_path) = 0;
+
+ // Returns a MessageLoopProxy instance associated with the message loop
+ // of the file thread in this renderer.
+ virtual scoped_refptr<base::MessageLoopProxy>
+ GetFileThreadMessageLoopProxy() = 0;
+
+ // For PPB_TCPSocket_Private.
+ virtual uint32 TCPSocketCreate() = 0;
+ virtual void TCPSocketConnect(PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id,
+ const std::string& host,
+ uint16_t port) = 0;
+ virtual void TCPSocketConnectWithNetAddress(
+ PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id,
+ const PP_NetAddress_Private& addr) = 0;
+ virtual void TCPSocketSSLHandshake(
+ uint32 socket_id,
+ const std::string& server_name,
+ uint16_t server_port,
+ const std::vector<std::vector<char> >& trusted_certs,
+ const std::vector<std::vector<char> >& untrusted_certs) = 0;
+ virtual void TCPSocketRead(uint32 socket_id, int32_t bytes_to_read) = 0;
+ virtual void TCPSocketWrite(uint32 socket_id, const std::string& buffer) = 0;
+ virtual void TCPSocketDisconnect(uint32 socket_id) = 0;
+ virtual void TCPSocketSetOption(uint32 socket_id,
+ PP_TCPSocket_Option name,
+ const ::ppapi::SocketOptionData& value) = 0;
+ virtual void RegisterTCPSocket(PPB_TCPSocket_Private_Impl* socket,
+ uint32 socket_id) = 0;
+
+ // For PPB_TCPServerSocket_Private.
+ virtual void TCPServerSocketListen(PP_Resource socket_resource,
+ const PP_NetAddress_Private& addr,
+ int32_t backlog) = 0;
+ virtual void TCPServerSocketAccept(uint32 server_socket_id) = 0;
+ virtual void TCPServerSocketStopListening(
+ PP_Resource socket_resource,
+ uint32 socket_id) = 0;
+
+ // Add/remove a network list observer.
+ virtual bool AddNetworkListObserver(
+ webkit_glue::NetworkListObserver* observer) = 0;
+ virtual void RemoveNetworkListObserver(
+ webkit_glue::NetworkListObserver* observer) = 0;
+
+ // For PPB_X509Certificate_Private.
+ virtual bool X509CertificateParseDER(
+ const std::vector<char>& der,
+ ::ppapi::PPB_X509Certificate_Fields* fields) = 0;
+
+ // Create a fullscreen container for a plugin instance. This effectively
+ // switches the plugin to fullscreen.
+ virtual FullscreenContainer* CreateFullscreenContainer(
+ PluginInstanceImpl* instance) = 0;
+
+ // Gets the size of the screen. The fullscreen window will be created at that
+ // size.
+ virtual gfx::Size GetScreenSize() = 0;
+
+ // Returns a string with the name of the default 8-bit char encoding.
+ virtual std::string GetDefaultEncoding() = 0;
+
+ // Sets the minimum and maximum zoom factors.
+ virtual void ZoomLimitsChanged(double minimum_factor,
+ double maximum_factor) = 0;
+
+ // Create an anonymous shared memory segment of size |size| bytes, and return
+ // a pointer to it, or NULL on error. Caller owns the returned pointer.
+ virtual base::SharedMemory* CreateAnonymousSharedMemory(size_t size) = 0;
+
+ // Returns the current preferences.
+ virtual ::ppapi::Preferences GetPreferences() = 0;
+
+ // Locks the mouse for |instance|. If false is returned, the lock is not
+ // possible. If true is returned then the lock is pending. Success or
+ // failure will be delivered asynchronously via
+ // PluginInstance::OnLockMouseACK().
+ virtual bool LockMouse(PluginInstanceImpl* instance) = 0;
+
+ // Unlocks the mouse if |instance| currently owns the mouse lock. Whenever an
+ // plugin instance has lost the mouse lock, it will be notified by
+ // PluginInstance::OnMouseLockLost(). Please note that UnlockMouse() is not
+ // the only cause of losing mouse lock. For example, a user may press the Esc
+ // key to quit the mouse lock mode, which also results in an OnMouseLockLost()
+ // call to the current mouse lock owner.
+ virtual void UnlockMouse(PluginInstanceImpl* instance) = 0;
+
+ // Returns true iff |instance| currently owns the mouse lock.
+ virtual bool IsMouseLocked(PluginInstanceImpl* instance) = 0;
+
+ // Notifies that |instance| has changed the cursor.
+ // This will update the cursor appearance if it is currently over the plugin
+ // instance.
+ virtual void DidChangeCursor(PluginInstanceImpl* instance,
+ const WebKit::WebCursorInfo& cursor) = 0;
+
+ // Notifies that |instance| has received a mouse event.
+ virtual void DidReceiveMouseEvent(PluginInstanceImpl* instance) = 0;
+
+ // Determines if the browser entered fullscreen mode.
+ virtual bool IsInFullscreenMode() = 0;
+
+ // Retrieve current gamepad data.
+ virtual void SampleGamepads(WebKit::WebGamepads* data) = 0;
+
+ // Returns true if the containing page is visible.
+ virtual bool IsPageVisible() const = 0;
+
+ typedef base::Callback<
+ void (int /* request_id */,
+ bool /* succeeded */,
+ const std::vector< ::ppapi::DeviceRefData>& /* devices */)>
+ EnumerateDevicesCallback;
+
+ // Enumerates devices of the specified type. The request ID passed into the
+ // callback will be the same as the return value.
+ virtual int EnumerateDevices(PP_DeviceType_Dev type,
+ const EnumerateDevicesCallback& callback) = 0;
+ // Stop enumerating devices of the specified |request_id|. The |request_id|
+ // is the return value of EnumerateDevicesCallback.
+ virtual void StopEnumerateDevices(int request_id) = 0;
+
+ // Share a given handle with the target process.
+ virtual IPC::PlatformFileForTransit ShareHandleWithRemote(
+ base::PlatformFile handle,
+ base::ProcessId target_process_id,
+ bool should_close_source) const = 0;
+
+ // Returns true if running in process.
+ virtual bool IsRunningInProcess(PP_Instance instance) const = 0;
+
+ // Notifies the plugin of the document load. This should initiate the call to
+ // PPP_Instance.HandleDocumentLoad.
+ //
+ // The loader object should set itself on the PluginInstance as the document
+ // loader using set_document_loader.
+ virtual void HandleDocumentLoad(PluginInstanceImpl* instance,
+ const WebKit::WebURLResponse& response) = 0;
+
+ // Sets up the renderer host and out-of-process proxy for an external plugin
+ // module. Returns the renderer host, or NULL if it couldn't be created.
+ virtual content::RendererPpapiHost* CreateExternalPluginModule(
+ scoped_refptr<PluginModule> module,
+ const base::FilePath& path,
+ ::ppapi::PpapiPermissions permissions,
+ const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) = 0;
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PLUGIN_DELEGATE_H_
diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc
new file mode 100644
index 0000000..820ba56
--- /dev/null
+++ b/content/renderer/pepper/plugin_module.cc
@@ -0,0 +1,634 @@
+// 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/plugin_module.h"
+
+#include <set>
+
+#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 "base/message_loop/message_loop_proxy.h"
+#include "base/time/time.h"
+#include "content/common/pepper_plugin_registry.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/ppapi_interface_factory.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppb_gpu_blacklist_private_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/pepper/ppb_proxy_impl.h"
+#include "content/renderer/pepper/ppb_scrollbar_impl.h"
+#include "content/renderer/pepper/ppb_uma_private_impl.h"
+#include "content/renderer/pepper/ppb_var_deprecated_impl.h"
+#include "content/renderer/pepper/ppb_video_decoder_impl.h"
+#include "ppapi/c/dev/ppb_audio_input_dev.h"
+#include "ppapi/c/dev/ppb_buffer_dev.h"
+#include "ppapi/c/dev/ppb_char_set_dev.h"
+#include "ppapi/c/dev/ppb_crypto_dev.h"
+#include "ppapi/c/dev/ppb_cursor_control_dev.h"
+#include "ppapi/c/dev/ppb_device_ref_dev.h"
+#include "ppapi/c/dev/ppb_file_chooser_dev.h"
+#include "ppapi/c/dev/ppb_find_dev.h"
+#include "ppapi/c/dev/ppb_font_dev.h"
+#include "ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h"
+#include "ppapi/c/dev/ppb_graphics_2d_dev.h"
+#include "ppapi/c/dev/ppb_memory_dev.h"
+#include "ppapi/c/dev/ppb_opengles2ext_dev.h"
+#include "ppapi/c/dev/ppb_printing_dev.h"
+#include "ppapi/c/dev/ppb_resource_array_dev.h"
+#include "ppapi/c/dev/ppb_scrollbar_dev.h"
+#include "ppapi/c/dev/ppb_testing_dev.h"
+#include "ppapi/c/dev/ppb_text_input_dev.h"
+#include "ppapi/c/dev/ppb_trace_event_dev.h"
+#include "ppapi/c/dev/ppb_truetype_font_dev.h"
+#include "ppapi/c/dev/ppb_url_util_dev.h"
+#include "ppapi/c/dev/ppb_var_deprecated.h"
+#include "ppapi/c/dev/ppb_video_capture_dev.h"
+#include "ppapi/c/dev/ppb_video_decoder_dev.h"
+#include "ppapi/c/dev/ppb_view_dev.h"
+#include "ppapi/c/dev/ppb_widget_dev.h"
+#include "ppapi/c/dev/ppb_zoom_dev.h"
+#include "ppapi/c/extensions/dev/ppb_ext_alarms_dev.h"
+#include "ppapi/c/extensions/dev/ppb_ext_socket_dev.h"
+#include "ppapi/c/pp_module.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppb_audio.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/c/ppb_console.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_file_io.h"
+#include "ppapi/c/ppb_file_ref.h"
+#include "ppapi/c/ppb_file_system.h"
+#include "ppapi/c/ppb_fullscreen.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_graphics_3d.h"
+#include "ppapi/c/ppb_host_resolver.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_messaging.h"
+#include "ppapi/c/ppb_mouse_cursor.h"
+#include "ppapi/c/ppb_mouse_lock.h"
+#include "ppapi/c/ppb_net_address.h"
+#include "ppapi/c/ppb_network_proxy.h"
+#include "ppapi/c/ppb_opengles2.h"
+#include "ppapi/c/ppb_tcp_socket.h"
+#include "ppapi/c/ppb_udp_socket.h"
+#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/c/ppb_url_request_info.h"
+#include "ppapi/c/ppb_url_response_info.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppb_var_array.h"
+#include "ppapi/c/ppb_var_array_buffer.h"
+#include "ppapi/c/ppb_var_dictionary.h"
+#include "ppapi/c/ppb_view.h"
+#include "ppapi/c/ppp.h"
+#include "ppapi/c/ppp_instance.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"
+#include "ppapi/c/private/ppb_flash.h"
+#include "ppapi/c/private/ppb_flash_clipboard.h"
+#include "ppapi/c/private/ppb_flash_device_id.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
+#include "ppapi/c/private/ppb_flash_file.h"
+#include "ppapi/c/private/ppb_flash_font_file.h"
+#include "ppapi/c/private/ppb_flash_fullscreen.h"
+#include "ppapi/c/private/ppb_flash_menu.h"
+#include "ppapi/c/private/ppb_flash_message_loop.h"
+#include "ppapi/c/private/ppb_flash_print.h"
+#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
+#include "ppapi/c/private/ppb_host_resolver_private.h"
+#include "ppapi/c/private/ppb_instance_private.h"
+#include "ppapi/c/private/ppb_network_list_private.h"
+#include "ppapi/c/private/ppb_network_monitor_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_udp_socket_private.h"
+#include "ppapi/c/private/ppb_uma_private.h"
+#include "ppapi/c/private/ppb_video_destination_private.h"
+#include "ppapi/c/private/ppb_video_source_private.h"
+#include "ppapi/c/private/ppb_x509_certificate_private.h"
+#include "ppapi/c/trusted/ppb_broker_trusted.h"
+#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
+#include "ppapi/c/trusted/ppb_char_set_trusted.h"
+#include "ppapi/c/trusted/ppb_file_chooser_trusted.h"
+#include "ppapi/c/trusted/ppb_file_io_trusted.h"
+#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
+#include "ppapi/shared_impl/callback_tracker.h"
+#include "ppapi/shared_impl/ppapi_switches.h"
+#include "ppapi/shared_impl/ppb_input_event_shared.h"
+#include "ppapi/shared_impl/ppb_opengles2_shared.h"
+#include "ppapi/shared_impl/ppb_var_shared.h"
+#include "ppapi/shared_impl/time_conversion.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_graphics_2d_api.h"
+#include "ppapi/thunk/thunk.h"
+#include "webkit/plugins/plugin_switches.h"
+
+using ppapi::InputEventData;
+using ppapi::PpapiGlobals;
+using ppapi::TimeTicksToPPTimeTicks;
+using ppapi::TimeToPPTime;
+using ppapi::thunk::EnterResource;
+using ppapi::thunk::PPB_Graphics2D_API;
+using ppapi::thunk::PPB_InputEvent_API;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+// Global tracking info for PPAPI plugins. This is lazily created before the
+// first plugin is allocated, and leaked on shutdown.
+//
+// Note that we don't want a Singleton here since destroying this object will
+// try to free some stuff that requires WebKit, and Singletons are destroyed
+// after WebKit.
+// TODO(raymes): I'm not sure if it is completely necessary to leak the
+// HostGlobals. Figure out the shutdown sequence and find a way to do this
+// more elegantly.
+webkit::ppapi::HostGlobals* host_globals = NULL;
+
+// Maintains all currently loaded plugin libs for validating PP_Module
+// identifiers.
+typedef std::set<PluginModule*> PluginModuleSet;
+
+PluginModuleSet* GetLivePluginSet() {
+ CR_DEFINE_STATIC_LOCAL(PluginModuleSet, live_plugin_libs, ());
+ return &live_plugin_libs;
+}
+
+// PPB_Core --------------------------------------------------------------------
+
+void AddRefResource(PP_Resource resource) {
+ PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(resource);
+}
+
+void ReleaseResource(PP_Resource resource) {
+ PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(resource);
+}
+
+PP_Time GetTime() {
+ return TimeToPPTime(base::Time::Now());
+}
+
+PP_TimeTicks GetTickTime() {
+ return TimeTicksToPPTimeTicks(base::TimeTicks::Now());
+}
+
+void CallOnMainThread(int delay_in_msec,
+ PP_CompletionCallback callback,
+ int32_t result) {
+ if (callback.func) {
+ PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(callback.func, callback.user_data, result),
+ base::TimeDelta::FromMilliseconds(delay_in_msec));
+ }
+}
+
+PP_Bool IsMainThread() {
+ return BoolToPPBool(PpapiGlobals::Get()->
+ GetMainThreadMessageLoop()->BelongsToCurrentThread());
+}
+
+const PPB_Core core_interface = {
+ &AddRefResource,
+ &ReleaseResource,
+ &GetTime,
+ &GetTickTime,
+ &CallOnMainThread,
+ &IsMainThread
+};
+
+// PPB_Testing -----------------------------------------------------------------
+
+PP_Bool ReadImageData(PP_Resource device_context_2d,
+ PP_Resource image,
+ const PP_Point* top_left) {
+ EnterResource<PPB_Graphics2D_API> enter(device_context_2d, true);
+ if (enter.failed())
+ return PP_FALSE;
+ return BoolToPPBool(enter.object()->ReadImageData(image, top_left));
+}
+
+void RunMessageLoop(PP_Instance instance) {
+ base::MessageLoop::ScopedNestableTaskAllower allow(
+ base::MessageLoop::current());
+ base::MessageLoop::current()->Run();
+}
+
+void QuitMessageLoop(PP_Instance instance) {
+ base::MessageLoop::current()->QuitNow();
+}
+
+uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) {
+ return HostGlobals::Get()->GetResourceTracker()->GetLiveObjectsForInstance(
+ instance_id);
+}
+
+PP_Bool IsOutOfProcess() {
+ return PP_FALSE;
+}
+
+void SimulateInputEvent(PP_Instance instance, PP_Resource input_event) {
+ PluginInstanceImpl* plugin_instance = host_globals->GetInstance(instance);
+ if (!plugin_instance)
+ return;
+
+ EnterResource<PPB_InputEvent_API> enter(input_event, false);
+ if (enter.failed())
+ return;
+
+ const InputEventData& input_event_data = enter.object()->GetInputEventData();
+ plugin_instance->SimulateInputEvent(input_event_data);
+}
+
+PP_Var GetDocumentURL(PP_Instance instance, PP_URLComponents_Dev* components) {
+ PluginInstanceImpl* plugin_instance = host_globals->GetInstance(instance);
+ if (!plugin_instance)
+ return PP_MakeUndefined();
+ return plugin_instance->GetDocumentURL(instance, components);
+}
+
+uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) {
+ std::vector<PP_Var> vars =
+ PpapiGlobals::Get()->GetVarTracker()->GetLiveVars();
+ for (size_t i = 0u;
+ i < std::min(static_cast<size_t>(array_size), vars.size());
+ ++i)
+ live_vars[i] = vars[i];
+ return vars.size();
+}
+
+void SetMinimumArrayBufferSizeForShmem(PP_Instance /*instance*/,
+ uint32_t /*threshold*/) {
+ // Does nothing. Not needed in-process.
+}
+
+const PPB_Testing_Dev testing_interface = {
+ &ReadImageData,
+ &RunMessageLoop,
+ &QuitMessageLoop,
+ &GetLiveObjectsForInstance,
+ &IsOutOfProcess,
+ &SimulateInputEvent,
+ &GetDocumentURL,
+ &GetLiveVars,
+ &SetMinimumArrayBufferSizeForShmem
+};
+
+// GetInterface ----------------------------------------------------------------
+
+const void* InternalGetInterface(const char* name) {
+ // Allow custom interface factories first stab at the GetInterface call.
+ const void* custom_interface =
+ PpapiInterfaceFactoryManager::GetInstance()->GetInterface(name);
+ if (custom_interface)
+ return custom_interface;
+
+ // TODO(brettw) put these in a hash map for better performance.
+ #define UNPROXIED_IFACE(api_name, iface_str, iface_struct) \
+ if (strcmp(name, iface_str) == 0) \
+ return ::ppapi::thunk::Get##iface_struct##_Thunk();
+ #define PROXIED_IFACE(api_name, iface_str, iface_struct) \
+ UNPROXIED_IFACE(api_name, iface_str, iface_struct)
+
+ #include "ppapi/thunk/interfaces_ppb_public_stable.h"
+ #include "ppapi/thunk/interfaces_ppb_public_dev.h"
+ #include "ppapi/thunk/interfaces_ppb_private.h"
+ #include "ppapi/thunk/interfaces_ppb_private_no_permissions.h"
+ #include "ppapi/thunk/interfaces_ppb_private_flash.h"
+
+ #undef UNPROXIED_API
+ #undef PROXIED_IFACE
+
+ #define LEGACY_IFACE(iface_str, function_name) \
+ if (strcmp(name, iface_str) == 0) \
+ return function_name;
+
+ #include "ppapi/thunk/interfaces_legacy.h"
+
+ #undef LEGACY_IFACE
+
+ // 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(
+ switches::kEnablePepperTesting)) {
+ if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0 ||
+ strcmp(name, PPB_TESTING_DEV_INTERFACE_0_9) == 0) {
+ return &testing_interface;
+ }
+ }
+ return NULL;
+}
+
+const void* GetInterface(const char* name) {
+ // All interfaces should be used on the main thread.
+ CHECK(IsMainThread());
+
+ return InternalGetInterface(name);
+}
+
+// Gets the PPAPI entry points from the given library and places them into the
+// given structure. Returns true on success.
+bool LoadEntryPointsFromLibrary(
+ const base::NativeLibrary& library,
+ content::PepperPluginInfo::EntryPoints* entry_points) {
+ entry_points->get_interface =
+ reinterpret_cast<content::PepperPluginInfo::GetInterfaceFunc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "PPP_GetInterface"));
+ if (!entry_points->get_interface) {
+ LOG(WARNING) << "No PPP_GetInterface in plugin library";
+ return false;
+ }
+
+ entry_points->initialize_module =
+ reinterpret_cast<content::PepperPluginInfo::PPP_InitializeModuleFunc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "PPP_InitializeModule"));
+ if (!entry_points->initialize_module) {
+ LOG(WARNING) << "No PPP_InitializeModule in plugin library";
+ return false;
+ }
+
+ // It's okay for PPP_ShutdownModule to not be defined and shutdown_module to
+ // be NULL.
+ entry_points->shutdown_module =
+ reinterpret_cast<content::PepperPluginInfo::PPP_ShutdownModuleFunc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "PPP_ShutdownModule"));
+
+ return true;
+}
+
+} // namespace
+
+// PluginModule ----------------------------------------------------------------
+
+PluginModule::PluginModule(const std::string& name,
+ const base::FilePath& path,
+ const ::ppapi::PpapiPermissions& perms)
+ : callback_tracker_(new ::ppapi::CallbackTracker),
+ is_in_destructor_(false),
+ is_crashed_(false),
+ broker_(NULL),
+ library_(NULL),
+ name_(name),
+ path_(path),
+ permissions_(perms),
+ reserve_instance_id_(NULL) {
+ // Ensure the globals object is created.
+ if (!host_globals)
+ host_globals = new HostGlobals;
+
+ memset(&entry_points_, 0, sizeof(entry_points_));
+ pp_module_ = HostGlobals::Get()->AddModule(this);
+ GetLivePluginSet()->insert(this);
+}
+
+PluginModule::~PluginModule() {
+ // In the past there have been crashes reentering the plugin module
+ // destructor. Catch if that happens again earlier.
+ CHECK(!is_in_destructor_);
+ is_in_destructor_ = true;
+
+ // When the module is being deleted, there should be no more instances still
+ // holding a reference to us.
+ DCHECK(instances_.empty());
+
+ // Some resources and other stuff are hung off of the embedder state, which
+ // should be torn down before the routing stuff below.
+ embedder_state_.reset();
+
+ GetLivePluginSet()->erase(this);
+
+ callback_tracker_->AbortAll();
+
+ if (entry_points_.shutdown_module)
+ entry_points_.shutdown_module();
+
+ if (library_)
+ base::UnloadNativeLibrary(library_);
+
+ // Notifications that we've been deleted should be last.
+ HostGlobals::Get()->ModuleDeleted(pp_module_);
+ if (!is_crashed_) {
+ // When the plugin crashes, we immediately tell the lifetime delegate that
+ // we're gone, so we don't want to tell it again.
+ content::PepperPluginRegistry::GetInstance()->PluginModuleDead(this);
+ }
+
+ // Don't add stuff here, the two notifications that the module object has
+ // been deleted should be last. This allows, for example,
+ // PPB_Proxy.IsInModuleDestructor to map PP_Module to this class during the
+ // previous parts of the destructor.
+}
+
+void PluginModule::SetEmbedderState(scoped_ptr<EmbedderState> state) {
+ embedder_state_ = state.Pass();
+}
+
+PluginModule::EmbedderState* PluginModule::GetEmbedderState() {
+ return embedder_state_.get();
+}
+
+bool PluginModule::InitAsInternalPlugin(
+ const content::PepperPluginInfo::EntryPoints& entry_points) {
+ if (InitializeModule(entry_points)) {
+ entry_points_ = entry_points;
+ return true;
+ }
+ return false;
+}
+
+bool PluginModule::InitAsLibrary(const base::FilePath& path) {
+ base::NativeLibrary library = base::LoadNativeLibrary(path, NULL);
+ if (!library)
+ return false;
+
+ content::PepperPluginInfo::EntryPoints entry_points;
+
+ if (!LoadEntryPointsFromLibrary(library, &entry_points) ||
+ !InitializeModule(entry_points)) {
+ base::UnloadNativeLibrary(library);
+ return false;
+ }
+ entry_points_ = entry_points;
+ library_ = library;
+ return true;
+}
+
+void PluginModule::InitAsProxied(
+ PluginDelegate::OutOfProcessProxy* out_of_process_proxy) {
+ DCHECK(!out_of_process_proxy_.get());
+ out_of_process_proxy_.reset(out_of_process_proxy);
+}
+
+scoped_refptr<PluginModule>
+ PluginModule::CreateModuleForExternalPluginInstance() {
+ // Create a new module, but don't set the lifetime delegate. This isn't a
+ // plugin in the usual sense, so it isn't tracked by the browser.
+ scoped_refptr<PluginModule> external_plugin_module(
+ new PluginModule(name_,
+ path_,
+ permissions_));
+ return external_plugin_module;
+}
+
+PP_ExternalPluginResult PluginModule::InitAsProxiedExternalPlugin(
+ PluginInstanceImpl* instance) {
+ DCHECK(out_of_process_proxy_.get());
+ // InitAsProxied (for the trusted/out-of-process case) initializes only the
+ // module, and one or more instances are added later. In this case, the
+ // PluginInstance was already created as in-process, so we missed the proxy
+ // AddInstance step and must do it now.
+ out_of_process_proxy_->AddInstance(instance->pp_instance());
+ // For external plugins, we need to tell the instance to reset itself as
+ // proxied. This will clear cached interface pointers and send DidCreate (etc)
+ // to the plugin side of the proxy.
+ return instance->ResetAsProxied(this);
+}
+
+bool PluginModule::IsProxied() const {
+ return !!out_of_process_proxy_;
+}
+
+base::ProcessId PluginModule::GetPeerProcessId() {
+ if (out_of_process_proxy_)
+ return out_of_process_proxy_->GetPeerProcessId();
+ return base::kNullProcessId;
+}
+
+int PluginModule::GetPluginChildId() {
+ if (out_of_process_proxy_)
+ return out_of_process_proxy_->GetPluginChildId();
+ return 0;
+}
+
+// static
+const PPB_Core* PluginModule::GetCore() {
+ return &core_interface;
+}
+
+// static
+content::PepperPluginInfo::GetInterfaceFunc
+ PluginModule::GetLocalGetInterfaceFunc() {
+ return &GetInterface;
+}
+
+// static
+bool PluginModule::SupportsInterface(const char* name) {
+ return !!InternalGetInterface(name);
+}
+
+PluginInstanceImpl* PluginModule::CreateInstance(
+ PluginDelegate* delegate,
+ content::RenderView* render_view,
+ WebKit::WebPluginContainer* container,
+ const GURL& plugin_url) {
+ PluginInstanceImpl* instance = PluginInstanceImpl::Create(
+ delegate, render_view, this, container, plugin_url);
+ if (!instance) {
+ LOG(WARNING) << "Plugin doesn't support instance interface, failing.";
+ return NULL;
+ }
+ if (out_of_process_proxy_)
+ out_of_process_proxy_->AddInstance(instance->pp_instance());
+ return instance;
+}
+
+PluginInstanceImpl* PluginModule::GetSomeInstance() const {
+ // This will generally crash later if there is not actually any instance to
+ // return, so we force a crash now to make bugs easier to track down.
+ CHECK(!instances_.empty());
+ return *instances_.begin();
+}
+
+const void* PluginModule::GetPluginInterface(const char* name) const {
+ if (out_of_process_proxy_)
+ return out_of_process_proxy_->GetProxiedInterface(name);
+
+ // In-process plugins.
+ if (!entry_points_.get_interface)
+ return NULL;
+ return entry_points_.get_interface(name);
+}
+
+void PluginModule::InstanceCreated(PluginInstanceImpl* instance) {
+ instances_.insert(instance);
+}
+
+void PluginModule::InstanceDeleted(PluginInstanceImpl* instance) {
+ if (out_of_process_proxy_)
+ out_of_process_proxy_->RemoveInstance(instance->pp_instance());
+ instances_.erase(instance);
+}
+
+scoped_refptr< ::ppapi::CallbackTracker> PluginModule::GetCallbackTracker() {
+ return callback_tracker_;
+}
+
+void PluginModule::PluginCrashed() {
+ DCHECK(!is_crashed_); // Should only get one notification.
+ is_crashed_ = true;
+
+ // Notify all instances that they crashed.
+ for (PluginInstanceSet::iterator i = instances_.begin();
+ i != instances_.end(); ++i)
+ (*i)->InstanceCrashed();
+
+ content::PepperPluginRegistry::GetInstance()->PluginModuleDead(this);
+}
+
+void PluginModule::SetReserveInstanceIDCallback(
+ PP_Bool (*reserve)(PP_Module, PP_Instance)) {
+ DCHECK(!reserve_instance_id_) << "Only expect one set.";
+ reserve_instance_id_ = reserve;
+}
+
+bool PluginModule::ReserveInstanceID(PP_Instance instance) {
+ if (reserve_instance_id_)
+ return PPBoolToBool(reserve_instance_id_(pp_module_, instance));
+ return true; // Instance ID is usable.
+}
+
+void PluginModule::SetBroker(PluginDelegate::Broker* broker) {
+ DCHECK(!broker_ || !broker);
+ broker_ = broker;
+}
+
+PluginDelegate::Broker* PluginModule::GetBroker() {
+ return broker_;
+}
+
+// static
+void PluginModule::ResetHostGlobalsForTest() {
+ delete host_globals;
+ host_globals = NULL;
+}
+
+bool PluginModule::InitializeModule(
+ const content::PepperPluginInfo::EntryPoints& entry_points) {
+ DCHECK(!out_of_process_proxy_.get()) << "Don't call for proxied modules.";
+ DCHECK(entry_points.initialize_module != NULL);
+ int retval = entry_points.initialize_module(pp_module(), &GetInterface);
+ if (retval != 0) {
+ LOG(WARNING) << "PPP_InitializeModule returned failure " << retval;
+ return false;
+ }
+ return true;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/plugin_module.h b/content/renderer/pepper/plugin_module.h
new file mode 100644
index 0000000..c4f3527
--- /dev/null
+++ b/content/renderer/pepper/plugin_module.h
@@ -0,0 +1,267 @@
+// 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_PLUGIN_MODULE_H_
+#define CONTENT_RENDERER_PEPPER_PLUGIN_MODULE_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/native_library.h"
+#include "base/process.h"
+#include "content/common/content_export.h"
+#include "content/public/common/pepper_plugin_info.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/private/ppb_instance_private.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
+
+typedef void* NPIdentifier;
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+class RenderView;
+}
+
+namespace ppapi {
+class CallbackTracker;
+class WebKitForwarding;
+} // namespace ppapi
+
+namespace WebKit {
+class WebPluginContainer;
+} // namespace WebKit
+
+namespace webkit {
+namespace ppapi {
+
+class PluginDelegate;
+class PluginInstanceImpl;
+
+// Represents one plugin library loaded into one renderer. This library may
+// have multiple instances.
+//
+// Note: to get from a PP_Instance to a PluginInstance*, use the
+// ResourceTracker.
+class CONTENT_EXPORT PluginModule :
+ public base::RefCounted<PluginModule>,
+ public base::SupportsWeakPtr<PluginModule> {
+ public:
+ // Allows the embedder to associate a class with this module. This is opaque
+ // from the PluginModule's perspective (see Set/GetEmbedderState below) but
+ // the module is in charge of deleting the class.
+ class EmbedderState {
+ public:
+ virtual ~EmbedderState() {}
+ };
+
+ typedef std::set<PluginInstanceImpl*> PluginInstanceSet;
+
+ // You must call one of the Init functions after the constructor to create a
+ // module of the type you desire.
+ //
+ // The module lifetime delegate is a non-owning pointer that must outlive
+ // all plugin modules. In practice it will be a global singleton that
+ // tracks which modules are alive.
+ PluginModule(const std::string& name,
+ const base::FilePath& path,
+ const ::ppapi::PpapiPermissions& perms);
+
+ // Sets the given class as being associated with this module. It will be
+ // deleted when the module is destroyed. You can only set it once, subsequent
+ // sets will assert.
+ //
+ // See EmbedderState above for more.
+ void SetEmbedderState(scoped_ptr<EmbedderState> state);
+ EmbedderState* GetEmbedderState();
+
+ // Initializes this module as an internal plugin with the given entrypoints.
+ // This is used for "plugins" compiled into Chrome. Returns true on success.
+ // False means that the plugin can not be used.
+ bool InitAsInternalPlugin(
+ const content::PepperPluginInfo::EntryPoints& entry_points);
+
+ // Initializes this module using the given library path as the plugin.
+ // Returns true on success. False means that the plugin can not be used.
+ bool InitAsLibrary(const base::FilePath& path);
+
+ // Initializes this module for the given out of process proxy. This takes
+ // ownership of the given pointer, even in the failure case.
+ void InitAsProxied(PluginDelegate::OutOfProcessProxy* out_of_process_proxy);
+
+ // Creates a new module for an external plugin instance that will be using the
+ // IPC proxy. We can't use the existing module, or new instances of the plugin
+ // can't be created.
+ scoped_refptr<PluginModule> CreateModuleForExternalPluginInstance();
+
+ // Initializes the external plugin module for the out of process proxy.
+ // InitAsProxied must be called before calling InitAsProxiedExternalPlugin.
+ // Returns a result code indicating whether the proxy started successfully or
+ // there was an error.
+ PP_ExternalPluginResult InitAsProxiedExternalPlugin(
+ PluginInstanceImpl* instance);
+
+ bool IsProxied() const;
+
+ // Returns the peer process ID if the plugin is running out of process;
+ // returns |base::kNullProcessId| otherwise.
+ base::ProcessId GetPeerProcessId();
+
+ // Returns the plugin child process ID if the plugin is running out of
+ // process. Returns 0 otherwise. This is the ID that the browser process uses
+ // to idetify the child process for the plugin. This isn't directly useful
+ // from our process (the renderer) except in messages to the browser to
+ // disambiguate plugins.
+ int GetPluginChildId();
+
+ static const PPB_Core* GetCore();
+
+ // Returns a pointer to the local GetInterface function for retrieving
+ // PPB interfaces.
+ static content::PepperPluginInfo::GetInterfaceFunc GetLocalGetInterfaceFunc();
+
+ // Returns whether an interface is supported. This method can be called from
+ // the browser process and used for interface matching before plugin
+ // registration.
+ // NOTE: those custom interfaces provided by PpapiInterfaceFactoryManager
+ // will not be considered when called on the browser process.
+ static bool SupportsInterface(const char* name);
+
+ // Returns the module handle. This may be used before Init() is called (the
+ // proxy needs this information to set itself up properly).
+ PP_Module pp_module() const { return pp_module_; }
+
+ const std::string& name() const { return name_; }
+ const base::FilePath& path() const { return path_; }
+ const ::ppapi::PpapiPermissions& permissions() const { return permissions_; }
+
+ PluginInstanceImpl* CreateInstance(PluginDelegate* delegate,
+ content::RenderView* render_view,
+ WebKit::WebPluginContainer* container,
+ const GURL& plugin_url);
+
+ // Returns "some" plugin instance associated with this module. This is not
+ // guaranteed to be any one in particular. This is normally used to execute
+ // callbacks up to the browser layer that are not inherently per-instance,
+ // but the delegate lives only on the plugin instance so we need one of them.
+ PluginInstanceImpl* GetSomeInstance() const;
+
+ const PluginInstanceSet& GetAllInstances() const { return instances_; }
+
+ // Calls the plugin's GetInterface and returns the given interface pointer,
+ // which could be NULL.
+ const void* GetPluginInterface(const char* name) const;
+
+ // This module is associated with a set of instances. The PluginInstance
+ // object declares its association with this module in its destructor and
+ // releases us in its destructor.
+ void InstanceCreated(PluginInstanceImpl* instance);
+ void InstanceDeleted(PluginInstanceImpl* instance);
+
+ scoped_refptr< ::ppapi::CallbackTracker> GetCallbackTracker();
+
+ // Called when running out of process and the plugin crashed. This will
+ // release relevant resources and update all affected instances.
+ void PluginCrashed();
+
+ bool is_in_destructor() const { return is_in_destructor_; }
+ bool is_crashed() const { return is_crashed_; }
+
+ // Reserves the given instance is unique within the plugin, checking for
+ // collisions. See PPB_Proxy_Private for more information.
+ //
+ // The setter will set the callback which is set up when the proxy
+ // initializes. The Reserve function will call the previously set callback if
+ // it exists to validate the ID. If the callback has not been set (such as
+ // for in-process plugins), the Reserve function will assume that the ID is
+ // usable and will return true.
+ void SetReserveInstanceIDCallback(
+ PP_Bool (*reserve)(PP_Module, PP_Instance));
+ bool ReserveInstanceID(PP_Instance instance);
+
+ // These should only be called from the main thread.
+ void SetBroker(PluginDelegate::Broker* broker);
+ PluginDelegate::Broker* GetBroker();
+
+ // In production we purposely leak the HostGlobals object but in unittest
+ // code, this can interfere with subsequent tests. This deletes the
+ // existing HostGlobals. A new one will be constructed when a PluginModule is
+ // instantiated.
+ static void ResetHostGlobalsForTest();
+
+ private:
+ friend class base::RefCounted<PluginModule>;
+ ~PluginModule();
+ // Calls the InitializeModule entrypoint. The entrypoint must have been
+ // set and the plugin must not be out of process (we don't maintain
+ // entrypoints in that case).
+ bool InitializeModule(
+ const content::PepperPluginInfo::EntryPoints& entry_points);
+
+ // See EmbedderState above.
+ scoped_ptr<EmbedderState> embedder_state_;
+
+ // Tracker for completion callbacks, used mainly to ensure that all callbacks
+ // are properly aborted on module shutdown.
+ scoped_refptr< ::ppapi::CallbackTracker> callback_tracker_;
+
+ PP_Module pp_module_;
+
+ // True when we're running in the destructor. This allows us to write some
+ // assertions.
+ bool is_in_destructor_;
+
+ // True if the plugin is running out-of-process and has crashed.
+ bool is_crashed_;
+
+ // Manages the out of process proxy interface. The presence of this
+ // pointer indicates that the plugin is running out of process and that the
+ // entry_points_ aren't valid.
+ scoped_ptr<PluginDelegate::OutOfProcessProxy> out_of_process_proxy_;
+
+ // Non-owning pointer to the broker for this plugin module, if one exists.
+ // It is populated and cleared in the main thread.
+ PluginDelegate::Broker* broker_;
+
+ // Holds a reference to the base::NativeLibrary handle if this PluginModule
+ // instance wraps functions loaded from a library. Can be NULL. If
+ // |library_| is non-NULL, PluginModule will attempt to unload the library
+ // during destruction.
+ base::NativeLibrary library_;
+
+ // Contains pointers to the entry points of the actual plugin implementation.
+ // These will be NULL for out-of-process plugins, which is indicated by the
+ // presence of the out_of_process_proxy_ value.
+ content::PepperPluginInfo::EntryPoints entry_points_;
+
+ // The name and file location of the module.
+ const std::string name_;
+ const base::FilePath path_;
+
+ ::ppapi::PpapiPermissions permissions_;
+
+ // Non-owning pointers to all instances associated with this module. When
+ // there are no more instances, this object should be deleted.
+ PluginInstanceSet instances_;
+
+ PP_Bool (*reserve_instance_id_)(PP_Module, PP_Instance);
+
+ DISALLOW_COPY_AND_ASSIGN(PluginModule);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PLUGIN_MODULE_H_
diff --git a/content/renderer/pepper/plugin_object.cc b/content/renderer/pepper/plugin_object.cc
new file mode 100644
index 0000000..9955d0cf8
--- /dev/null
+++ b/content/renderer/pepper/plugin_object.cc
@@ -0,0 +1,360 @@
+// 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/pepper/plugin_object.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "content/renderer/pepper/npapi_glue.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/dev/ppb_var_deprecated.h"
+#include "ppapi/c/dev/ppp_class_deprecated.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+using ppapi::PpapiGlobals;
+using ppapi::StringVar;
+using ppapi::Var;
+using WebKit::WebBindings;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+const char kInvalidValueException[] = "Error: Invalid value";
+
+// NPObject implementation in terms of PPP_Class_Deprecated --------------------
+
+NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) {
+ return PluginObject::AllocateObjectWrapper();
+}
+
+void WrapperClass_Deallocate(NPObject* np_object) {
+ PluginObject* plugin_object = PluginObject::FromNPObject(np_object);
+ if (!plugin_object)
+ return;
+ plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data());
+ delete plugin_object;
+}
+
+void WrapperClass_Invalidate(NPObject* object) {
+}
+
+bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) {
+ NPObjectAccessorWithIdentifier accessor(object, method_name, false);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(
+ accessor.object()->GetNPObject(), NULL);
+ bool rv = accessor.object()->ppp_class()->HasMethod(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception());
+ result_converter.CheckExceptionForNoResult();
+ return rv;
+}
+
+bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name,
+ const NPVariant* argv, uint32_t argc,
+ NPVariant* result) {
+ NPObjectAccessorWithIdentifier accessor(object, method_name, false);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(
+ accessor.object()->GetNPObject(), result);
+ PPVarArrayFromNPVariantArray args(accessor.object()->instance(),
+ argc, argv);
+
+ // For the OOP plugin case we need to grab a reference on the plugin module
+ // object to ensure that it is not destroyed courtsey an incoming
+ // ExecuteScript call which destroys the plugin module and in turn the
+ // dispatcher.
+ scoped_refptr<webkit::ppapi::PluginModule> ref(
+ accessor.object()->instance()->module());
+
+ return result_converter.SetResult(accessor.object()->ppp_class()->Call(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ argc, args.array(), result_converter.exception()));
+}
+
+bool WrapperClass_InvokeDefault(NPObject* np_object, const NPVariant* argv,
+ uint32_t argc, NPVariant* result) {
+ PluginObject* obj = PluginObject::FromNPObject(np_object);
+ if (!obj)
+ return false;
+
+ PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv);
+ PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result);
+
+ // For the OOP plugin case we need to grab a reference on the plugin module
+ // object to ensure that it is not destroyed courtsey an incoming
+ // ExecuteScript call which destroys the plugin module and in turn the
+ // dispatcher.
+ scoped_refptr<webkit::ppapi::PluginModule> ref(
+ obj->instance()->module());
+
+ result_converter.SetResult(obj->ppp_class()->Call(
+ obj->ppp_class_data(), PP_MakeUndefined(), argc, args.array(),
+ result_converter.exception()));
+ return result_converter.success();
+}
+
+bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) {
+ NPObjectAccessorWithIdentifier accessor(object, property_name, true);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(
+ accessor.object()->GetNPObject(), NULL);
+ bool rv = accessor.object()->ppp_class()->HasProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception());
+ result_converter.CheckExceptionForNoResult();
+ return rv;
+}
+
+bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name,
+ NPVariant* result) {
+ NPObjectAccessorWithIdentifier accessor(object, property_name, true);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(
+ accessor.object()->GetNPObject(), result);
+ return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception()));
+}
+
+bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name,
+ const NPVariant* value) {
+ NPObjectAccessorWithIdentifier accessor(object, property_name, true);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(
+ accessor.object()->GetNPObject(), NULL);
+ PP_Var value_var = NPVariantToPPVar(accessor.object()->instance(), value);
+ accessor.object()->ppp_class()->SetProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(), value_var,
+ result_converter.exception());
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(value_var);
+ return result_converter.CheckExceptionForNoResult();
+}
+
+bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) {
+ NPObjectAccessorWithIdentifier accessor(object, property_name, true);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(
+ accessor.object()->GetNPObject(), NULL);
+ accessor.object()->ppp_class()->RemoveProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception());
+ return result_converter.CheckExceptionForNoResult();
+}
+
+bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values,
+ uint32_t* count) {
+ *values = NULL;
+ *count = 0;
+ PluginObject* obj = PluginObject::FromNPObject(object);
+ if (!obj)
+ return false;
+
+ uint32_t property_count = 0;
+ PP_Var* properties = NULL; // Must be freed!
+ PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), NULL);
+ obj->ppp_class()->GetAllPropertyNames(obj->ppp_class_data(),
+ &property_count, &properties,
+ result_converter.exception());
+
+ // Convert the array of PP_Var to an array of NPIdentifiers. If any
+ // conversions fail, we will set the exception.
+ if (!result_converter.has_exception()) {
+ if (property_count > 0) {
+ *values = static_cast<NPIdentifier*>(
+ malloc(sizeof(NPIdentifier) * property_count));
+ *count = 0; // Will be the number of items successfully converted.
+ for (uint32_t i = 0; i < property_count; ++i) {
+ if (!((*values)[i] = PPVarToNPIdentifier(properties[i]))) {
+ // Throw an exception for the failed convertion.
+ *result_converter.exception() =
+ StringVar::StringToPPVar(kInvalidValueException);
+ break;
+ }
+ (*count)++;
+ }
+
+ if (result_converter.has_exception()) {
+ // We don't actually have to free the identifiers we converted since
+ // all identifiers leak anyway :( .
+ free(*values);
+ *values = NULL;
+ *count = 0;
+ }
+ }
+ }
+
+ // This will actually throw the exception, either from GetAllPropertyNames,
+ // or if anything was set during the conversion process.
+ result_converter.CheckExceptionForNoResult();
+
+ // Release the PP_Var that the plugin allocated. On success, they will all
+ // be converted to NPVariants, and on failure, we want them to just go away.
+ ::ppapi::VarTracker* var_tracker = PpapiGlobals::Get()->GetVarTracker();
+ for (uint32_t i = 0; i < property_count; ++i)
+ var_tracker->ReleaseVar(properties[i]);
+ free(properties);
+ return result_converter.success();
+}
+
+bool WrapperClass_Construct(NPObject* object, const NPVariant* argv,
+ uint32_t argc, NPVariant* result) {
+ PluginObject* obj = PluginObject::FromNPObject(object);
+ if (!obj)
+ return false;
+
+ PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv);
+ PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result);
+ return result_converter.SetResult(obj->ppp_class()->Construct(
+ obj->ppp_class_data(), argc, args.array(),
+ result_converter.exception()));
+}
+
+const NPClass wrapper_class = {
+ NP_CLASS_STRUCT_VERSION,
+ WrapperClass_Allocate,
+ WrapperClass_Deallocate,
+ WrapperClass_Invalidate,
+ WrapperClass_HasMethod,
+ WrapperClass_Invoke,
+ WrapperClass_InvokeDefault,
+ WrapperClass_HasProperty,
+ WrapperClass_GetProperty,
+ WrapperClass_SetProperty,
+ WrapperClass_RemoveProperty,
+ WrapperClass_Enumerate,
+ WrapperClass_Construct
+};
+
+} // namespace
+
+// PluginObject ----------------------------------------------------------------
+
+struct PluginObject::NPObjectWrapper : public NPObject {
+ // Points to the var object that owns this wrapper. This value may be NULL
+ // if there is no var owning this wrapper. This can happen if the plugin
+ // releases all references to the var, but a reference to the underlying
+ // NPObject is still held by script on the page.
+ PluginObject* obj;
+};
+
+PluginObject::PluginObject(PluginInstanceImpl* instance,
+ NPObjectWrapper* object_wrapper,
+ const PPP_Class_Deprecated* ppp_class,
+ void* ppp_class_data)
+ : instance_(instance),
+ object_wrapper_(object_wrapper),
+ ppp_class_(ppp_class),
+ ppp_class_data_(ppp_class_data) {
+ // Make the object wrapper refer back to this class so our NPObject
+ // implementation can call back into the Pepper layer.
+ object_wrapper_->obj = this;
+ instance_->AddPluginObject(this);
+}
+
+PluginObject::~PluginObject() {
+ // The wrapper we made for this NPObject may still have a reference to it
+ // from JavaScript, so we clear out its ObjectVar back pointer which will
+ // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base
+ // class will release our reference to the object, which may or may not
+ // delete the NPObject.
+ DCHECK(object_wrapper_->obj == this);
+ object_wrapper_->obj = NULL;
+ instance_->RemovePluginObject(this);
+}
+
+PP_Var PluginObject::Create(PluginInstanceImpl* instance,
+ const PPP_Class_Deprecated* ppp_class,
+ void* ppp_class_data) {
+ // This will internally end up calling our AllocateObjectWrapper via the
+ // WrapperClass_Allocated function which will have created an object wrapper
+ // appropriate for this class (derived from NPObject).
+ NPObjectWrapper* wrapper = static_cast<NPObjectWrapper*>(
+ WebBindings::createObject(instance->instanceNPP(),
+ const_cast<NPClass*>(&wrapper_class)));
+
+ // This object will register itself both with the NPObject and with the
+ // PluginModule. The NPObject will normally handle its lifetime, and it
+ // will get deleted in the destroy method. It may also get deleted when the
+ // plugin module is deallocated.
+ new PluginObject(instance, wrapper, ppp_class, ppp_class_data);
+
+ // We can just use a normal ObjectVar to refer to this object from the
+ // plugin. It will hold a ref to the underlying NPObject which will in turn
+ // hold our pluginObject.
+ PP_Var obj_var(NPObjectToPPVar(instance, wrapper));
+
+ // Note that the ObjectVar constructor incremented the reference count, and so
+ // did WebBindings::createObject above. Now that the PP_Var has taken
+ // ownership, we need to release to balance out the createObject reference
+ // count bump.
+ WebBindings::releaseObject(wrapper);
+ return obj_var;
+}
+
+NPObject* PluginObject::GetNPObject() const {
+ return object_wrapper_;
+}
+
+// static
+bool PluginObject::IsInstanceOf(NPObject* np_object,
+ const PPP_Class_Deprecated* ppp_class,
+ void** ppp_class_data) {
+ // Validate that this object is implemented by our wrapper class before
+ // trying to get the PluginObject.
+ if (np_object->_class != &wrapper_class)
+ return false;
+
+ PluginObject* plugin_object = FromNPObject(np_object);
+ if (!plugin_object)
+ return false; // Object is no longer alive.
+
+ if (plugin_object->ppp_class() != ppp_class)
+ return false;
+ if (ppp_class_data)
+ *ppp_class_data = plugin_object->ppp_class_data();
+ return true;
+}
+
+// static
+PluginObject* PluginObject::FromNPObject(NPObject* object) {
+ return static_cast<NPObjectWrapper*>(object)->obj;
+}
+
+// static
+NPObject* PluginObject::AllocateObjectWrapper() {
+ NPObjectWrapper* wrapper = new NPObjectWrapper;
+ memset(wrapper, 0, sizeof(NPObjectWrapper));
+ return wrapper;
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/content/renderer/pepper/plugin_object.h b/content/renderer/pepper/plugin_object.h
new file mode 100644
index 0000000..c222e50
--- /dev/null
+++ b/content/renderer/pepper/plugin_object.h
@@ -0,0 +1,95 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_PEPPER_PLUGIN_OBJECT_H_
+#define CONTENT_RENDERER_PEPPER_PLUGIN_OBJECT_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+struct PP_Var;
+struct PPP_Class_Deprecated;
+typedef struct NPObject NPObject;
+typedef struct _NPVariant NPVariant;
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstanceImpl;
+
+// A PluginObject is a JS-accessible object implemented by the plugin.
+//
+// In contrast, a var of type PP_VARTYPE_OBJECT is a reference to a JS object,
+// which might be implemented by the plugin (here) or by the JS engine.
+class PluginObject {
+ public:
+ virtual ~PluginObject();
+
+ // Allocates a new PluginObject and returns it as a PP_Var with a
+ // refcount of 1.
+ static PP_Var Create(PluginInstanceImpl* instance,
+ const PPP_Class_Deprecated* ppp_class,
+ void* ppp_class_data);
+
+ PluginInstanceImpl* instance() const { return instance_; }
+
+ const PPP_Class_Deprecated* ppp_class() { return ppp_class_; }
+ void* ppp_class_data() { return ppp_class_data_; };
+
+ NPObject* GetNPObject() const;
+
+ // Returns true if the given var is an object implemented by the same plugin
+ // that owns the var object, and that the class matches. If it matches,
+ // returns true and places the class data into |*ppp_class_data| (which can
+ // optionally be NULL if no class data is desired).
+ static bool IsInstanceOf(NPObject* np_object,
+ const PPP_Class_Deprecated* ppp_class,
+ void** ppp_class_data);
+
+ // Converts the given NPObject to the corresponding ObjectVar.
+ //
+ // The given NPObject must be one corresponding to a PluginObject or this
+ // will crash. If the object is a PluginObject but the plugin has gone
+ // away (the object could still be alive because of a reference from JS),
+ // then the return value will be NULL.
+ static PluginObject* FromNPObject(NPObject* object);
+
+ // Allocates a plugin wrapper object and returns it as an NPObject. This is
+ // used internally only.
+ static NPObject* AllocateObjectWrapper();
+
+ private:
+ struct NPObjectWrapper;
+
+ // This object must be created using the CreateObject function of the which
+ // will set up the correct NPObject.
+ //
+ // The NPObjectWrapper (an NPObject) should already have the reference
+ // incremented on it, and this class will take ownership of that reference.
+ PluginObject(PluginInstanceImpl* instance,
+ NPObjectWrapper* object_wrapper,
+ const PPP_Class_Deprecated* ppp_class,
+ void* ppp_class_data);
+
+ PluginInstanceImpl* instance_;
+
+ // Holds a pointer to the NPObject wrapper backing the var. This class
+ // derives from NPObject and we hold a reference to it, so it must be
+ // refcounted. When the type is not an object, this value will be NULL.
+ //
+ // We don't actually own this pointer, it's the NPObject that actually
+ // owns us.
+ NPObjectWrapper* object_wrapper_;
+
+ const PPP_Class_Deprecated* ppp_class_;
+ void* ppp_class_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginObject);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PLUGIN_OBJECT_H_
diff --git a/content/renderer/pepper/ppapi_interface_factory.cc b/content/renderer/pepper/ppapi_interface_factory.cc
new file mode 100644
index 0000000..acb6858
--- /dev/null
+++ b/content/renderer/pepper/ppapi_interface_factory.cc
@@ -0,0 +1,62 @@
+// 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/pepper/ppapi_interface_factory.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace webkit {
+namespace ppapi {
+
+base::LazyInstance<PpapiInterfaceFactoryManager>
+ g_ppapi_interface_factory_manager = LAZY_INSTANCE_INITIALIZER;
+
+PpapiInterfaceFactoryManager::PpapiInterfaceFactoryManager() {
+}
+
+PpapiInterfaceFactoryManager::~PpapiInterfaceFactoryManager() {
+}
+
+void PpapiInterfaceFactoryManager::RegisterFactory(InterfaceFactory* factory) {
+ DCHECK(std::find(interface_factory_list_.begin(),
+ interface_factory_list_.end(), factory) ==
+ interface_factory_list_.end());
+ interface_factory_list_.push_back(factory);
+}
+
+void PpapiInterfaceFactoryManager::UnregisterFactory(
+ InterfaceFactory* factory) {
+ FactoryList::iterator index =
+ std::find(interface_factory_list_.begin(), interface_factory_list_.end(),
+ factory);
+ if (index != interface_factory_list_.end())
+ interface_factory_list_.erase(index);
+}
+
+const void* PpapiInterfaceFactoryManager::GetInterface(
+ const std::string& interface_name) {
+ FactoryList::iterator index;
+
+ const void* ppapi_interface = NULL;
+
+ for (index = interface_factory_list_.begin();
+ index != interface_factory_list_.end();
+ ++index) {
+ ppapi_interface = (*index)(interface_name);
+ if (ppapi_interface)
+ break;
+ }
+ return ppapi_interface;
+}
+
+// static
+PpapiInterfaceFactoryManager* PpapiInterfaceFactoryManager::GetInstance() {
+ return &g_ppapi_interface_factory_manager.Get();
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/content/renderer/pepper/ppapi_interface_factory.h b/content/renderer/pepper/ppapi_interface_factory.h
new file mode 100644
index 0000000..6654f61
--- /dev/null
+++ b/content/renderer/pepper/ppapi_interface_factory.h
@@ -0,0 +1,56 @@
+// 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_PEPPER_PLUGIN_INTERFACE_FACTORY_H_
+#define CONTENT_RENDERER_PEPPER_PLUGIN_INTERFACE_FACTORY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "content/common/content_export.h"
+
+namespace webkit {
+namespace ppapi {
+
+// This class provides functionality to manage custom PPAPI interface
+// factories.
+class PpapiInterfaceFactoryManager {
+ public:
+ typedef const void* (InterfaceFactory)(const std::string& interface_name);
+
+ // Registers a custom PPAPI interface factory.
+ CONTENT_EXPORT void RegisterFactory(InterfaceFactory* factory);
+
+ // Unregisters the custom PPAPI interface factory passed in.
+ CONTENT_EXPORT void UnregisterFactory(InterfaceFactory* factory);
+
+ // Returns a pointer to the interface identified by the name passed in.
+ // Returns NULL if no factory handles this interface.
+ const void* GetInterface(const std::string& interface_name);
+
+ // Returns a pointer to the global instance of the
+ // PpapiInterfaceFactoryManager class.
+ CONTENT_EXPORT static PpapiInterfaceFactoryManager* GetInstance();
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<PpapiInterfaceFactoryManager>;
+
+ PpapiInterfaceFactoryManager();
+ ~PpapiInterfaceFactoryManager();
+
+ typedef std::vector<InterfaceFactory*> FactoryList;
+
+ // List of registered factories.
+ FactoryList interface_factory_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(PpapiInterfaceFactoryManager);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PLUGIN_INTERFACE_FACTORY_H_
+
diff --git a/content/renderer/pepper/ppapi_plugin_instance_impl.cc b/content/renderer/pepper/ppapi_plugin_instance_impl.cc
new file mode 100644
index 0000000..229c31e
--- /dev/null
+++ b/content/renderer/pepper/ppapi_plugin_instance_impl.cc
@@ -0,0 +1,2726 @@
+// 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/ppapi_plugin_instance_impl.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.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/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/layers/texture_layer.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/content_decryptor_delegate.h"
+#include "content/renderer/pepper/event_conversion.h"
+#include "content/renderer/pepper/fullscreen_container.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/message_channel.h"
+#include "content/renderer/pepper/npapi_glue.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/plugin_object.h"
+#include "content/renderer/pepper/ppb_buffer_impl.h"
+#include "content/renderer/pepper/ppb_file_ref_impl.h"
+#include "content/renderer/pepper/ppb_graphics_3d_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/pepper/ppp_pdf.h"
+#include "content/renderer/pepper/url_request_info_util.h"
+#include "ppapi/c/dev/ppb_find_dev.h"
+#include "ppapi/c/dev/ppb_zoom_dev.h"
+#include "ppapi/c/dev/ppp_find_dev.h"
+#include "ppapi/c/dev/ppp_selection_dev.h"
+#include "ppapi/c/dev/ppp_text_input_dev.h"
+#include "ppapi/c/dev/ppp_zoom_dev.h"
+#include "ppapi/c/pp_rect.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_gamepad.h"
+#include "ppapi/c/ppp_input_event.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/c/ppp_messaging.h"
+#include "ppapi/c/ppp_mouse_lock.h"
+#include "ppapi/c/private/ppp_instance_private.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"
+#include "ppapi/shared_impl/ppb_view_shared.h"
+#include "ppapi/shared_impl/ppp_instance_combined.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/shared_impl/time_conversion.h"
+#include "ppapi/shared_impl/url_request_info_data.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_buffer_api.h"
+#include "printing/metafile.h"
+#include "printing/metafile_skia_wrapper.h"
+#include "printing/units.h"
+#include "skia/ext/platform_canvas.h"
+#include "skia/ext/platform_device.h"
+#include "third_party/WebKit/public/platform/WebGamepads.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"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
+#include "third_party/WebKit/public/web/WebCursorInfo.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/WebKit/public/web/WebPrintParams.h"
+#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "ui/base/range/range.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+#include "v8/include/v8.h"
+#include "webkit/plugins/plugin_constants.h"
+#include "webkit/plugins/sad_plugin.h"
+#include "webkit/renderer/compositor_bindings/web_layer_impl.h"
+
+#if defined(OS_MACOSX)
+#include "printing/metafile_impl.h"
+#endif // defined(OS_MACOSX)
+
+#if defined(OS_WIN)
+#include "base/metrics/histogram.h"
+#include "base/win/windows_version.h"
+#include "skia/ext/platform_canvas.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+#include "ui/gfx/gdi_util.h"
+#endif
+
+using base::StringPrintf;
+using ppapi::InputEventData;
+using ppapi::PpapiGlobals;
+using ppapi::PPB_InputEvent_Shared;
+using ppapi::PPB_View_Shared;
+using ppapi::PPP_Instance_Combined;
+using ppapi::Resource;
+using ppapi::ScopedPPResource;
+using ppapi::StringVar;
+using ppapi::TrackedCallback;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Buffer_API;
+using ppapi::thunk::PPB_Gamepad_API;
+using ppapi::thunk::PPB_Graphics2D_API;
+using ppapi::thunk::PPB_Graphics3D_API;
+using ppapi::thunk::PPB_ImageData_API;
+using ppapi::Var;
+using ppapi::ArrayBufferVar;
+using ppapi::ViewData;
+using WebKit::WebBindings;
+using WebKit::WebCanvas;
+using WebKit::WebCursorInfo;
+using WebKit::WebDocument;
+using WebKit::WebElement;
+using WebKit::WebFrame;
+using WebKit::WebInputEvent;
+using WebKit::WebPlugin;
+using WebKit::WebPluginContainer;
+using WebKit::WebPrintParams;
+using WebKit::WebPrintScalingOption;
+using WebKit::WebScopedUserGesture;
+using WebKit::WebString;
+using WebKit::WebURLError;
+using WebKit::WebURLLoader;
+using WebKit::WebURLLoaderClient;
+using WebKit::WebURLRequest;
+using WebKit::WebURLResponse;
+using WebKit::WebUserGestureIndicator;
+using WebKit::WebUserGestureToken;
+using WebKit::WebView;
+
+namespace webkit {
+namespace ppapi {
+
+#if defined(OS_WIN)
+// Exported by pdf.dll
+typedef bool (*RenderPDFPageToDCProc)(
+ const unsigned char* pdf_buffer, int buffer_size, int page_number, HDC dc,
+ int dpi_x, int dpi_y, int bounds_origin_x, int bounds_origin_y,
+ int bounds_width, int bounds_height, bool fit_to_bounds,
+ bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds,
+ bool autorotate);
+
+void DrawEmptyRectangle(HDC dc) {
+ // TODO(sanjeevr): This is a temporary hack. If we output a JPEG
+ // to the EMF, the EnumEnhMetaFile call fails in the browser
+ // process. The failure also happens if we output nothing here.
+ // We need to investigate the reason for this failure and fix it.
+ // In the meantime this temporary hack of drawing an empty
+ // rectangle in the DC gets us by.
+ Rectangle(dc, 0, 0, 0, 0);
+}
+#endif // defined(OS_WIN)
+
+namespace {
+
+// 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);
+
+// 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-
+// unaware plugins (e.g., PPAPI Flash or PDF plugin for M16).
+// Plugins need to explicitly opt out the text input mode if they know
+// 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);
+// Do not assert WebCursorInfo::TypeCustom == PP_CURSORTYPE_CUSTOM;
+// PP_CURSORTYPE_CUSTOM is pinned to allow new cursor types.
+
+COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(WebKit::WebPrintScalingOptionNone,
+ PP_PRINTSCALINGOPTION_NONE);
+COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(
+ WebKit::WebPrintScalingOptionFitToPrintableArea,
+ PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA);
+COMPILE_ASSERT_PRINT_SCALING_MATCHING_ENUM(
+ WebKit::WebPrintScalingOptionSourceSize, PP_PRINTSCALINGOPTION_SOURCE_SIZE);
+
+// Sets |*security_origin| to be the WebKit security origin associated with the
+// document containing the given plugin instance. On success, returns true. If
+// the instance is invalid, returns false and |*security_origin| will be
+// unchanged.
+bool SecurityOriginForInstance(PP_Instance instance_id,
+ WebKit::WebSecurityOrigin* security_origin) {
+ PluginInstanceImpl* instance = HostGlobals::Get()->GetInstance(instance_id);
+ if (!instance)
+ return false;
+
+ WebElement plugin_element = instance->container()->element();
+ *security_origin = plugin_element.document().securityOrigin();
+ return true;
+}
+
+// Convert the given vector to an array of C-strings. The strings in the
+// returned vector are only guaranteed valid so long as the vector of strings
+// is not modified.
+scoped_ptr<const char*[]> StringVectorToArgArray(
+ const std::vector<std::string>& vector) {
+ scoped_ptr<const char*[]> array(new const char*[vector.size()]);
+ for (size_t i = 0; i < vector.size(); ++i)
+ array[i] = vector[i].c_str();
+ return array.Pass();
+}
+
+} // namespace
+
+// static
+PluginInstanceImpl* PluginInstanceImpl::Create(PluginDelegate* delegate,
+ content::RenderView* render_view,
+ PluginModule* module,
+ WebPluginContainer* container,
+ const GURL& plugin_url) {
+ base::Callback<const void*(const char*)> get_plugin_interface_func =
+ base::Bind(&PluginModule::GetPluginInterface, module);
+ PPP_Instance_Combined* ppp_instance_combined =
+ PPP_Instance_Combined::Create(get_plugin_interface_func);
+ if (!ppp_instance_combined)
+ return NULL;
+ return new PluginInstanceImpl(delegate, render_view, module,
+ ppp_instance_combined, container, plugin_url);
+}
+
+PluginInstanceImpl::NaClDocumentLoader::NaClDocumentLoader()
+ : finished_loading_(false) {
+}
+
+PluginInstanceImpl::NaClDocumentLoader::~NaClDocumentLoader(){
+}
+
+void PluginInstanceImpl::NaClDocumentLoader::ReplayReceivedData(
+ WebURLLoaderClient* document_loader) {
+ for (std::list<std::string>::iterator it = data_.begin();
+ it != data_.end(); ++it) {
+ document_loader->didReceiveData(NULL, it->c_str(), it->length(),
+ 0 /* encoded_data_length */);
+ }
+ if (finished_loading_) {
+ document_loader->didFinishLoading(NULL,
+ 0 /* finish_time */);
+ }
+ if (error_.get()) {
+ document_loader->didFail(NULL, *error_);
+ }
+}
+
+void PluginInstanceImpl::NaClDocumentLoader::didReceiveData(
+ WebURLLoader* loader,
+ const char* data,
+ int data_length,
+ int encoded_data_length) {
+ data_.push_back(std::string(data, data_length));
+}
+
+void PluginInstanceImpl::NaClDocumentLoader::didFinishLoading(
+ WebURLLoader* loader,
+ double finish_time) {
+ DCHECK(!finished_loading_);
+ finished_loading_ = true;
+}
+
+void PluginInstanceImpl::NaClDocumentLoader::didFail(
+ WebURLLoader* loader,
+ const WebURLError& error) {
+ DCHECK(!error_.get());
+ error_.reset(new WebURLError(error));
+}
+
+PluginInstanceImpl::GamepadImpl::GamepadImpl(PluginDelegate* delegate)
+ : Resource(::ppapi::Resource::Untracked()),
+ delegate_(delegate) {
+}
+
+PluginInstanceImpl::GamepadImpl::~GamepadImpl() {
+}
+
+PPB_Gamepad_API* PluginInstanceImpl::GamepadImpl::AsPPB_Gamepad_API() {
+ return this;
+}
+
+void PluginInstanceImpl::GamepadImpl::Sample(PP_Instance instance,
+ PP_GamepadsSampleData* data) {
+ WebKit::WebGamepads webkit_data;
+ delegate_->SampleGamepads(&webkit_data);
+ ConvertWebKitGamepadData(
+ *reinterpret_cast<const ::ppapi::WebKitGamepads*>(&webkit_data), data);
+}
+
+PluginInstanceImpl::PluginInstanceImpl(
+ PluginDelegate* delegate,
+ content::RenderView* render_view,
+ PluginModule* module,
+ ::ppapi::PPP_Instance_Combined* instance_interface,
+ WebPluginContainer* container,
+ const GURL& plugin_url)
+ : delegate_(delegate),
+ render_view_(render_view),
+ module_(module),
+ instance_interface_(instance_interface),
+ pp_instance_(0),
+ container_(container),
+ layer_bound_to_fullscreen_(false),
+ plugin_url_(plugin_url),
+ full_frame_(false),
+ sent_initial_did_change_view_(false),
+ view_change_weak_ptr_factory_(this),
+ bound_graphics_2d_platform_(NULL),
+ has_webkit_focus_(false),
+ has_content_area_focus_(false),
+ find_identifier_(-1),
+ plugin_find_interface_(NULL),
+ plugin_input_event_interface_(NULL),
+ plugin_messaging_interface_(NULL),
+ plugin_mouse_lock_interface_(NULL),
+ plugin_pdf_interface_(NULL),
+ plugin_private_interface_(NULL),
+ plugin_selection_interface_(NULL),
+ plugin_textinput_interface_(NULL),
+ plugin_zoom_interface_(NULL),
+ checked_for_plugin_input_event_interface_(false),
+ checked_for_plugin_messaging_interface_(false),
+ checked_for_plugin_pdf_interface_(false),
+ gamepad_impl_(new GamepadImpl(delegate)),
+ plugin_print_interface_(NULL),
+ plugin_graphics_3d_interface_(NULL),
+ always_on_top_(false),
+ fullscreen_container_(NULL),
+ flash_fullscreen_(false),
+ desired_fullscreen_state_(false),
+ sad_plugin_(NULL),
+ input_event_mask_(0),
+ filtered_input_event_mask_(0),
+ text_input_type_(kPluginDefaultTextInputType),
+ text_input_caret_(0, 0, 0, 0),
+ text_input_caret_bounds_(0, 0, 0, 0),
+ text_input_caret_set_(false),
+ selection_caret_(0),
+ selection_anchor_(0),
+ pending_user_gesture_(0.0),
+ document_loader_(NULL),
+ nacl_document_load_(false),
+ npp_(new NPP_t),
+ isolate_(v8::Isolate::GetCurrent()) {
+ pp_instance_ = HostGlobals::Get()->AddInstance(this);
+
+ memset(&current_print_settings_, 0, sizeof(current_print_settings_));
+ DCHECK(delegate);
+ module_->InstanceCreated(this);
+ delegate_->InstanceCreated(this);
+
+ view_data_.is_page_visible = delegate->IsPageVisible();
+ resource_creation_ = delegate_->CreateResourceCreationAPI(this);
+
+ // TODO(bbudge) remove this when the trusted NaCl plugin has been removed.
+ // We must defer certain plugin events for NaCl instances since we switch
+ // from the in-process to the out-of-process proxy after instantiating them.
+ if (module->name() == "Native Client")
+ nacl_document_load_ = true;
+}
+
+PluginInstanceImpl::~PluginInstanceImpl() {
+ DCHECK(!fullscreen_container_);
+
+ // Force-unbind any Graphics. In the case of Graphics2D, if the plugin
+ // leaks the graphics 2D, it may actually get cleaned up after our
+ // destruction, so we need its pointers to be up-to-date.
+ BindGraphics(pp_instance(), 0);
+
+ // Free all the plugin objects. This will automatically clear the back-
+ // pointer from the NPObject so WebKit can't call into the plugin any more.
+ //
+ // Swap out the set so we can delete from it (the objects will try to
+ // unregister themselves inside the delete call).
+ PluginObjectSet plugin_object_copy;
+ live_plugin_objects_.swap(plugin_object_copy);
+ for (PluginObjectSet::iterator i = plugin_object_copy.begin();
+ i != plugin_object_copy.end(); ++i)
+ delete *i;
+
+ if (TrackedCallback::IsPending(lock_mouse_callback_))
+ lock_mouse_callback_->Abort();
+
+ delegate_->InstanceDeleted(this);
+ module_->InstanceDeleted(this);
+ // If we switched from the NaCl plugin module, notify it too.
+ if (original_module_.get())
+ original_module_->InstanceDeleted(this);
+
+ // 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_);
+}
+
+// NOTE: Any of these methods that calls into the plugin needs to take into
+// account that the plugin may use Var to remove the <embed> from the DOM, which
+// will make the WebPluginImpl drop its reference, usually the last one. If a
+// method needs to access a member of the instance after the call has returned,
+// then it needs to keep its own reference on the stack.
+
+void PluginInstanceImpl::Delete() {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ // 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.
+ message_channel_->SetPassthroughObject(NULL);
+ // 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_)
+ original_instance_interface_->DidDestroy(pp_instance());
+ 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();
+
+ if (fullscreen_container_) {
+ fullscreen_container_->Destroy();
+ fullscreen_container_ = NULL;
+ }
+ bound_graphics_3d_ = NULL;
+ UpdateLayer();
+ container_ = NULL;
+}
+
+void PluginInstanceImpl::Paint(WebCanvas* canvas,
+ const gfx::Rect& plugin_rect,
+ const gfx::Rect& paint_rect) {
+ TRACE_EVENT0("ppapi", "PluginInstance::Paint");
+ if (module()->is_crashed()) {
+ // Crashed plugin painting.
+ if (!sad_plugin_) // Lazily initialize bitmap.
+ sad_plugin_ = delegate_->GetSadPluginBitmap();
+ if (sad_plugin_)
+ webkit::PaintSadPlugin(canvas, plugin_rect, *sad_plugin_);
+ return;
+ }
+
+ PluginDelegate::PlatformGraphics2D* bound_graphics_2d = GetBoundGraphics2D();
+ if (bound_graphics_2d)
+ bound_graphics_2d->Paint(canvas, plugin_rect, paint_rect);
+}
+
+void PluginInstanceImpl::InvalidateRect(const gfx::Rect& rect) {
+ if (fullscreen_container_) {
+ if (rect.IsEmpty())
+ fullscreen_container_->Invalidate();
+ else
+ fullscreen_container_->InvalidateRect(rect);
+ } else {
+ if (!container_ ||
+ view_data_.rect.size.width == 0 || view_data_.rect.size.height == 0)
+ return; // Nothing to do.
+ if (rect.IsEmpty())
+ container_->invalidate();
+ else
+ container_->invalidateRect(rect);
+ }
+}
+
+void PluginInstanceImpl::ScrollRect(int dx, int dy, const gfx::Rect& rect) {
+ if (fullscreen_container_) {
+ fullscreen_container_->ScrollRect(dx, dy, rect);
+ } else {
+ if (full_frame_ && !IsViewAccelerated()) {
+ container_->scrollRect(dx, dy, rect);
+ } else {
+ // Can't do optimized scrolling since there could be other elements on top
+ // of us or the view renders via the accelerated compositor which is
+ // incompatible with the move and backfill scrolling model.
+ InvalidateRect(rect);
+ }
+ }
+}
+
+void PluginInstanceImpl::CommitBackingTexture() {
+ if (texture_layer_.get())
+ texture_layer_->SetNeedsDisplay();
+}
+
+void PluginInstanceImpl::InstanceCrashed() {
+ // Force free all resources and vars.
+ HostGlobals::Get()->InstanceCrashed(pp_instance());
+
+ // Free any associated graphics.
+ SetFullscreen(false);
+ FlashSetFullscreen(false, false);
+ // Unbind current 2D or 3D graphics context.
+ BindGraphics(pp_instance(), 0);
+ InvalidateRect(gfx::Rect());
+
+ delegate()->PluginCrashed(this);
+}
+
+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 PluginInstanceImpl::Initialize(const std::vector<std::string>& arg_names,
+ const std::vector<std::string>& arg_values,
+ bool full_frame) {
+ message_channel_.reset(new MessageChannel(this));
+
+ full_frame_ = full_frame;
+
+ UpdateTouchEventRequest();
+ container_->setWantsWheelEvents(IsAcceptingWheelEvents());
+
+ SetGPUHistogram(delegate_->GetPreferences(), arg_names, arg_values);
+
+ argn_ = arg_names;
+ argv_ = arg_values;
+ scoped_ptr<const char*[]> argn_array(StringVectorToArgArray(argn_));
+ scoped_ptr<const char*[]> argv_array(StringVectorToArgArray(argv_));
+ bool success = PP_ToBool(instance_interface_->DidCreate(pp_instance(),
+ argn_.size(),
+ argn_array.get(),
+ argv_array.get()));
+ if (success)
+ message_channel_->StopQueueingJavaScriptMessages();
+ return success;
+}
+
+bool PluginInstanceImpl::HandleDocumentLoad(
+ const WebKit::WebURLResponse& response) {
+ DCHECK(!document_loader_);
+ if (!nacl_document_load_) {
+ if (module()->is_crashed()) {
+ // Don't create a resource for a crashed plugin.
+ container()->element().document().frame()->stopLoading();
+ return false;
+ }
+ delegate()->HandleDocumentLoad(this, response);
+ // If the load was not abandoned, document_loader_ will now be set. It's
+ // possible that the load was canceled by now and document_loader_ was
+ // already nulled out.
+ } else {
+ // The NaCl proxy isn't available, so save the response and record document
+ // load notifications for later replay.
+ nacl_document_response_ = response;
+ nacl_document_loader_.reset(new NaClDocumentLoader());
+ document_loader_ = nacl_document_loader_.get();
+ }
+ return true;
+}
+
+bool PluginInstanceImpl::SendCompositionEventToPlugin(
+ PP_InputEvent_Type type, const base::string16& text) {
+ std::vector<WebKit::WebCompositionUnderline> empty;
+ return SendCompositionEventWithUnderlineInformationToPlugin(
+ type, text, empty, static_cast<int>(text.size()),
+ static_cast<int>(text.size()));
+}
+
+bool PluginInstanceImpl::SendCompositionEventWithUnderlineInformationToPlugin(
+ PP_InputEvent_Type type,
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+
+ if (!LoadInputEventInterface())
+ return false;
+
+ PP_InputEvent_Class event_class = PP_INPUTEVENT_CLASS_IME;
+ if (!(filtered_input_event_mask_ & event_class) &&
+ !(input_event_mask_ & event_class))
+ return false;
+
+ ::ppapi::InputEventData event;
+ event.event_type = type;
+ event.event_time_stamp = ::ppapi::TimeTicksToPPTimeTicks(
+ base::TimeTicks::Now());
+
+ // Convert UTF16 text to UTF8 with offset conversion.
+ std::vector<size_t> utf16_offsets;
+ utf16_offsets.push_back(selection_start);
+ utf16_offsets.push_back(selection_end);
+ for (size_t i = 0; i < underlines.size(); ++i) {
+ utf16_offsets.push_back(underlines[i].startOffset);
+ utf16_offsets.push_back(underlines[i].endOffset);
+ }
+ std::vector<size_t> utf8_offsets(utf16_offsets);
+ event.character_text = base::UTF16ToUTF8AndAdjustOffsets(text, &utf8_offsets);
+
+ // Set the converted selection range.
+ event.composition_selection_start = (utf8_offsets[0] == std::string::npos ?
+ event.character_text.size() : utf8_offsets[0]);
+ event.composition_selection_end = (utf8_offsets[1] == std::string::npos ?
+ event.character_text.size() : utf8_offsets[1]);
+
+ // Set the converted segmentation points.
+ // Be sure to add 0 and size(), and remove duplication or errors.
+ std::set<size_t> offset_set(utf8_offsets.begin()+2, utf8_offsets.end());
+ offset_set.insert(0);
+ offset_set.insert(event.character_text.size());
+ offset_set.erase(std::string::npos);
+ event.composition_segment_offsets.assign(offset_set.begin(),
+ offset_set.end());
+
+ // Set the composition target.
+ for (size_t i = 0; i < underlines.size(); ++i) {
+ if (underlines[i].thick) {
+ std::vector<uint32_t>::iterator it =
+ std::find(event.composition_segment_offsets.begin(),
+ event.composition_segment_offsets.end(),
+ utf8_offsets[2*i+2]);
+ if (it != event.composition_segment_offsets.end()) {
+ event.composition_target_segment =
+ it - event.composition_segment_offsets.begin();
+ break;
+ }
+ }
+ }
+
+ // Send the event.
+ bool handled = false;
+ if (filtered_input_event_mask_ & event_class)
+ event.is_filtered = true;
+ else
+ handled = true; // Unfiltered events are assumed to be handled.
+ scoped_refptr<PPB_InputEvent_Shared> event_resource(
+ new PPB_InputEvent_Shared(::ppapi::OBJECT_IS_IMPL, pp_instance(), event));
+ handled |= PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
+ pp_instance(), event_resource->pp_resource()));
+ return handled;
+}
+
+void PluginInstanceImpl::RequestInputEventsHelper(uint32_t event_classes) {
+ if (event_classes & PP_INPUTEVENT_CLASS_TOUCH)
+ UpdateTouchEventRequest();
+ if (event_classes & PP_INPUTEVENT_CLASS_WHEEL)
+ container_->setWantsWheelEvents(IsAcceptingWheelEvents());
+}
+
+bool PluginInstanceImpl::HandleCompositionStart(const base::string16& text) {
+ return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_COMPOSITION_START,
+ text);
+}
+
+bool PluginInstanceImpl::HandleCompositionUpdate(
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end) {
+ return SendCompositionEventWithUnderlineInformationToPlugin(
+ PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE,
+ text, underlines, selection_start, selection_end);
+}
+
+bool PluginInstanceImpl::HandleCompositionEnd(const base::string16& text) {
+ return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_COMPOSITION_END,
+ text);
+}
+
+bool PluginInstanceImpl::HandleTextInput(const base::string16& text) {
+ return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_TEXT,
+ text);
+}
+
+void PluginInstanceImpl::GetSurroundingText(base::string16* text,
+ ui::Range* range) const {
+ std::vector<size_t> offsets;
+ offsets.push_back(selection_anchor_);
+ offsets.push_back(selection_caret_);
+ *text = base::UTF8ToUTF16AndAdjustOffsets(surrounding_text_, &offsets);
+ range->set_start(offsets[0] == base::string16::npos ? text->size()
+ : offsets[0]);
+ range->set_end(offsets[1] == base::string16::npos ? text->size()
+ : offsets[1]);
+}
+
+bool PluginInstanceImpl::IsPluginAcceptingCompositionEvents() const {
+ return (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_IME) ||
+ (input_event_mask_ & PP_INPUTEVENT_CLASS_IME);
+}
+
+gfx::Rect PluginInstanceImpl::GetCaretBounds() const {
+ if (!text_input_caret_set_) {
+ // If it is never set by the plugin, use the bottom left corner.
+ return gfx::Rect(view_data_.rect.point.x,
+ view_data_.rect.point.y + view_data_.rect.size.height,
+ 0, 0);
+ }
+
+ // TODO(kinaba) Take CSS transformation into accont.
+ // TODO(kinaba) Take bounding_box into account. On some platforms, an
+ // "exclude rectangle" where candidate window must avoid the region can be
+ // passed to IME. Currently, we pass only the caret rectangle because
+ // it is the only information supported uniformly in Chromium.
+ gfx::Rect caret(text_input_caret_);
+ caret.Offset(view_data_.rect.point.x, view_data_.rect.point.y);
+ return caret;
+}
+
+bool PluginInstanceImpl::HandleInputEvent(const WebKit::WebInputEvent& event,
+ WebCursorInfo* cursor_info) {
+ TRACE_EVENT0("ppapi", "PluginInstanceImpl::HandleInputEvent");
+
+ if (WebInputEvent::isMouseEventType(event.type))
+ delegate()->DidReceiveMouseEvent(this);
+
+ // Don't dispatch input events to crashed plugins.
+ if (module()->is_crashed())
+ return false;
+
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+
+ bool rv = false;
+ if (LoadInputEventInterface()) {
+ PP_InputEvent_Class event_class = ClassifyInputEvent(event.type);
+ if (!event_class)
+ return false;
+
+ if ((filtered_input_event_mask_ & event_class) ||
+ (input_event_mask_ & event_class)) {
+ // Actually send the event.
+ std::vector< ::ppapi::InputEventData > events;
+ CreateInputEventData(event, &events);
+
+ // Allow the user gesture to be pending after the plugin handles the
+ // event. This allows out-of-process plugins to respond to the user
+ // gesture after processing has finished here.
+ if (WebUserGestureIndicator::isProcessingUserGesture()) {
+ pending_user_gesture_ =
+ ::ppapi::EventTimeToPPTimeTicks(event.timeStampSeconds);
+ pending_user_gesture_token_ =
+ WebUserGestureIndicator::currentUserGestureToken();
+ pending_user_gesture_token_.setOutOfProcess();
+ }
+
+ // Each input event may generate more than one PP_InputEvent.
+ for (size_t i = 0; i < events.size(); i++) {
+ if (filtered_input_event_mask_ & event_class)
+ events[i].is_filtered = true;
+ else
+ rv = true; // Unfiltered events are assumed to be handled.
+ scoped_refptr<PPB_InputEvent_Shared> event_resource(
+ new PPB_InputEvent_Shared(::ppapi::OBJECT_IS_IMPL,
+ pp_instance(), events[i]));
+
+ rv |= PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
+ pp_instance(), event_resource->pp_resource()));
+ }
+ }
+ }
+
+ if (cursor_)
+ *cursor_info = *cursor_;
+ return rv;
+}
+
+void PluginInstanceImpl::HandleMessage(PP_Var message) {
+ TRACE_EVENT0("ppapi", "PluginInstanceImpl::HandleMessage");
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadMessagingInterface())
+ return;
+ plugin_messaging_interface_->HandleMessage(pp_instance(), message);
+}
+
+PP_Var PluginInstanceImpl::GetInstanceObject() {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+
+ // If the plugin supports the private instance interface, try to retrieve its
+ // instance object.
+ if (LoadPrivateInterface())
+ return plugin_private_interface_->GetInstanceObject(pp_instance());
+ return PP_MakeUndefined();
+}
+
+void PluginInstanceImpl::ViewChanged(
+ const gfx::Rect& position,
+ const gfx::Rect& clip,
+ 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
+ // consistent since this is given to the plugin, so force everything to 0
+ // in the "everything is clipped" case.
+ gfx::Rect new_clip;
+ if (!clip.IsEmpty())
+ new_clip = clip;
+
+ cut_outs_rects_ = cut_outs_rects;
+
+ view_data_.rect = PP_FromGfxRect(position);
+ view_data_.clip_rect = PP_FromGfxRect(clip);
+ view_data_.device_scale = container_->deviceScaleFactor();
+ view_data_.css_scale = container_->pageZoomFactor() *
+ container_->pageScaleFactor();
+
+ if (desired_fullscreen_state_ || view_data_.is_fullscreen) {
+ WebElement element = container_->element();
+ WebDocument document = element.document();
+ bool is_fullscreen_element = (element == document.fullScreenElement());
+ if (!view_data_.is_fullscreen && desired_fullscreen_state_ &&
+ delegate()->IsInFullscreenMode() && is_fullscreen_element) {
+ // Entered fullscreen. Only possible via SetFullscreen().
+ view_data_.is_fullscreen = true;
+ } else if (view_data_.is_fullscreen && !is_fullscreen_element) {
+ // Exited fullscreen. Possible via SetFullscreen() or F11/link,
+ // so desired_fullscreen_state might be out-of-date.
+ desired_fullscreen_state_ = false;
+ view_data_.is_fullscreen = false;
+
+ // This operation will cause the plugin to re-layout which will send more
+ // DidChangeView updates. Schedule an asynchronous update and suppress
+ // notifications until that completes to avoid sending intermediate sizes
+ // to the plugins.
+ ScheduleAsyncDidChangeView();
+
+ // Reset the size attributes that we hacked to fill in the screen and
+ // retrigger ViewChanged. Make sure we don't forward duplicates of
+ // this view to the plugin.
+ ResetSizeAttributesAfterFullscreen();
+ return;
+ }
+ }
+
+ UpdateFlashFullscreenState(fullscreen_container_ != NULL);
+
+ SendDidChangeView();
+}
+
+void PluginInstanceImpl::SetWebKitFocus(bool has_focus) {
+ if (has_webkit_focus_ == has_focus)
+ return;
+
+ bool old_plugin_focus = PluginHasFocus();
+ has_webkit_focus_ = has_focus;
+ if (PluginHasFocus() != old_plugin_focus)
+ SendFocusChangeNotification();
+}
+
+void PluginInstanceImpl::SetContentAreaFocus(bool has_focus) {
+ if (has_content_area_focus_ == has_focus)
+ return;
+
+ bool old_plugin_focus = PluginHasFocus();
+ has_content_area_focus_ = has_focus;
+ if (PluginHasFocus() != old_plugin_focus)
+ SendFocusChangeNotification();
+}
+
+void PluginInstanceImpl::PageVisibilityChanged(bool is_visible) {
+ if (is_visible == view_data_.is_page_visible)
+ return; // Nothing to do.
+ view_data_.is_page_visible = is_visible;
+
+ // If the initial DidChangeView notification hasn't been sent to the plugin,
+ // let it pass the visibility state for us, instead of sending a notification
+ // immediately. It is possible that PluginInstanceImpl::ViewChanged() hasn't
+ // been called for the first time. In that case, most of the fields in
+ // |view_data_| haven't been properly initialized.
+ if (sent_initial_did_change_view_)
+ SendDidChangeView();
+}
+
+void PluginInstanceImpl::ViewWillInitiatePaint() {
+ if (GetBoundGraphics2D())
+ GetBoundGraphics2D()->ViewWillInitiatePaint();
+ else if (bound_graphics_3d_.get())
+ bound_graphics_3d_->ViewWillInitiatePaint();
+}
+
+void PluginInstanceImpl::ViewInitiatedPaint() {
+ if (GetBoundGraphics2D())
+ GetBoundGraphics2D()->ViewInitiatedPaint();
+ else if (bound_graphics_3d_.get())
+ bound_graphics_3d_->ViewInitiatedPaint();
+}
+
+void PluginInstanceImpl::ViewFlushedPaint() {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (GetBoundGraphics2D())
+ GetBoundGraphics2D()->ViewFlushedPaint();
+ else if (bound_graphics_3d_.get())
+ bound_graphics_3d_->ViewFlushedPaint();
+}
+
+bool PluginInstanceImpl::GetBitmapForOptimizedPluginPaint(
+ const gfx::Rect& paint_bounds,
+ TransportDIB** dib,
+ gfx::Rect* location,
+ gfx::Rect* clip,
+ float* scale_factor) {
+ if (!always_on_top_)
+ return false;
+ if (!GetBoundGraphics2D() || !GetBoundGraphics2D()->IsAlwaysOpaque())
+ return false;
+
+ // We specifically want to compare against the area covered by the backing
+ // store when seeing if we cover the given paint bounds, since the backing
+ // store could be smaller than the declared plugin area.
+ PPB_ImageData_Impl* image_data = GetBoundGraphics2D()->ImageData();
+ // ImageDatas created by NaCl don't have a PlatformImage, so can't be
+ // optimized this way.
+ if (!image_data->PlatformImage())
+ return false;
+
+ gfx::Point plugin_origin = PP_ToGfxPoint(view_data_.rect.point);
+ gfx::Vector2d plugin_offset = plugin_origin.OffsetFromOrigin();
+ // Convert |paint_bounds| to be relative to the left-top corner of the plugin.
+ gfx::Rect relative_paint_bounds(paint_bounds);
+ relative_paint_bounds.Offset(-plugin_offset);
+
+ gfx::Rect pixel_plugin_backing_store_rect(
+ 0, 0, image_data->width(), image_data->height());
+ float scale = GetBoundGraphics2D()->GetScale();
+ gfx::Rect plugin_backing_store_rect = gfx::ToEnclosedRect(
+ gfx::ScaleRect(pixel_plugin_backing_store_rect, scale));
+
+ gfx::Rect clip_page = PP_ToGfxRect(view_data_.clip_rect);
+ gfx::Rect plugin_paint_rect =
+ gfx::IntersectRects(plugin_backing_store_rect, clip_page);
+ if (!plugin_paint_rect.Contains(relative_paint_bounds))
+ return false;
+
+ // Don't do optimized painting if the area to paint intersects with the
+ // cut-out rects, otherwise we will paint over them.
+ for (std::vector<gfx::Rect>::const_iterator iter = cut_outs_rects_.begin();
+ iter != cut_outs_rects_.end(); ++iter) {
+ if (relative_paint_bounds.Intersects(*iter))
+ return false;
+ }
+
+ *dib = image_data->PlatformImage()->GetTransportDIB();
+ plugin_backing_store_rect.Offset(plugin_offset);
+ *location = plugin_backing_store_rect;
+ clip_page.Offset(plugin_offset);
+ *clip = clip_page;
+ // The plugin scale factor is inverted, e.g. for a device scale factor of 2x
+ // the plugin scale factor is 0.5.
+ *scale_factor = 1.0 / scale;
+ return true;
+}
+
+base::string16 PluginInstanceImpl::GetSelectedText(bool html) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadSelectionInterface())
+ return base::string16();
+
+ PP_Var rv = plugin_selection_interface_->GetSelectedText(pp_instance(),
+ PP_FromBool(html));
+ StringVar* string = StringVar::FromPPVar(rv);
+ base::string16 selection;
+ if (string)
+ selection = UTF8ToUTF16(string->value());
+ // Release the ref the plugin transfered to us.
+ HostGlobals::Get()->GetVarTracker()->ReleaseVar(rv);
+ return selection;
+}
+
+base::string16 PluginInstanceImpl::GetLinkAtPosition(const gfx::Point& point) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadPdfInterface())
+ return base::string16();
+
+ PP_Point p;
+ p.x = point.x();
+ p.y = point.y();
+ PP_Var rv = plugin_pdf_interface_->GetLinkAtPosition(pp_instance(), p);
+ StringVar* string = StringVar::FromPPVar(rv);
+ base::string16 link;
+ if (string)
+ link = UTF8ToUTF16(string->value());
+ // Release the ref the plugin transfered to us.
+ PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(rv);
+ return link;
+}
+
+void PluginInstanceImpl::RequestSurroundingText(
+ size_t desired_number_of_characters) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadTextInputInterface())
+ return;
+ plugin_textinput_interface_->RequestSurroundingText(
+ pp_instance(), desired_number_of_characters);
+}
+
+void PluginInstanceImpl::Zoom(double factor, bool text_only) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadZoomInterface())
+ return;
+ plugin_zoom_interface_->Zoom(pp_instance(), factor, PP_FromBool(text_only));
+}
+
+bool PluginInstanceImpl::StartFind(const base::string16& search_text,
+ bool case_sensitive,
+ int identifier) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadFindInterface())
+ return false;
+ find_identifier_ = identifier;
+ return PP_ToBool(
+ plugin_find_interface_->StartFind(
+ pp_instance(),
+ UTF16ToUTF8(search_text.c_str()).c_str(),
+ PP_FromBool(case_sensitive)));
+}
+
+void PluginInstanceImpl::SelectFindResult(bool forward) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (LoadFindInterface())
+ plugin_find_interface_->SelectFindResult(pp_instance(),
+ PP_FromBool(forward));
+}
+
+void PluginInstanceImpl::StopFind() {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadFindInterface())
+ return;
+ find_identifier_ = -1;
+ plugin_find_interface_->StopFind(pp_instance());
+}
+
+bool PluginInstanceImpl::LoadFindInterface() {
+ if (!plugin_find_interface_) {
+ plugin_find_interface_ =
+ static_cast<const PPP_Find_Dev*>(module_->GetPluginInterface(
+ PPP_FIND_DEV_INTERFACE));
+ }
+
+ return !!plugin_find_interface_;
+}
+
+bool PluginInstanceImpl::LoadInputEventInterface() {
+ if (!checked_for_plugin_input_event_interface_) {
+ checked_for_plugin_input_event_interface_ = true;
+ plugin_input_event_interface_ =
+ static_cast<const PPP_InputEvent*>(module_->GetPluginInterface(
+ PPP_INPUT_EVENT_INTERFACE));
+ }
+ return !!plugin_input_event_interface_;
+}
+
+bool PluginInstanceImpl::LoadMessagingInterface() {
+ if (!checked_for_plugin_messaging_interface_) {
+ checked_for_plugin_messaging_interface_ = true;
+ plugin_messaging_interface_ =
+ static_cast<const PPP_Messaging*>(module_->GetPluginInterface(
+ PPP_MESSAGING_INTERFACE));
+ }
+ return !!plugin_messaging_interface_;
+}
+
+bool PluginInstanceImpl::LoadMouseLockInterface() {
+ if (!plugin_mouse_lock_interface_) {
+ plugin_mouse_lock_interface_ =
+ static_cast<const PPP_MouseLock*>(module_->GetPluginInterface(
+ PPP_MOUSELOCK_INTERFACE));
+ }
+
+ return !!plugin_mouse_lock_interface_;
+}
+
+bool PluginInstanceImpl::LoadPdfInterface() {
+ if (!checked_for_plugin_pdf_interface_) {
+ checked_for_plugin_pdf_interface_ = true;
+ plugin_pdf_interface_ =
+ static_cast<const PPP_Pdf_1*>(module_->GetPluginInterface(
+ PPP_PDF_INTERFACE_1));
+ }
+
+ return !!plugin_pdf_interface_;
+}
+
+bool PluginInstanceImpl::LoadPrintInterface() {
+ // Only check for the interface if the plugin has dev permission.
+ if (!module_->permissions().HasPermission(::ppapi::PERMISSION_DEV))
+ return false;
+ if (!plugin_print_interface_) {
+ plugin_print_interface_ = static_cast<const PPP_Printing_Dev*>(
+ module_->GetPluginInterface(PPP_PRINTING_DEV_INTERFACE));
+ }
+ return !!plugin_print_interface_;
+}
+
+bool PluginInstanceImpl::LoadPrivateInterface() {
+ // Only check for the interface if the plugin has private permission.
+ if (!module_->permissions().HasPermission(::ppapi::PERMISSION_PRIVATE))
+ return false;
+ if (!plugin_private_interface_) {
+ plugin_private_interface_ = static_cast<const PPP_Instance_Private*>(
+ module_->GetPluginInterface(PPP_INSTANCE_PRIVATE_INTERFACE));
+ }
+
+ return !!plugin_private_interface_;
+}
+
+bool PluginInstanceImpl::LoadSelectionInterface() {
+ if (!plugin_selection_interface_) {
+ plugin_selection_interface_ =
+ static_cast<const PPP_Selection_Dev*>(module_->GetPluginInterface(
+ PPP_SELECTION_DEV_INTERFACE));
+ }
+ return !!plugin_selection_interface_;
+}
+
+bool PluginInstanceImpl::LoadTextInputInterface() {
+ if (!plugin_textinput_interface_) {
+ plugin_textinput_interface_ =
+ static_cast<const PPP_TextInput_Dev*>(module_->GetPluginInterface(
+ PPP_TEXTINPUT_DEV_INTERFACE));
+ }
+
+ return !!plugin_textinput_interface_;
+}
+
+bool PluginInstanceImpl::LoadZoomInterface() {
+ if (!plugin_zoom_interface_) {
+ plugin_zoom_interface_ =
+ static_cast<const PPP_Zoom_Dev*>(module_->GetPluginInterface(
+ PPP_ZOOM_DEV_INTERFACE));
+ }
+
+ return !!plugin_zoom_interface_;
+}
+
+bool PluginInstanceImpl::PluginHasFocus() const {
+ return flash_fullscreen_ || (has_webkit_focus_ && has_content_area_focus_);
+}
+
+void PluginInstanceImpl::SendFocusChangeNotification() {
+ // This call can happen during PluginInstanceImpl destruction, because WebKit
+ // informs the plugin it's losing focus. See crbug.com/236574
+ if (!delegate_ || !instance_interface_)
+ return;
+ bool has_focus = PluginHasFocus();
+ delegate()->PluginFocusChanged(this, has_focus);
+ instance_interface_->DidChangeFocus(pp_instance(), PP_FromBool(has_focus));
+}
+
+void PluginInstanceImpl::UpdateTouchEventRequest() {
+ bool raw_touch = (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_TOUCH) ||
+ (input_event_mask_ & PP_INPUTEVENT_CLASS_TOUCH);
+ container_->requestTouchEventType(raw_touch ?
+ WebKit::WebPluginContainer::TouchEventRequestTypeRaw :
+ WebKit::WebPluginContainer::TouchEventRequestTypeSynthesizedMouse);
+}
+
+bool PluginInstanceImpl::IsAcceptingWheelEvents() const {
+ return (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_WHEEL) ||
+ (input_event_mask_ & PP_INPUTEVENT_CLASS_WHEEL);
+}
+
+void PluginInstanceImpl::ScheduleAsyncDidChangeView() {
+ if (view_change_weak_ptr_factory_.HasWeakPtrs())
+ return; // Already scheduled.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PluginInstanceImpl::SendAsyncDidChangeView,
+ view_change_weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PluginInstanceImpl::SendAsyncDidChangeView() {
+ // The bound callback that owns the weak pointer is still valid until after
+ // this function returns. SendDidChangeView checks HasWeakPtrs, so we need to
+ // invalidate them here.
+ // NOTE: If we ever want to have more than one pending callback, it should
+ // use a different factory, or we should have a different strategy here.
+ view_change_weak_ptr_factory_.InvalidateWeakPtrs();
+ SendDidChangeView();
+}
+
+void PluginInstanceImpl::SendDidChangeView() {
+ // Don't send DidChangeView to crashed plugins.
+ if (module()->is_crashed())
+ return;
+
+ if (view_change_weak_ptr_factory_.HasWeakPtrs() ||
+ (sent_initial_did_change_view_ &&
+ last_sent_view_data_.Equals(view_data_)))
+ return; // Nothing to update.
+
+ const PP_Size& size = view_data_.rect.size;
+ // Avoid sending a notification with a huge rectangle.
+ if (size.width < 0 || size.width > kMaxPluginSideLength ||
+ size.height < 0 || size.height > kMaxPluginSideLength ||
+ // We know this won't overflow due to above checks.
+ static_cast<uint32>(size.width) * static_cast<uint32>(size.height) >
+ kMaxPluginSize) {
+ return;
+ }
+
+ sent_initial_did_change_view_ = true;
+ last_sent_view_data_ = view_data_;
+ ScopedPPResource resource(
+ ScopedPPResource::PassRef(),
+ (new PPB_View_Shared(::ppapi::OBJECT_IS_IMPL,
+ pp_instance(), view_data_))->GetReference());
+
+ instance_interface_->DidChangeView(pp_instance(), resource,
+ &view_data_.rect,
+ &view_data_.clip_rect);
+}
+
+void PluginInstanceImpl::ReportGeometry() {
+ // If this call was delayed, we may have transitioned back to fullscreen in
+ // the mean time, so only report the geometry if we are actually in normal
+ // mode.
+ if (container_ && !fullscreen_container_ && !flash_fullscreen_)
+ container_->reportGeometry();
+}
+
+bool PluginInstanceImpl::GetPreferredPrintOutputFormat(
+ PP_PrintOutputFormat_Dev* format) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!LoadPrintInterface())
+ return false;
+ uint32_t supported_formats =
+ plugin_print_interface_->QuerySupportedFormats(pp_instance());
+ if (supported_formats & PP_PRINTOUTPUTFORMAT_PDF) {
+ *format = PP_PRINTOUTPUTFORMAT_PDF;
+ return true;
+ }
+ return false;
+}
+
+bool PluginInstanceImpl::SupportsPrintInterface() {
+ PP_PrintOutputFormat_Dev format;
+ return GetPreferredPrintOutputFormat(&format);
+}
+
+bool PluginInstanceImpl::IsPrintScalingDisabled() {
+ DCHECK(plugin_print_interface_);
+ if (!plugin_print_interface_)
+ return false;
+ return plugin_print_interface_->IsScalingDisabled(pp_instance()) == PP_TRUE;
+}
+
+int PluginInstanceImpl::PrintBegin(const WebPrintParams& print_params) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ PP_PrintOutputFormat_Dev format;
+ if (!GetPreferredPrintOutputFormat(&format)) {
+ // PrintBegin should not have been called since SupportsPrintInterface
+ // would have returned false;
+ NOTREACHED();
+ return 0;
+ }
+ int num_pages = 0;
+ PP_PrintSettings_Dev print_settings;
+ print_settings.printable_area = PP_FromGfxRect(print_params.printableArea);
+ print_settings.content_area = PP_FromGfxRect(print_params.printContentArea);
+ print_settings.paper_size = PP_FromGfxSize(print_params.paperSize);
+ print_settings.dpi = print_params.printerDPI;
+ print_settings.orientation = PP_PRINTORIENTATION_NORMAL;
+ print_settings.grayscale = PP_FALSE;
+ print_settings.print_scaling_option = static_cast<PP_PrintScalingOption_Dev>(
+ print_params.printScalingOption);
+ print_settings.format = format;
+ num_pages = plugin_print_interface_->Begin(pp_instance(),
+ &print_settings);
+ if (!num_pages)
+ return 0;
+ current_print_settings_ = print_settings;
+ canvas_.clear();
+ ranges_.clear();
+ return num_pages;
+}
+
+bool PluginInstanceImpl::PrintPage(int page_number, WebKit::WebCanvas* canvas) {
+#if defined(ENABLE_PRINTING)
+ DCHECK(plugin_print_interface_);
+ PP_PrintPageNumberRange_Dev page_range;
+ page_range.first_page_number = page_range.last_page_number = page_number;
+ // The canvas only has a metafile on it for print preview.
+ bool save_for_later =
+ (printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas) != NULL);
+#if defined(OS_MACOSX) || defined(OS_WIN)
+ save_for_later = save_for_later && skia::IsPreviewMetafile(*canvas);
+#endif
+ if (save_for_later) {
+ ranges_.push_back(page_range);
+ canvas_ = skia::SharePtr(canvas);
+ return true;
+ } else {
+ return PrintPageHelper(&page_range, 1, canvas);
+ }
+#else // defined(ENABLED_PRINTING)
+ return false;
+#endif
+}
+
+bool PluginInstanceImpl::PrintPageHelper(
+ PP_PrintPageNumberRange_Dev* page_ranges,
+ int num_ranges,
+ WebKit::WebCanvas* canvas) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ DCHECK(plugin_print_interface_);
+ if (!plugin_print_interface_)
+ return false;
+ PP_Resource print_output = plugin_print_interface_->PrintPages(
+ pp_instance(), page_ranges, num_ranges);
+ if (!print_output)
+ return false;
+
+ bool ret = false;
+
+ if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF)
+ ret = PrintPDFOutput(print_output, canvas);
+
+ // Now we need to release the print output resource.
+ PluginModule::GetCore()->ReleaseResource(print_output);
+
+ return ret;
+}
+
+void PluginInstanceImpl::PrintEnd() {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ if (!ranges_.empty())
+ PrintPageHelper(&(ranges_.front()), ranges_.size(), canvas_.get());
+ canvas_.clear();
+ ranges_.clear();
+
+ DCHECK(plugin_print_interface_);
+ if (plugin_print_interface_)
+ plugin_print_interface_->End(pp_instance());
+
+ memset(&current_print_settings_, 0, sizeof(current_print_settings_));
+#if defined(OS_MACOSX)
+ last_printed_page_ = NULL;
+#endif // defined(OS_MACOSX)
+}
+
+bool PluginInstanceImpl::CanRotateView() {
+ if (!LoadPdfInterface())
+ return false;
+
+ return true;
+}
+
+void PluginInstanceImpl::SetBoundGraphics2DForTest(
+ PluginDelegate::PlatformGraphics2D* graphics) {
+ BindGraphics(pp_instance(), 0); // Unbind any old stuff.
+ if (graphics) {
+ bound_graphics_2d_platform_ = graphics;
+ bound_graphics_2d_platform_->BindToInstance(this);
+ }
+}
+
+void PluginInstanceImpl::RotateView(WebPlugin::RotationType type) {
+ if (!LoadPdfInterface())
+ return;
+ PP_PrivatePageTransformType transform_type =
+ type == WebPlugin::RotationType90Clockwise ?
+ PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CW :
+ PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CCW;
+ plugin_pdf_interface_->Transform(pp_instance(), transform_type);
+ // NOTE: plugin instance may have been deleted.
+}
+
+bool PluginInstanceImpl::FlashIsFullscreenOrPending() {
+ return fullscreen_container_ != NULL;
+}
+
+bool PluginInstanceImpl::IsFullscreenOrPending() {
+ return desired_fullscreen_state_;
+}
+
+bool PluginInstanceImpl::SetFullscreen(bool fullscreen) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+
+ // Check whether we are trying to switch to the state we're already going
+ // to (i.e. if we're already switching to fullscreen but the fullscreen
+ // container isn't ready yet, don't do anything more).
+ if (fullscreen == IsFullscreenOrPending())
+ return false;
+
+ // Check whether we are trying to switch while the state is in transition.
+ // The 2nd request gets dropped while messing up the internal state, so
+ // disallow this.
+ if (view_data_.is_fullscreen != desired_fullscreen_state_)
+ return false;
+
+ if (fullscreen && !IsProcessingUserGesture())
+ return false;
+
+ VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
+ desired_fullscreen_state_ = fullscreen;
+
+ if (fullscreen) {
+ // Create the user gesture in case we're processing one that's pending.
+ WebScopedUserGesture user_gesture(CurrentUserGestureToken());
+ // WebKit does not resize the plugin to fill the screen in fullscreen mode,
+ // so we will tweak plugin's attributes to support the expected behavior.
+ KeepSizeAttributesBeforeFullscreen();
+ SetSizeAttributesForFullscreen();
+ container_->element().requestFullScreen();
+ } else {
+ container_->element().document().cancelFullScreen();
+ }
+ return true;
+}
+
+void PluginInstanceImpl::UpdateFlashFullscreenState(bool flash_fullscreen) {
+ bool is_mouselock_pending = TrackedCallback::IsPending(lock_mouse_callback_);
+
+ if (flash_fullscreen == flash_fullscreen_) {
+ // Manually clear callback when fullscreen fails with mouselock pending.
+ if (!flash_fullscreen && is_mouselock_pending)
+ lock_mouse_callback_->Run(PP_ERROR_FAILED);
+ return;
+ }
+
+ PPB_Graphics3D_Impl* graphics_3d = bound_graphics_3d_.get();
+ if (graphics_3d)
+ UpdateLayer();
+
+ bool old_plugin_focus = PluginHasFocus();
+ flash_fullscreen_ = flash_fullscreen;
+ if (is_mouselock_pending && !delegate()->IsMouseLocked(this)) {
+ if (!IsProcessingUserGesture() &&
+ !module_->permissions().HasPermission(
+ ::ppapi::PERMISSION_BYPASS_USER_GESTURE)) {
+ lock_mouse_callback_->Run(PP_ERROR_NO_USER_GESTURE);
+ } else {
+ // Open a user gesture here so the Webkit user gesture checks will succeed
+ // for out-of-process plugins.
+ WebScopedUserGesture user_gesture(CurrentUserGestureToken());
+ if (!delegate()->LockMouse(this))
+ lock_mouse_callback_->Run(PP_ERROR_FAILED);
+ }
+ }
+
+ if (PluginHasFocus() != old_plugin_focus)
+ SendFocusChangeNotification();
+}
+
+bool PluginInstanceImpl::IsViewAccelerated() {
+ if (!container_)
+ return false;
+
+ WebDocument document = container_->element().document();
+ WebFrame* frame = document.frame();
+ if (!frame)
+ return false;
+ WebView* view = frame->view();
+ if (!view)
+ return false;
+
+ return view->isAcceleratedCompositingActive();
+}
+
+PluginDelegate::PlatformContext3D* PluginInstanceImpl::CreateContext3D() {
+ return delegate_->CreateContext3D();
+}
+
+bool PluginInstanceImpl::PrintPDFOutput(PP_Resource print_output,
+ WebKit::WebCanvas* canvas) {
+#if defined(ENABLE_PRINTING)
+ ::ppapi::thunk::EnterResourceNoLock<PPB_Buffer_API> enter(print_output, true);
+ if (enter.failed())
+ return false;
+
+ BufferAutoMapper mapper(enter.object());
+ if (!mapper.data() || !mapper.size()) {
+ NOTREACHED();
+ return false;
+ }
+#if defined(OS_WIN)
+ // For Windows, we need the PDF DLL to render the output PDF to a DC.
+ HMODULE pdf_module = GetModuleHandle(L"pdf.dll");
+ if (!pdf_module)
+ return false;
+ RenderPDFPageToDCProc render_proc =
+ reinterpret_cast<RenderPDFPageToDCProc>(
+ GetProcAddress(pdf_module, "RenderPDFPageToDC"));
+ if (!render_proc)
+ return false;
+#endif // defined(OS_WIN)
+
+ bool ret = false;
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+ // On Linux we just set the final bits in the native metafile
+ // (NativeMetafile and PreviewMetafile must have compatible formats,
+ // i.e. both PDF for this to work).
+ printing::Metafile* metafile =
+ printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas);
+ DCHECK(metafile != NULL);
+ if (metafile)
+ ret = metafile->InitFromData(mapper.data(), mapper.size());
+#elif defined(OS_WIN)
+ printing::Metafile* metafile =
+ printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas);
+ if (metafile) {
+ // We only have a metafile when doing print preview, so we just want to
+ // pass the PDF off to preview.
+ ret = metafile->InitFromData(mapper.data(), mapper.size());
+ } else {
+ // On Windows, we now need to render the PDF to the DC that backs the
+ // supplied canvas.
+ HDC dc = skia::BeginPlatformPaint(canvas);
+ DrawEmptyRectangle(dc);
+ gfx::Size size_in_pixels;
+ size_in_pixels.set_width(printing::ConvertUnit(
+ current_print_settings_.printable_area.size.width,
+ static_cast<int>(printing::kPointsPerInch),
+ current_print_settings_.dpi));
+ size_in_pixels.set_height(printing::ConvertUnit(
+ current_print_settings_.printable_area.size.height,
+ static_cast<int>(printing::kPointsPerInch),
+ current_print_settings_.dpi));
+ // We need to scale down DC to fit an entire page into DC available area.
+ // First, we'll try to use default scaling based on the 72dpi that is
+ // used in webkit for printing.
+ // If default scaling is not enough to fit the entire PDF without
+ // Current metafile is based on screen DC and have current screen size.
+ // Writing outside of those boundaries will result in the cut-off output.
+ // On metafiles (this is the case here), scaling down will still record
+ // original coordinates and we'll be able to print in full resolution.
+ // Before playback we'll need to counter the scaling up that will happen
+ // in the browser (printed_document_win.cc).
+ double dynamic_scale = gfx::CalculatePageScale(dc, size_in_pixels.width(),
+ size_in_pixels.height());
+ double page_scale = static_cast<double>(printing::kPointsPerInch) /
+ static_cast<double>(current_print_settings_.dpi);
+
+ if (dynamic_scale < page_scale) {
+ page_scale = dynamic_scale;
+ printing::MetafileSkiaWrapper::SetCustomScaleOnCanvas(*canvas,
+ page_scale);
+ }
+
+ gfx::ScaleDC(dc, page_scale);
+
+ ret = render_proc(static_cast<unsigned char*>(mapper.data()), mapper.size(),
+ 0, dc, current_print_settings_.dpi,
+ current_print_settings_.dpi, 0, 0, size_in_pixels.width(),
+ size_in_pixels.height(), true, false, true, true, true);
+ skia::EndPlatformPaint(canvas);
+ }
+#endif // defined(OS_WIN)
+
+ return ret;
+#else // defined(ENABLE_PRINTING)
+ return false;
+#endif
+}
+
+PluginDelegate::PlatformGraphics2D*
+ PluginInstanceImpl::GetBoundGraphics2D() const {
+ return bound_graphics_2d_platform_;
+}
+
+static void IgnoreCallback(unsigned, bool) {}
+
+void PluginInstanceImpl::UpdateLayer() {
+ if (!container_)
+ return;
+
+ gpu::Mailbox mailbox;
+ if (bound_graphics_3d_.get()) {
+ PluginDelegate::PlatformContext3D* context =
+ bound_graphics_3d_->platform_context();
+ context->GetBackingMailbox(&mailbox);
+ }
+ bool want_layer = !mailbox.IsZero();
+
+ if (want_layer == !!texture_layer_.get() &&
+ layer_bound_to_fullscreen_ == !!fullscreen_container_)
+ return;
+
+ if (texture_layer_.get()) {
+ if (!layer_bound_to_fullscreen_)
+ container_->setWebLayer(NULL);
+ else if (fullscreen_container_)
+ fullscreen_container_->SetLayer(NULL);
+ web_layer_.reset();
+ texture_layer_ = NULL;
+ }
+ if (want_layer) {
+ DCHECK(bound_graphics_3d_.get());
+ texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL);
+ web_layer_.reset(new webkit::WebLayerImpl(texture_layer_));
+ if (fullscreen_container_) {
+ fullscreen_container_->SetLayer(web_layer_.get());
+ // Ignore transparency in fullscreen, since that's what Flash always
+ // wants to do, and that lets it not recreate a context if
+ // wmode=transparent was specified.
+ texture_layer_->SetContentsOpaque(true);
+ } else {
+ container_->setWebLayer(web_layer_.get());
+ texture_layer_->SetContentsOpaque(bound_graphics_3d_->IsOpaque());
+ }
+ texture_layer_->SetTextureMailbox(
+ cc::TextureMailbox(mailbox, base::Bind(&IgnoreCallback), 0));
+ }
+ layer_bound_to_fullscreen_ = !!fullscreen_container_;
+}
+
+void PluginInstanceImpl::AddPluginObject(PluginObject* plugin_object) {
+ DCHECK(live_plugin_objects_.find(plugin_object) ==
+ live_plugin_objects_.end());
+ live_plugin_objects_.insert(plugin_object);
+}
+
+void PluginInstanceImpl::RemovePluginObject(PluginObject* plugin_object) {
+ // Don't actually verify that the object is in the set since during module
+ // deletion we'll be in the process of freeing them.
+ live_plugin_objects_.erase(plugin_object);
+}
+
+bool PluginInstanceImpl::IsProcessingUserGesture() {
+ PP_TimeTicks now =
+ ::ppapi::TimeTicksToPPTimeTicks(base::TimeTicks::Now());
+ // Give a lot of slack so tests won't be flaky.
+ const PP_TimeTicks kUserGestureDurationInSeconds = 10.0;
+ return pending_user_gesture_token_.hasGestures() &&
+ (now - pending_user_gesture_ < kUserGestureDurationInSeconds);
+}
+
+WebUserGestureToken PluginInstanceImpl::CurrentUserGestureToken() {
+ if (!IsProcessingUserGesture())
+ pending_user_gesture_token_ = WebUserGestureToken();
+ return pending_user_gesture_token_;
+}
+
+void PluginInstanceImpl::OnLockMouseACK(bool succeeded) {
+ if (TrackedCallback::IsPending(lock_mouse_callback_))
+ lock_mouse_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
+}
+
+void PluginInstanceImpl::OnMouseLockLost() {
+ if (LoadMouseLockInterface())
+ plugin_mouse_lock_interface_->MouseLockLost(pp_instance());
+}
+
+void PluginInstanceImpl::HandleMouseLockedInputEvent(
+ const WebKit::WebMouseEvent& event) {
+ // |cursor_info| is ignored since it is hidden when the mouse is locked.
+ WebKit::WebCursorInfo cursor_info;
+ HandleInputEvent(event, &cursor_info);
+}
+
+void PluginInstanceImpl::SimulateInputEvent(const InputEventData& input_event) {
+ WebView* web_view = container()->element().document().frame()->view();
+ if (!web_view) {
+ NOTREACHED();
+ return;
+ }
+
+ bool handled = SimulateIMEEvent(input_event);
+ if (handled)
+ return;
+
+ std::vector<linked_ptr<WebInputEvent> > events =
+ CreateSimulatedWebInputEvents(
+ input_event,
+ view_data_.rect.point.x + view_data_.rect.size.width / 2,
+ view_data_.rect.point.y + view_data_.rect.size.height / 2);
+ for (std::vector<linked_ptr<WebInputEvent> >::iterator it = events.begin();
+ it != events.end(); ++it) {
+ web_view->handleInputEvent(*it->get());
+ }
+}
+
+bool PluginInstanceImpl::SimulateIMEEvent(const InputEventData& input_event) {
+ switch (input_event.event_type) {
+ case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
+ case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
+ SimulateImeSetCompositionEvent(input_event);
+ break;
+ case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
+ DCHECK(input_event.character_text.empty());
+ SimulateImeSetCompositionEvent(input_event);
+ break;
+ case PP_INPUTEVENT_TYPE_IME_TEXT:
+ delegate()->SimulateImeConfirmComposition(
+ UTF8ToUTF16(input_event.character_text));
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void PluginInstanceImpl::SimulateImeSetCompositionEvent(
+ const InputEventData& input_event) {
+ std::vector<size_t> offsets;
+ offsets.push_back(input_event.composition_selection_start);
+ offsets.push_back(input_event.composition_selection_end);
+ offsets.insert(offsets.end(),
+ input_event.composition_segment_offsets.begin(),
+ input_event.composition_segment_offsets.end());
+
+ base::string16 utf16_text =
+ base::UTF8ToUTF16AndAdjustOffsets(input_event.character_text, &offsets);
+
+ std::vector<WebKit::WebCompositionUnderline> underlines;
+ for (size_t i = 2; i + 1 < offsets.size(); ++i) {
+ WebKit::WebCompositionUnderline underline;
+ underline.startOffset = offsets[i];
+ underline.endOffset = offsets[i + 1];
+ if (input_event.composition_target_segment == static_cast<int32_t>(i - 2))
+ underline.thick = true;
+ underlines.push_back(underline);
+ }
+
+ delegate()->SimulateImeSetComposition(
+ utf16_text, underlines, offsets[0], offsets[1]);
+}
+
+ContentDecryptorDelegate* PluginInstanceImpl::GetContentDecryptorDelegate() {
+ if (content_decryptor_delegate_)
+ return content_decryptor_delegate_.get();
+
+ const PPP_ContentDecryptor_Private* plugin_decryption_interface =
+ static_cast<const PPP_ContentDecryptor_Private*>(
+ module_->GetPluginInterface(
+ PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE));
+ if (!plugin_decryption_interface)
+ return NULL;
+
+ content_decryptor_delegate_.reset(
+ new ContentDecryptorDelegate(pp_instance_, plugin_decryption_interface));
+ return content_decryptor_delegate_.get();
+}
+
+PP_Bool PluginInstanceImpl::BindGraphics(PP_Instance instance,
+ PP_Resource device) {
+ TRACE_EVENT0("ppapi", "PluginInstanceImpl::BindGraphics");
+ // The Graphics3D instance can't be destroyed until we call
+ // UpdateLayer().
+ scoped_refptr< ::ppapi::Resource> old_graphics = bound_graphics_3d_.get();
+ if (bound_graphics_3d_.get()) {
+ bound_graphics_3d_->BindToInstance(false);
+ bound_graphics_3d_ = NULL;
+ }
+ if (bound_graphics_2d_platform_) {
+ GetBoundGraphics2D()->BindToInstance(NULL);
+ bound_graphics_2d_platform_ = NULL;
+ }
+
+ // Special-case clearing the current device.
+ if (!device) {
+ UpdateLayer();
+ InvalidateRect(gfx::Rect());
+ return PP_TRUE;
+ }
+
+ // Refuse to bind if in transition to fullscreen with PPB_FlashFullscreen or
+ // to/from fullscreen with PPB_Fullscreen.
+ if ((fullscreen_container_ && !flash_fullscreen_) ||
+ desired_fullscreen_state_ != view_data_.is_fullscreen)
+ return PP_FALSE;
+
+ PluginDelegate::PlatformGraphics2D* graphics_2d =
+ delegate_->GetGraphics2D(this, device);
+ EnterResourceNoLock<PPB_Graphics3D_API> enter_3d(device, false);
+ PPB_Graphics3D_Impl* graphics_3d = enter_3d.succeeded() ?
+ static_cast<PPB_Graphics3D_Impl*>(enter_3d.object()) : NULL;
+
+ if (graphics_2d) {
+ if (graphics_2d->BindToInstance(this)) {
+ bound_graphics_2d_platform_ = graphics_2d;
+ UpdateLayer();
+ return PP_TRUE;
+ }
+ } else if (graphics_3d) {
+ // Make sure graphics can only be bound to the instance it is
+ // associated with.
+ if (graphics_3d->pp_instance() == pp_instance() &&
+ graphics_3d->BindToInstance(true)) {
+ bound_graphics_3d_ = graphics_3d;
+ UpdateLayer();
+ return PP_TRUE;
+ }
+ }
+
+ // The instance cannot be bound or the device is not a valid resource type.
+ return PP_FALSE;
+}
+
+PP_Bool PluginInstanceImpl::IsFullFrame(PP_Instance instance) {
+ return PP_FromBool(full_frame());
+}
+
+const ViewData* PluginInstanceImpl::GetViewData(PP_Instance instance) {
+ return &view_data_;
+}
+
+PP_Bool PluginInstanceImpl::FlashIsFullscreen(PP_Instance instance) {
+ return PP_FromBool(flash_fullscreen_);
+}
+
+PP_Var PluginInstanceImpl::GetWindowObject(PP_Instance instance) {
+ if (!container_)
+ return PP_MakeUndefined();
+
+ WebFrame* frame = container_->element().document().frame();
+ if (!frame)
+ return PP_MakeUndefined();
+
+ return NPObjectToPPVar(this, frame->windowObject());
+}
+
+PP_Var PluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) {
+ if (!container_)
+ return PP_MakeUndefined();
+ return NPObjectToPPVar(this, container_->scriptableObjectForElement());
+}
+
+PP_Var PluginInstanceImpl::ExecuteScript(PP_Instance instance,
+ PP_Var script,
+ PP_Var* exception) {
+ // 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
+ // WebBindings::evaluate() below.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+ TryCatch try_catch(exception);
+ if (try_catch.has_exception())
+ return PP_MakeUndefined();
+
+ // Convert the script into an inconvenient NPString object.
+ StringVar* script_string = StringVar::FromPPVar(script);
+ if (!script_string) {
+ try_catch.SetException("Script param to ExecuteScript must be a string.");
+ return PP_MakeUndefined();
+ }
+ NPString np_script;
+ np_script.UTF8Characters = script_string->value().c_str();
+ np_script.UTF8Length = script_string->value().length();
+
+ // Get the current frame to pass to the evaluate function.
+ WebFrame* frame = container_->element().document().frame();
+ if (!frame) {
+ try_catch.SetException("No frame to execute script in.");
+ return PP_MakeUndefined();
+ }
+
+ NPVariant result;
+ bool ok = false;
+ if (IsProcessingUserGesture()) {
+ WebKit::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
+ ok = WebBindings::evaluate(NULL, frame->windowObject(), &np_script,
+ &result);
+ } else {
+ ok = WebBindings::evaluate(NULL, frame->windowObject(), &np_script,
+ &result);
+ }
+ if (!ok) {
+ // TryCatch doesn't catch the exceptions properly. Since this is only for
+ // a trusted API, just set to a general exception message.
+ try_catch.SetException("Exception caught");
+ WebBindings::releaseVariantValue(&result);
+ return PP_MakeUndefined();
+ }
+
+ PP_Var ret = NPVariantToPPVar(this, &result);
+ WebBindings::releaseVariantValue(&result);
+ return ret;
+}
+
+uint32_t PluginInstanceImpl::GetAudioHardwareOutputSampleRate(
+ PP_Instance instance) {
+ return delegate()->GetAudioHardwareOutputSampleRate();
+}
+
+uint32_t PluginInstanceImpl::GetAudioHardwareOutputBufferSize(
+ PP_Instance instance) {
+ return delegate()->GetAudioHardwareOutputBufferSize();
+}
+
+PP_Var PluginInstanceImpl::GetDefaultCharSet(PP_Instance instance) {
+ std::string encoding = delegate()->GetDefaultEncoding();
+ return StringVar::StringToPPVar(encoding);
+}
+
+// These PPB_ContentDecryptor_Private calls are responses to
+// PPP_ContentDecryptor_Private calls made on |content_decryptor_delegate_|.
+// Therefore, |content_decryptor_delegate_| must have been initialized when
+// the following methods are called.
+void PluginInstanceImpl::NeedKey(PP_Instance instance,
+ PP_Var key_system_var,
+ PP_Var session_id_var,
+ PP_Var init_data_var) {
+ content_decryptor_delegate_->NeedKey(
+ key_system_var, session_id_var, init_data_var);
+}
+
+void PluginInstanceImpl::KeyAdded(PP_Instance instance,
+ PP_Var key_system_var,
+ PP_Var session_id_var) {
+ content_decryptor_delegate_->KeyAdded(key_system_var, session_id_var);
+}
+
+void PluginInstanceImpl::KeyMessage(PP_Instance instance,
+ PP_Var key_system_var,
+ PP_Var session_id_var,
+ PP_Var message_var,
+ PP_Var default_url_var) {
+ content_decryptor_delegate_->KeyMessage(
+ key_system_var, session_id_var, message_var, default_url_var);
+}
+
+void PluginInstanceImpl::KeyError(PP_Instance instance,
+ PP_Var key_system_var,
+ PP_Var session_id_var,
+ int32_t media_error,
+ int32_t system_code) {
+ content_decryptor_delegate_->KeyError(
+ key_system_var, session_id_var, media_error, system_code);
+}
+
+void PluginInstanceImpl::DeliverBlock(PP_Instance instance,
+ PP_Resource decrypted_block,
+ const PP_DecryptedBlockInfo* block_info) {
+ content_decryptor_delegate_->DeliverBlock(decrypted_block, block_info);
+}
+
+void PluginInstanceImpl::DecoderInitializeDone(
+ PP_Instance instance,
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id,
+ PP_Bool success) {
+ content_decryptor_delegate_->DecoderInitializeDone(
+ decoder_type, request_id, success);
+}
+
+void PluginInstanceImpl::DecoderDeinitializeDone(
+ PP_Instance instance,
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id) {
+ content_decryptor_delegate_->DecoderDeinitializeDone(decoder_type,
+ request_id);
+}
+
+void PluginInstanceImpl::DecoderResetDone(PP_Instance instance,
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id) {
+ content_decryptor_delegate_->DecoderResetDone(decoder_type, request_id);
+}
+
+
+void PluginInstanceImpl::DeliverFrame(PP_Instance instance,
+ PP_Resource decrypted_frame,
+ const PP_DecryptedFrameInfo* frame_info) {
+ content_decryptor_delegate_->DeliverFrame(decrypted_frame, frame_info);
+}
+
+void PluginInstanceImpl::DeliverSamples(
+ PP_Instance instance,
+ PP_Resource audio_frames,
+ const PP_DecryptedBlockInfo* block_info) {
+ content_decryptor_delegate_->DeliverSamples(audio_frames, block_info);
+}
+
+void PluginInstanceImpl::NumberOfFindResultsChanged(PP_Instance instance,
+ int32_t total,
+ PP_Bool final_result) {
+ DCHECK_NE(find_identifier_, -1);
+ delegate_->NumberOfFindResultsChanged(find_identifier_, total,
+ PP_ToBool(final_result));
+}
+
+void PluginInstanceImpl::SelectedFindResultChanged(PP_Instance instance,
+ int32_t index) {
+ DCHECK_NE(find_identifier_, -1);
+ delegate_->SelectedFindResultChanged(find_identifier_, index);
+}
+
+PP_Bool PluginInstanceImpl::IsFullscreen(PP_Instance instance) {
+ return PP_FromBool(view_data_.is_fullscreen);
+}
+
+PP_Bool PluginInstanceImpl::SetFullscreen(PP_Instance instance,
+ PP_Bool fullscreen) {
+ return PP_FromBool(SetFullscreen(PP_ToBool(fullscreen)));
+}
+
+PP_Bool PluginInstanceImpl::GetScreenSize(PP_Instance instance, PP_Size* size) {
+ gfx::Size screen_size = delegate()->GetScreenSize();
+ *size = PP_MakeSize(screen_size.width(), screen_size.height());
+ return PP_TRUE;
+}
+
+::ppapi::Resource* PluginInstanceImpl::GetSingletonResource(
+ PP_Instance instance,
+ ::ppapi::SingletonResourceID id) {
+ // Flash APIs and some others aren't implemented in-process.
+ switch (id) {
+ case ::ppapi::BROKER_SINGLETON_ID:
+ case ::ppapi::BROWSER_FONT_SINGLETON_ID:
+ case ::ppapi::CRX_FILESYSTEM_SINGLETON_ID:
+ case ::ppapi::EXTENSIONS_COMMON_SINGLETON_ID:
+ case ::ppapi::FLASH_CLIPBOARD_SINGLETON_ID:
+ case ::ppapi::FLASH_FILE_SINGLETON_ID:
+ case ::ppapi::FLASH_FULLSCREEN_SINGLETON_ID:
+ case ::ppapi::FLASH_SINGLETON_ID:
+ case ::ppapi::NETWORK_PROXY_SINGLETON_ID:
+ case ::ppapi::PDF_SINGLETON_ID:
+ case ::ppapi::TRUETYPE_FONT_SINGLETON_ID:
+ NOTIMPLEMENTED();
+ return NULL;
+ case ::ppapi::GAMEPAD_SINGLETON_ID:
+ return gamepad_impl_.get();
+ }
+
+ NOTREACHED();
+ return NULL;
+}
+
+int32_t PluginInstanceImpl::RequestInputEvents(PP_Instance instance,
+ uint32_t event_classes) {
+ input_event_mask_ |= event_classes;
+ filtered_input_event_mask_ &= ~(event_classes);
+ RequestInputEventsHelper(event_classes);
+ return ValidateRequestInputEvents(false, event_classes);
+}
+
+int32_t PluginInstanceImpl::RequestFilteringInputEvents(
+ PP_Instance instance,
+ uint32_t event_classes) {
+ filtered_input_event_mask_ |= event_classes;
+ input_event_mask_ &= ~(event_classes);
+ RequestInputEventsHelper(event_classes);
+ return ValidateRequestInputEvents(true, event_classes);
+}
+
+void PluginInstanceImpl::ClearInputEventRequest(PP_Instance instance,
+ uint32_t event_classes) {
+ input_event_mask_ &= ~(event_classes);
+ filtered_input_event_mask_ &= ~(event_classes);
+ RequestInputEventsHelper(event_classes);
+}
+
+void PluginInstanceImpl::ZoomChanged(PP_Instance instance, double factor) {
+ // We only want to tell the page to change its zoom if the whole page is the
+ // plugin. If we're in an iframe, then don't do anything.
+ if (!IsFullPagePlugin())
+ return;
+ container()->zoomLevelChanged(WebView::zoomFactorToZoomLevel(factor));
+}
+
+void PluginInstanceImpl::ZoomLimitsChanged(PP_Instance instance,
+ double minimum_factor,
+ double maximium_factor) {
+ if (minimum_factor > maximium_factor) {
+ NOTREACHED();
+ return;
+ }
+ delegate()->ZoomLimitsChanged(minimum_factor, maximium_factor);
+}
+
+void PluginInstanceImpl::PostMessage(PP_Instance instance, PP_Var message) {
+ message_channel_->PostMessageToJavaScript(message);
+}
+
+PP_Bool PluginInstanceImpl::SetCursor(PP_Instance instance,
+ PP_MouseCursor_Type type,
+ PP_Resource image,
+ const PP_Point* hot_spot) {
+ if (!ValidateSetCursorParams(type, image, hot_spot))
+ return PP_FALSE;
+
+ if (type != PP_MOUSECURSOR_TYPE_CUSTOM) {
+ DoSetCursor(new WebCursorInfo(static_cast<WebCursorInfo::Type>(type)));
+ return PP_TRUE;
+ }
+
+ EnterResourceNoLock<PPB_ImageData_API> enter(image, true);
+ if (enter.failed())
+ return PP_FALSE;
+ PPB_ImageData_Impl* image_data =
+ static_cast<PPB_ImageData_Impl*>(enter.object());
+
+ ImageDataAutoMapper auto_mapper(image_data);
+ if (!auto_mapper.is_valid())
+ return PP_FALSE;
+
+ scoped_ptr<WebCursorInfo> custom_cursor(
+ new WebCursorInfo(WebCursorInfo::TypeCustom));
+ custom_cursor->hotSpot.x = hot_spot->x;
+ custom_cursor->hotSpot.y = hot_spot->y;
+
+ const SkBitmap* bitmap = image_data->GetMappedBitmap();
+ // Make a deep copy, so that the cursor remains valid even after the original
+ // image data gets freed.
+ if (!bitmap->copyTo(&custom_cursor->customImage.getSkBitmap(),
+ bitmap->config())) {
+ return PP_FALSE;
+ }
+
+ DoSetCursor(custom_cursor.release());
+ return PP_TRUE;
+}
+
+int32_t PluginInstanceImpl::LockMouse(PP_Instance instance,
+ scoped_refptr<TrackedCallback> callback) {
+ if (TrackedCallback::IsPending(lock_mouse_callback_))
+ return PP_ERROR_INPROGRESS;
+
+ if (delegate()->IsMouseLocked(this))
+ return PP_OK;
+
+ if (!CanAccessMainFrame())
+ return PP_ERROR_NOACCESS;
+
+ if (!IsProcessingUserGesture())
+ return PP_ERROR_NO_USER_GESTURE;
+
+ // Attempt mouselock only if Flash isn't waiting on fullscreen, otherwise
+ // we wait and call LockMouse() in UpdateFlashFullscreenState().
+ if (!FlashIsFullscreenOrPending() || flash_fullscreen()) {
+ // Open a user gesture here so the Webkit user gesture checks will succeed
+ // for out-of-process plugins.
+ WebScopedUserGesture user_gesture(CurrentUserGestureToken());
+ if (!delegate()->LockMouse(this))
+ return PP_ERROR_FAILED;
+ }
+
+ // Either mouselock succeeded or a Flash fullscreen is pending.
+ lock_mouse_callback_ = callback;
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PluginInstanceImpl::UnlockMouse(PP_Instance instance) {
+ delegate()->UnlockMouse(this);
+}
+
+void PluginInstanceImpl::SetTextInputType(PP_Instance instance,
+ PP_TextInput_Type type) {
+ int itype = type;
+ if (itype < 0 || itype > ui::TEXT_INPUT_TYPE_URL)
+ itype = ui::TEXT_INPUT_TYPE_NONE;
+ text_input_type_ = static_cast<ui::TextInputType>(itype);
+ delegate()->PluginTextInputTypeChanged(this);
+}
+
+void PluginInstanceImpl::UpdateCaretPosition(PP_Instance instance,
+ const PP_Rect& caret,
+ const PP_Rect& bounding_box) {
+ text_input_caret_ = PP_ToGfxRect(caret);
+ text_input_caret_bounds_ = PP_ToGfxRect(bounding_box);
+ text_input_caret_set_ = true;
+ delegate()->PluginCaretPositionChanged(this);
+}
+
+void PluginInstanceImpl::CancelCompositionText(PP_Instance instance) {
+ delegate()->PluginRequestedCancelComposition(this);
+}
+
+void PluginInstanceImpl::SelectionChanged(PP_Instance instance) {
+ // TODO(kinaba): currently the browser always calls RequestSurroundingText.
+ // It can be optimized so that it won't call it back until the information
+ // is really needed.
+
+ // Avoid calling in nested context or else this will reenter the plugin. This
+ // uses a weak pointer rather than exploiting the fact that this class is
+ // refcounted because we don't actually want this operation to affect the
+ // lifetime of the instance.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PluginInstanceImpl::RequestSurroundingText,
+ AsWeakPtr(),
+ static_cast<size_t>(kExtraCharsForTextInput)));
+}
+
+void PluginInstanceImpl::UpdateSurroundingText(PP_Instance instance,
+ const char* text,
+ uint32_t caret,
+ uint32_t anchor) {
+ surrounding_text_ = text;
+ selection_caret_ = caret;
+ selection_anchor_ = anchor;
+ delegate()->PluginSelectionChanged(this);
+}
+
+PP_Var PluginInstanceImpl::ResolveRelativeToDocument(
+ PP_Instance instance,
+ PP_Var relative,
+ PP_URLComponents_Dev* components) {
+ StringVar* relative_string = StringVar::FromPPVar(relative);
+ if (!relative_string)
+ return PP_MakeNull();
+
+ WebElement plugin_element = container()->element();
+ GURL document_url = plugin_element.document().baseURL();
+ return ::ppapi::PPB_URLUtil_Shared::GenerateURLReturn(
+ document_url.Resolve(relative_string->value()),
+ components);
+}
+
+PP_Bool PluginInstanceImpl::DocumentCanRequest(PP_Instance instance,
+ PP_Var url) {
+ StringVar* url_string = StringVar::FromPPVar(url);
+ if (!url_string)
+ return PP_FALSE;
+
+ WebKit::WebSecurityOrigin security_origin;
+ if (!SecurityOriginForInstance(instance, &security_origin))
+ return PP_FALSE;
+
+ GURL gurl(url_string->value());
+ if (!gurl.is_valid())
+ return PP_FALSE;
+
+ return BoolToPPBool(security_origin.canRequest(gurl));
+}
+
+PP_Bool PluginInstanceImpl::DocumentCanAccessDocument(PP_Instance instance,
+ PP_Instance target) {
+ WebKit::WebSecurityOrigin our_origin;
+ if (!SecurityOriginForInstance(instance, &our_origin))
+ return PP_FALSE;
+
+ WebKit::WebSecurityOrigin target_origin;
+ if (!SecurityOriginForInstance(instance, &target_origin))
+ return PP_FALSE;
+
+ return BoolToPPBool(our_origin.canAccess(target_origin));
+}
+
+PP_Var PluginInstanceImpl::GetDocumentURL(PP_Instance instance,
+ PP_URLComponents_Dev* components) {
+ WebKit::WebDocument document = container()->element().document();
+ return ::ppapi::PPB_URLUtil_Shared::GenerateURLReturn(document.url(),
+ components);
+}
+
+PP_Var PluginInstanceImpl::GetPluginInstanceURL(
+ PP_Instance instance,
+ PP_URLComponents_Dev* components) {
+ return ::ppapi::PPB_URLUtil_Shared::GenerateURLReturn(plugin_url_,
+ components);
+}
+
+PP_ExternalPluginResult PluginInstanceImpl::ResetAsProxied(
+ scoped_refptr<PluginModule> module) {
+ // Save the original module and switch over to the new one now that this
+ // plugin is using the IPC-based proxy.
+ original_module_ = module_;
+ module_ = module;
+
+ // Don't send any messages to the plugin until DidCreate() has finished.
+ message_channel_->QueueJavaScriptMessages();
+
+ // For NaCl instances, remember the NaCl plugin instance interface, so we
+ // can shut it down by calling its DidDestroy in our Delete() method.
+ original_instance_interface_.reset(instance_interface_.release());
+
+ base::Callback<const void*(const char*)> get_plugin_interface_func =
+ base::Bind(&PluginModule::GetPluginInterface, module_.get());
+ PPP_Instance_Combined* ppp_instance_combined =
+ PPP_Instance_Combined::Create(get_plugin_interface_func);
+ if (!ppp_instance_combined) {
+ // The proxy must support at least one usable PPP_Instance interface.
+ // While this could be a failure to implement the interface in the NaCl
+ // module, it is more likely that the NaCl process has crashed. Either
+ // way, report that module initialization failed.
+ return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
+ }
+
+ instance_interface_.reset(ppp_instance_combined);
+ // Clear all PPP interfaces we may have cached.
+ plugin_find_interface_ = NULL;
+ plugin_input_event_interface_ = NULL;
+ checked_for_plugin_input_event_interface_ = false;
+ plugin_messaging_interface_ = NULL;
+ checked_for_plugin_messaging_interface_ = false;
+ plugin_mouse_lock_interface_ = NULL;
+ plugin_pdf_interface_ = NULL;
+ checked_for_plugin_pdf_interface_ = false;
+ plugin_private_interface_ = NULL;
+ plugin_selection_interface_ = NULL;
+ plugin_textinput_interface_ = NULL;
+ plugin_zoom_interface_ = NULL;
+
+ // Re-send the DidCreate event via the proxy.
+ scoped_ptr<const char*[]> argn_array(StringVectorToArgArray(argn_));
+ scoped_ptr<const char*[]> argv_array(StringVectorToArgArray(argv_));
+ if (!instance_interface_->DidCreate(pp_instance(), argn_.size(),
+ argn_array.get(), argv_array.get()))
+ return PP_EXTERNAL_PLUGIN_ERROR_INSTANCE;
+ message_channel_->StopQueueingJavaScriptMessages();
+
+ // Clear sent_initial_did_change_view_ and cancel any pending DidChangeView
+ // event. This way, SendDidChangeView will send the "current" view
+ // immediately (before other events like HandleDocumentLoad).
+ sent_initial_did_change_view_ = false;
+ view_change_weak_ptr_factory_.InvalidateWeakPtrs();
+ SendDidChangeView();
+
+ DCHECK(nacl_document_load_);
+ nacl_document_load_ = false;
+ if (!nacl_document_response_.isNull()) {
+ document_loader_ = NULL;
+ // Pass the response to the new proxy.
+ HandleDocumentLoad(nacl_document_response_);
+ nacl_document_response_ = WebKit::WebURLResponse();
+ // Replay any document load events we've received to the real loader.
+ nacl_document_loader_->ReplayReceivedData(document_loader_);
+ nacl_document_loader_.reset(NULL);
+ }
+
+ return PP_EXTERNAL_PLUGIN_OK;
+}
+
+bool PluginInstanceImpl::IsValidInstanceOf(PluginModule* module) {
+ DCHECK(module);
+ return module == module_.get() ||
+ module == original_module_.get();
+}
+
+NPP PluginInstanceImpl::instanceNPP() {
+ return npp_.get();
+}
+
+v8::Isolate* PluginInstanceImpl::GetIsolate() const {
+ return isolate_;
+}
+
+PluginInstance* PluginInstance::Get(PP_Instance instance_id) {
+ return HostGlobals::Get()->GetInstance(instance_id);
+}
+
+content::RenderView* PluginInstanceImpl::GetRenderView() {
+ return render_view_;
+}
+
+WebKit::WebPluginContainer* PluginInstanceImpl::GetContainer() {
+ return container_;
+}
+
+::ppapi::VarTracker* PluginInstanceImpl::GetVarTracker() {
+ return HostGlobals::Get()->GetVarTracker();
+}
+
+const GURL& PluginInstanceImpl::GetPluginURL() {
+ return plugin_url_;
+}
+
+base::FilePath PluginInstanceImpl::GetModulePath() {
+ return module_->path();
+}
+
+PP_Resource PluginInstanceImpl::CreateExternalFileReference(
+ const base::FilePath& external_file_path) {
+ webkit::ppapi::PPB_FileRef_Impl* ref =
+ webkit::ppapi::PPB_FileRef_Impl::CreateExternal(
+ pp_instance(), external_file_path, "");
+ return ref->GetReference();
+}
+
+PP_Resource PluginInstanceImpl::CreateImage(gfx::ImageSkia* source_image,
+ float scale) {
+ ui::ScaleFactor scale_factor = ui::GetScaleFactorFromScale(scale);
+ gfx::ImageSkiaRep image_skia_rep = source_image->GetRepresentation(
+ scale_factor);
+
+ if (image_skia_rep.is_null() || image_skia_rep.scale_factor() != scale_factor)
+ return 0;
+
+ scoped_refptr<webkit::ppapi::PPB_ImageData_Impl> image_data(
+ new webkit::ppapi::PPB_ImageData_Impl(
+ pp_instance(),
+ webkit::ppapi::PPB_ImageData_Impl::PLATFORM));
+ if (!image_data->Init(
+ webkit::ppapi::PPB_ImageData_Impl::GetNativeImageDataFormat(),
+ image_skia_rep.pixel_width(),
+ image_skia_rep.pixel_height(),
+ false)) {
+ return 0;
+ }
+
+ webkit::ppapi::ImageDataAutoMapper mapper(image_data.get());
+ if (!mapper.is_valid())
+ return 0;
+
+ skia::PlatformCanvas* canvas = image_data->GetPlatformCanvas();
+ // Note: Do not SkBitmap::copyTo the canvas bitmap directly because it will
+ // ignore the allocated pixels in shared memory and re-allocate a new buffer.
+ canvas->writePixels(image_skia_rep.sk_bitmap(), 0, 0);
+
+ return image_data->GetReference();
+}
+
+PP_ExternalPluginResult PluginInstanceImpl::SwitchToOutOfProcessProxy(
+ const base::FilePath& file_path,
+ ::ppapi::PpapiPermissions permissions,
+ const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) {
+ // Create a new module for each instance of the external plugin that is using
+ // the IPC based out-of-process proxy. We can't use the existing module,
+ // because it is configured for the in-process plugin, and we must keep it
+ // that way to allow the page to create other instances.
+ scoped_refptr<webkit::ppapi::PluginModule> external_plugin_module(
+ module_->CreateModuleForExternalPluginInstance());
+
+ content::RendererPpapiHost* renderer_ppapi_host =
+ delegate_->CreateExternalPluginModule(
+ external_plugin_module,
+ file_path,
+ permissions,
+ channel_handle,
+ plugin_pid,
+ plugin_child_id);
+ if (!renderer_ppapi_host) {
+ DLOG(ERROR) << "CreateExternalPluginModule() failed";
+ return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
+ }
+
+ // Finally, switch the instance to the proxy.
+ return external_plugin_module->InitAsProxiedExternalPlugin(this);
+}
+
+void PluginInstanceImpl::SetAlwaysOnTop(bool on_top) {
+ always_on_top_ = on_top;
+}
+
+void PluginInstanceImpl::DoSetCursor(WebCursorInfo* cursor) {
+ cursor_.reset(cursor);
+ if (fullscreen_container_) {
+ fullscreen_container_->DidChangeCursor(*cursor);
+ } else {
+ delegate()->DidChangeCursor(this, *cursor);
+ }
+}
+
+bool PluginInstanceImpl::IsFullPagePlugin() {
+ WebFrame* frame = container()->element().document().frame();
+ return frame->view()->mainFrame()->document().isPluginDocument();
+}
+
+void PluginInstanceImpl::FlashSetFullscreen(bool fullscreen,
+ bool delay_report) {
+ TRACE_EVENT0("ppapi", "PluginInstanceImpl::FlashSetFullscreen");
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstanceImpl> ref(this);
+
+ // We check whether we are trying to switch to the state we're already going
+ // to (i.e. if we're already switching to fullscreen but the fullscreen
+ // container isn't ready yet, don't do anything more).
+ if (fullscreen == FlashIsFullscreenOrPending())
+ return;
+
+ // Unbind current 2D or 3D graphics context.
+ VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
+ if (fullscreen) {
+ DCHECK(!fullscreen_container_);
+ fullscreen_container_ = delegate_->CreateFullscreenContainer(this);
+ UpdateLayer();
+ } else {
+ DCHECK(fullscreen_container_);
+ fullscreen_container_->Destroy();
+ fullscreen_container_ = NULL;
+ UpdateFlashFullscreenState(false);
+ if (!delay_report) {
+ ReportGeometry();
+ } else {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&PluginInstanceImpl::ReportGeometry, this));
+ }
+ }
+}
+
+bool PluginInstanceImpl::IsRectTopmost(const gfx::Rect& rect) {
+ if (flash_fullscreen_)
+ return true;
+
+ return container_->isRectTopmost(rect);
+}
+
+int32_t PluginInstanceImpl::Navigate(const ::ppapi::URLRequestInfoData& request,
+ const char* target,
+ bool from_user_action) {
+ if (!container_)
+ return PP_ERROR_FAILED;
+
+ WebDocument document = container_->element().document();
+ WebFrame* frame = document.frame();
+ if (!frame)
+ return PP_ERROR_FAILED;
+
+ ::ppapi::URLRequestInfoData completed_request = request;
+
+ WebURLRequest web_request;
+ if (!CreateWebURLRequest(&completed_request, frame, &web_request))
+ return PP_ERROR_FAILED;
+ web_request.setFirstPartyForCookies(document.firstPartyForCookies());
+ web_request.setHasUserGesture(from_user_action);
+
+ GURL gurl(web_request.url());
+ if (gurl.SchemeIs("javascript")) {
+ // In imitation of the NPAPI implementation, only |target_frame == frame| is
+ // allowed for security reasons.
+ WebFrame* target_frame =
+ frame->view()->findFrameByName(WebString::fromUTF8(target), frame);
+ if (target_frame != frame)
+ return PP_ERROR_NOACCESS;
+
+ // TODO(viettrungluu): NPAPI sends the result back to the plugin -- do we
+ // need that?
+ WebString result = container_->executeScriptURL(gurl, from_user_action);
+ return result.isNull() ? PP_ERROR_FAILED : PP_OK;
+ }
+
+ // Only GETs and POSTs are supported.
+ if (web_request.httpMethod() != "GET" &&
+ web_request.httpMethod() != "POST")
+ return PP_ERROR_BADARGUMENT;
+
+ WebString target_str = WebString::fromUTF8(target);
+ container_->loadFrameRequest(web_request, target_str, false, NULL);
+ return PP_OK;
+}
+
+bool PluginInstanceImpl::CanAccessMainFrame() const {
+ if (!container_)
+ return false;
+ WebKit::WebDocument containing_document = container_->element().document();
+
+ if (!containing_document.frame() ||
+ !containing_document.frame()->view() ||
+ !containing_document.frame()->view()->mainFrame()) {
+ return false;
+ }
+ WebKit::WebDocument main_document =
+ containing_document.frame()->view()->mainFrame()->document();
+
+ return containing_document.securityOrigin().canAccess(
+ main_document.securityOrigin());
+}
+
+void PluginInstanceImpl::KeepSizeAttributesBeforeFullscreen() {
+ WebElement element = container_->element();
+ width_before_fullscreen_ = element.getAttribute(WebString::fromUTF8(kWidth));
+ height_before_fullscreen_ =
+ element.getAttribute(WebString::fromUTF8(kHeight));
+ border_before_fullscreen_ =
+ element.getAttribute(WebString::fromUTF8(kBorder));
+ style_before_fullscreen_ = element.getAttribute(WebString::fromUTF8(kStyle));
+}
+
+void PluginInstanceImpl::SetSizeAttributesForFullscreen() {
+ screen_size_for_fullscreen_ = delegate()->GetScreenSize();
+ std::string width = StringPrintf("%d", screen_size_for_fullscreen_.width());
+ std::string height = StringPrintf("%d", screen_size_for_fullscreen_.height());
+
+ WebElement element = container_->element();
+ element.setAttribute(WebString::fromUTF8(kWidth), WebString::fromUTF8(width));
+ element.setAttribute(WebString::fromUTF8(kHeight),
+ WebString::fromUTF8(height));
+ element.setAttribute(WebString::fromUTF8(kBorder), WebString::fromUTF8("0"));
+
+ // There should be no style settings that matter in fullscreen mode,
+ // so just replace them instead of appending.
+ // NOTE: "position: fixed" and "display: block" reset the plugin and
+ // using %% settings might not work without them (e.g. if the plugin is a
+ // child of a container element).
+ std::string style;
+ style += StringPrintf("width: %s !important; ", width.c_str());
+ style += StringPrintf("height: %s !important; ", height.c_str());
+ style += "margin: 0 !important; padding: 0 !important; border: 0 !important";
+ container_->element().setAttribute(kStyle, WebString::fromUTF8(style));
+}
+
+void PluginInstanceImpl::ResetSizeAttributesAfterFullscreen() {
+ screen_size_for_fullscreen_ = gfx::Size();
+ WebElement element = container_->element();
+ element.setAttribute(WebString::fromUTF8(kWidth), width_before_fullscreen_);
+ element.setAttribute(WebString::fromUTF8(kHeight), height_before_fullscreen_);
+ element.setAttribute(WebString::fromUTF8(kBorder), border_before_fullscreen_);
+ element.setAttribute(WebString::fromUTF8(kStyle), style_before_fullscreen_);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppapi_plugin_instance_impl.h b/content/renderer/pepper/ppapi_plugin_instance_impl.h
new file mode 100644
index 0000000..c5d22c4
--- /dev/null
+++ b/content/renderer/pepper/ppapi_plugin_instance_impl.h
@@ -0,0 +1,864 @@
+// 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_PPAPI_PLUGIN_INSTANCE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPAPI_PLUGIN_INSTANCE_IMPL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "cc/layers/texture_layer_client.h"
+#include "content/common/content_export.h"
+#include "content/public/renderer/ppapi_plugin_instance.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppp_pdf.h"
+#include "ppapi/c/dev/pp_cursor_type_dev.h"
+#include "ppapi/c/dev/ppp_find_dev.h"
+#include "ppapi/c/dev/ppp_printing_dev.h"
+#include "ppapi/c/dev/ppp_selection_dev.h"
+#include "ppapi/c/dev/ppp_text_input_dev.h"
+#include "ppapi/c/dev/ppp_zoom_dev.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_time.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/c/ppb_gamepad.h"
+#include "ppapi/c/ppb_input_event.h"
+#include "ppapi/c/ppp_graphics_3d.h"
+#include "ppapi/c/ppp_input_event.h"
+#include "ppapi/c/ppp_messaging.h"
+#include "ppapi/c/ppp_mouse_lock.h"
+#include "ppapi/c/private/ppb_content_decryptor_private.h"
+#include "ppapi/c/private/ppp_instance_private.h"
+#include "ppapi/shared_impl/ppb_instance_shared.h"
+#include "ppapi/shared_impl/ppb_view_shared.h"
+#include "ppapi/shared_impl/singleton_resource_id.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/ppb_gamepad_api.h"
+#include "ppapi/thunk/resource_creation_api.h"
+#include "skia/ext/refptr.h"
+#include "third_party/WebKit/public/platform/WebCanvas.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/web/WebPlugin.h"
+#include "third_party/WebKit/public/web/WebUserGestureToken.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/gfx/rect.h"
+#include "url/gurl.h"
+
+struct PP_Point;
+struct _NPP;
+
+class SkBitmap;
+class TransportDIB;
+
+namespace WebKit {
+class WebInputEvent;
+class WebLayer;
+class WebMouseEvent;
+class WebPluginContainer;
+class WebURLLoader;
+class WebURLResponse;
+struct WebCompositionUnderline;
+struct WebCursorInfo;
+struct WebURLError;
+struct WebPrintParams;
+}
+
+namespace cc {
+class TextureLayer;
+}
+
+namespace ppapi {
+class Resource;
+struct InputEventData;
+struct PPP_Instance_Combined;
+}
+
+namespace ui {
+class Range;
+}
+
+namespace v8 {
+class Isolate;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class ContentDecryptorDelegate;
+class FullscreenContainer;
+class MessageChannel;
+class PluginDelegate;
+class PluginModule;
+class PluginObject;
+class PPB_Graphics3D_Impl;
+class PPB_ImageData_Impl;
+class PPB_URLLoader_Impl;
+
+// Represents one time a plugin appears on one web page.
+//
+// Note: to get from a PP_Instance to a PluginInstance*, use the
+// ResourceTracker.
+class CONTENT_EXPORT PluginInstanceImpl
+ : public base::RefCounted<PluginInstanceImpl>,
+ public base::SupportsWeakPtr<PluginInstanceImpl>,
+ public NON_EXPORTED_BASE(PluginInstance),
+ public ::ppapi::PPB_Instance_Shared {
+ public:
+ // Create and return a PluginInstanceImpl object which supports the most
+ // recent version of PPP_Instance possible by querying the given
+ // get_plugin_interface function. If the plugin does not support any valid
+ // PPP_Instance interface, returns NULL.
+ static PluginInstanceImpl* Create(
+ PluginDelegate* delegate,
+ content::RenderView* render_view,
+ PluginModule* module,
+ WebKit::WebPluginContainer* container,
+ const GURL& plugin_url);
+ PluginDelegate* delegate() const { return delegate_; }
+ PluginModule* module() const { return module_.get(); }
+ MessageChannel& message_channel() { return *message_channel_; }
+
+ WebKit::WebPluginContainer* container() const { return container_; }
+
+ // Returns the PP_Instance uniquely identifying this instance. Guaranteed
+ // nonzero.
+ PP_Instance pp_instance() const { return pp_instance_; }
+
+ ::ppapi::PPP_Instance_Combined* instance_interface() const {
+ return instance_interface_.get();
+ }
+
+ ::ppapi::thunk::ResourceCreationAPI& resource_creation() {
+ return *resource_creation_.get();
+ }
+
+ // Does some pre-destructor cleanup on the instance. This is necessary
+ // because some cleanup depends on the plugin instance still existing (like
+ // calling the plugin's DidDestroy function). This function is called from
+ // the WebPlugin implementation when WebKit is about to remove the plugin.
+ void Delete();
+
+ // Paints the current backing store to the web page.
+ void Paint(WebKit::WebCanvas* canvas,
+ const gfx::Rect& plugin_rect,
+ const gfx::Rect& paint_rect);
+
+ // Schedules a paint of the page for the given region. The coordinates are
+ // relative to the top-left of the plugin. This does nothing if the plugin
+ // has not yet been positioned. You can supply an empty gfx::Rect() to
+ // invalidate the entire plugin.
+ void InvalidateRect(const gfx::Rect& rect);
+
+ // Schedules a scroll of the plugin. This uses optimized scrolling only for
+ // full-frame plugins, as otherwise there could be other elements on top. The
+ // slow path can also be triggered if there is an overlapping frame.
+ void ScrollRect(int dx, int dy, const gfx::Rect& rect);
+
+ // Commit the backing texture to the screen once the side effects some
+ // rendering up to an offscreen SwapBuffers are visible.
+ void CommitBackingTexture();
+
+ // Called when the out-of-process plugin implementing this instance crashed.
+ void InstanceCrashed();
+
+ // PPB_Instance and PPB_Instance_Private implementation.
+ bool full_frame() const { return full_frame_; }
+ const ::ppapi::ViewData& view_data() const { return view_data_; }
+
+ // 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 HandleDocumentLoad(const WebKit::WebURLResponse& response);
+ bool HandleInputEvent(const WebKit::WebInputEvent& event,
+ WebKit::WebCursorInfo* cursor_info);
+ PP_Var GetInstanceObject();
+ void ViewChanged(const gfx::Rect& position, const gfx::Rect& clip,
+ const std::vector<gfx::Rect>& cut_outs_rects);
+
+ // Handlers for composition events.
+ bool HandleCompositionStart(const base::string16& text);
+ bool HandleCompositionUpdate(
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end);
+ bool HandleCompositionEnd(const base::string16& text);
+ bool HandleTextInput(const base::string16& text);
+
+ // Gets the current text input status.
+ ui::TextInputType text_input_type() const { return text_input_type_; }
+ gfx::Rect GetCaretBounds() const;
+ bool IsPluginAcceptingCompositionEvents() const;
+ void GetSurroundingText(base::string16* text, ui::Range* range) const;
+
+ // Notifications about focus changes, see has_webkit_focus_ below.
+ void SetWebKitFocus(bool has_focus);
+ void SetContentAreaFocus(bool has_focus);
+
+ // Notification about page visibility. The default is "visible".
+ void PageVisibilityChanged(bool is_visible);
+
+ // Notifications that the view is about to paint, 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.
+ void ViewWillInitiatePaint();
+ void ViewInitiatedPaint();
+ void ViewFlushedPaint();
+
+ // If this plugin can be painted merely by copying the backing store to the
+ // screen, and the plugin bounds encloses the given paint bounds, returns
+ // true. In this case, the location, clipping, and ID of the backing store
+ // will be filled into the given output parameters.
+ bool GetBitmapForOptimizedPluginPaint(
+ const gfx::Rect& paint_bounds,
+ TransportDIB** dib,
+ gfx::Rect* dib_bounds,
+ gfx::Rect* clip,
+ float* scale_factor);
+
+ // Tracks all live PluginObjects.
+ void AddPluginObject(PluginObject* plugin_object);
+ void RemovePluginObject(PluginObject* plugin_object);
+
+ base::string16 GetSelectedText(bool html);
+ base::string16 GetLinkAtPosition(const gfx::Point& point);
+ void RequestSurroundingText(size_t desired_number_of_characters);
+ void Zoom(double factor, bool text_only);
+ bool StartFind(const base::string16& search_text,
+ bool case_sensitive,
+ int identifier);
+ void SelectFindResult(bool forward);
+ void StopFind();
+
+ bool SupportsPrintInterface();
+ bool IsPrintScalingDisabled();
+ int PrintBegin(const WebKit::WebPrintParams& print_params);
+ bool PrintPage(int page_number, WebKit::WebCanvas* canvas);
+ void PrintEnd();
+
+ bool CanRotateView();
+ void RotateView(WebKit::WebPlugin::RotationType type);
+
+ // Sets the bound_graphics_2d_platform_ for testing purposes. This is instead
+ // of calling BindGraphics and allows any PlatformGraphics implementation to
+ // be used, not just a resource one.
+ void SetBoundGraphics2DForTest(PluginDelegate::PlatformGraphics2D* graphics);
+
+ // There are 2 implementations of the fullscreen interface
+ // PPB_FlashFullscreen is used by Pepper Flash.
+ // PPB_Fullscreen is intended for other applications including NaCl.
+ // The two interface are mutually exclusive.
+
+ // Implementation of PPB_FlashFullscreen.
+
+ // Because going to fullscreen is asynchronous (but going out is not), there
+ // are 3 states:
+ // - normal : fullscreen_container_ == NULL
+ // flash_fullscreen_ == false
+ // - fullscreen pending: fullscreen_container_ != NULL
+ // flash_fullscreen_ == false
+ // - fullscreen : fullscreen_container_ != NULL
+ // flash_fullscreen_ == true
+ //
+ // In normal state, events come from webkit and painting goes back to it.
+ // In fullscreen state, events come from the fullscreen container, and
+ // painting goes back to it.
+ // In pending state, events from webkit are ignored, and as soon as we
+ // receive events from the fullscreen container, we go to the fullscreen
+ // state.
+ bool FlashIsFullscreenOrPending();
+
+ // Updates |flash_fullscreen_| and sends focus change notification if
+ // necessary.
+ void UpdateFlashFullscreenState(bool flash_fullscreen);
+
+ FullscreenContainer* fullscreen_container() const {
+ return fullscreen_container_;
+ }
+
+ // Implementation of PPB_Fullscreen.
+
+ // Because going to/from fullscreen is asynchronous, there are 4 states:
+ // - normal : desired_fullscreen_state_ == false
+ // view_data_.is_fullscreen == false
+ // - fullscreen pending: desired_fullscreen_state_ == true
+ // view_data_.is_fullscreen == false
+ // - fullscreen : desired_fullscreen_state_ == true
+ // view_data_.is_fullscreen == true
+ // - normal pending : desired_fullscreen_state_ = false
+ // view_data_.is_fullscreen = true
+ bool IsFullscreenOrPending();
+
+ bool flash_fullscreen() const { return flash_fullscreen_; }
+
+ // Switches between fullscreen and normal mode. The transition is
+ // asynchronous. WebKit will trigger corresponding VewChanged calls.
+ // Returns true on success, false on failure (e.g. trying to enter fullscreen
+ // when not processing a user gesture or trying to set fullscreen when
+ // already in fullscreen mode).
+ bool SetFullscreen(bool fullscreen);
+
+ // Implementation of PPP_Messaging.
+ void HandleMessage(PP_Var message);
+
+ PluginDelegate::PlatformContext3D* CreateContext3D();
+
+ // Returns true if the plugin is processing a user gesture.
+ bool IsProcessingUserGesture();
+
+ // Returns the user gesture token to use for creating a WebScopedUserGesture,
+ // if IsProcessingUserGesture returned true.
+ WebKit::WebUserGestureToken CurrentUserGestureToken();
+
+ // A mouse lock request was pending and this reports success or failure.
+ void OnLockMouseACK(bool succeeded);
+ // A mouse lock was in place, but has been lost.
+ void OnMouseLockLost();
+ // A mouse lock is enabled and mouse events are being delivered.
+ void HandleMouseLockedInputEvent(const WebKit::WebMouseEvent& event);
+
+ // Simulates an input event to the plugin by passing it down to WebKit,
+ // which sends it back up to the plugin as if it came from the user.
+ void SimulateInputEvent(const ::ppapi::InputEventData& input_event);
+
+ // Simulates an IME event at the level of RenderView which sends it back up to
+ // the plugin as if it came from the user.
+ bool SimulateIMEEvent(const ::ppapi::InputEventData& input_event);
+ void SimulateImeSetCompositionEvent(
+ const ::ppapi::InputEventData& input_event);
+
+ // The document loader is valid when the plugin is "full-frame" and in this
+ // case is non-NULL as long as the corresponding loader resource is alive.
+ // This pointer is non-owning, so the loader must use set_document_loader to
+ // clear itself when it is destroyed.
+ WebKit::WebURLLoaderClient* document_loader() const {
+ return document_loader_;
+ }
+ void set_document_loader(WebKit::WebURLLoaderClient* loader) {
+ document_loader_ = loader;
+ }
+
+ ContentDecryptorDelegate* GetContentDecryptorDelegate();
+
+ // webkit::ppapi::PluginInstance implementation
+ virtual content::RenderView* GetRenderView() OVERRIDE;
+ virtual WebKit::WebPluginContainer* GetContainer() OVERRIDE;
+ virtual ::ppapi::VarTracker* GetVarTracker() OVERRIDE;
+ virtual const GURL& GetPluginURL() OVERRIDE;
+ virtual base::FilePath GetModulePath() OVERRIDE;
+ virtual PP_Resource CreateExternalFileReference(
+ const base::FilePath& external_file_path) OVERRIDE;
+ virtual PP_Resource CreateImage(gfx::ImageSkia* source_image,
+ float scale) OVERRIDE;
+ virtual PP_ExternalPluginResult SwitchToOutOfProcessProxy(
+ const base::FilePath& file_path,
+ ::ppapi::PpapiPermissions permissions,
+ const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) OVERRIDE;
+ virtual void SetAlwaysOnTop(bool on_top) OVERRIDE;
+ virtual bool IsFullPagePlugin() OVERRIDE;
+ virtual void FlashSetFullscreen(bool fullscreen, bool delay_report) OVERRIDE;
+ virtual bool IsRectTopmost(const gfx::Rect& rect) OVERRIDE;
+ virtual int32_t Navigate(const ::ppapi::URLRequestInfoData& request,
+ const char* target,
+ bool from_user_action) OVERRIDE;
+
+ // PPB_Instance_API implementation.
+ virtual PP_Bool BindGraphics(PP_Instance instance,
+ PP_Resource device) OVERRIDE;
+ virtual PP_Bool IsFullFrame(PP_Instance instance) OVERRIDE;
+ virtual const ::ppapi::ViewData* GetViewData(PP_Instance instance) OVERRIDE;
+ virtual PP_Bool FlashIsFullscreen(PP_Instance instance) OVERRIDE;
+ virtual PP_Var GetWindowObject(PP_Instance instance) OVERRIDE;
+ virtual PP_Var GetOwnerElementObject(PP_Instance instance) OVERRIDE;
+ virtual PP_Var ExecuteScript(PP_Instance instance,
+ PP_Var script,
+ PP_Var* exception) OVERRIDE;
+ virtual uint32_t GetAudioHardwareOutputSampleRate(PP_Instance instance)
+ OVERRIDE;
+ virtual uint32_t GetAudioHardwareOutputBufferSize(PP_Instance instance)
+ OVERRIDE;
+ virtual PP_Var GetDefaultCharSet(PP_Instance instance) OVERRIDE;
+ virtual void NumberOfFindResultsChanged(PP_Instance instance,
+ int32_t total,
+ PP_Bool final_result) OVERRIDE;
+ virtual void SelectedFindResultChanged(PP_Instance instance,
+ int32_t index) OVERRIDE;
+ virtual PP_Bool IsFullscreen(PP_Instance instance) OVERRIDE;
+ virtual PP_Bool SetFullscreen(PP_Instance instance,
+ PP_Bool fullscreen) OVERRIDE;
+ virtual PP_Bool GetScreenSize(PP_Instance instance, PP_Size* size)
+ OVERRIDE;
+ virtual ::ppapi::Resource* GetSingletonResource(PP_Instance instance,
+ ::ppapi::SingletonResourceID id) OVERRIDE;
+ virtual int32_t RequestInputEvents(PP_Instance instance,
+ uint32_t event_classes) OVERRIDE;
+ virtual int32_t RequestFilteringInputEvents(PP_Instance instance,
+ uint32_t event_classes) OVERRIDE;
+ virtual void ClearInputEventRequest(PP_Instance instance,
+ uint32_t event_classes) OVERRIDE;
+ virtual void ZoomChanged(PP_Instance instance, double factor) OVERRIDE;
+ virtual void ZoomLimitsChanged(PP_Instance instance,
+ double minimum_factor,
+ double maximium_factor) OVERRIDE;
+ virtual void PostMessage(PP_Instance instance, PP_Var message) OVERRIDE;
+ virtual PP_Bool SetCursor(PP_Instance instance,
+ PP_MouseCursor_Type type,
+ PP_Resource image,
+ const PP_Point* hot_spot) OVERRIDE;
+ virtual int32_t LockMouse(
+ PP_Instance instance,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual void UnlockMouse(PP_Instance instance) OVERRIDE;
+ virtual void SetTextInputType(PP_Instance instance,
+ PP_TextInput_Type type) OVERRIDE;
+ virtual void UpdateCaretPosition(PP_Instance instance,
+ const PP_Rect& caret,
+ const PP_Rect& bounding_box) OVERRIDE;
+ virtual void CancelCompositionText(PP_Instance instance) OVERRIDE;
+ virtual void SelectionChanged(PP_Instance instance) OVERRIDE;
+ virtual void UpdateSurroundingText(PP_Instance instance,
+ const char* text,
+ uint32_t caret,
+ uint32_t anchor) OVERRIDE;
+ virtual PP_Var ResolveRelativeToDocument(
+ PP_Instance instance,
+ PP_Var relative,
+ PP_URLComponents_Dev* components) OVERRIDE;
+ virtual PP_Bool DocumentCanRequest(PP_Instance instance, PP_Var url) OVERRIDE;
+ virtual PP_Bool DocumentCanAccessDocument(PP_Instance instance,
+ PP_Instance target) OVERRIDE;
+ virtual PP_Var GetDocumentURL(PP_Instance instance,
+ PP_URLComponents_Dev* components) OVERRIDE;
+ virtual PP_Var GetPluginInstanceURL(
+ PP_Instance instance,
+ PP_URLComponents_Dev* components) OVERRIDE;
+
+ // PPB_ContentDecryptor_Private implementation.
+ virtual void NeedKey(PP_Instance instance,
+ PP_Var key_system,
+ PP_Var session_id,
+ PP_Var init_data) OVERRIDE;
+ virtual void KeyAdded(PP_Instance instance,
+ PP_Var key_system,
+ PP_Var session_id) OVERRIDE;
+ virtual void KeyMessage(PP_Instance instance,
+ PP_Var key_system,
+ PP_Var session_id,
+ PP_Var message,
+ PP_Var default_url) OVERRIDE;
+ virtual void KeyError(PP_Instance instance,
+ PP_Var key_system,
+ PP_Var session_id,
+ int32_t media_error,
+ int32_t system_code) OVERRIDE;
+ virtual void DeliverBlock(PP_Instance instance,
+ PP_Resource decrypted_block,
+ const PP_DecryptedBlockInfo* block_info) OVERRIDE;
+ virtual void DecoderInitializeDone(PP_Instance instance,
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id,
+ PP_Bool success) OVERRIDE;
+ virtual void DecoderDeinitializeDone(PP_Instance instance,
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id) OVERRIDE;
+ virtual void DecoderResetDone(PP_Instance instance,
+ PP_DecryptorStreamType decoder_type,
+ uint32_t request_id) OVERRIDE;
+ virtual void DeliverFrame(PP_Instance instance,
+ PP_Resource decrypted_frame,
+ const PP_DecryptedFrameInfo* frame_info) OVERRIDE;
+ virtual void DeliverSamples(PP_Instance instance,
+ PP_Resource audio_frames,
+ const PP_DecryptedBlockInfo* block_info) OVERRIDE;
+
+ // Reset this instance as proxied. Assigns the instance a new module, resets
+ // cached interfaces to point to the out-of-process proxy and re-sends
+ // DidCreate, DidChangeView, and HandleDocumentLoad (if necessary).
+ // This should be used only when switching an in-process instance to an
+ // external out-of-process instance.
+ PP_ExternalPluginResult ResetAsProxied(scoped_refptr<PluginModule> module);
+
+ // Checks whether this is a valid instance of the given module. After calling
+ // ResetAsProxied above, a NaCl plugin instance's module changes, so external
+ // hosts won't recognize it as a valid instance of the original module. This
+ // method fixes that be checking that either module_ or original_module_ match
+ // the given module.
+ bool IsValidInstanceOf(PluginModule* module);
+
+ // Returns the plugin NPP identifier that this plugin will use to identify
+ // itself when making NPObject scripting calls to WebBindings.
+ struct _NPP* instanceNPP();
+
+ // Returns the v8::Isolate that was current when this Instance was created.
+ // This is not inlined so as to avoid an unnecessary header include of v8.h.
+ v8::Isolate* GetIsolate() const;
+
+ private:
+ friend class base::RefCounted<PluginInstanceImpl>;
+ friend class PpapiUnittest;
+
+ // Delete should be called by the WebPlugin before this destructor.
+ virtual ~PluginInstanceImpl();
+
+ // Class to record document load notifications and play them back once the
+ // real document loader becomes available. Used only by NaCl instances.
+ class NaClDocumentLoader : public WebKit::WebURLLoaderClient {
+ public:
+ NaClDocumentLoader();
+ virtual ~NaClDocumentLoader();
+
+ void ReplayReceivedData(WebURLLoaderClient* document_loader);
+
+ // WebKit::WebURLLoaderClient implementation.
+ virtual void didReceiveData(WebKit::WebURLLoader* loader,
+ const char* data,
+ int data_length,
+ int encoded_data_length);
+ virtual void didFinishLoading(WebKit::WebURLLoader* loader,
+ double finish_time);
+ virtual void didFail(WebKit::WebURLLoader* loader,
+ const WebKit::WebURLError& error);
+
+ private:
+ std::list<std::string> data_;
+ bool finished_loading_;
+ scoped_ptr<WebKit::WebURLError> error_;
+ };
+
+ // Implements PPB_Gamepad_API. This is just to avoid having an excessive
+ // number of interfaces implemented by PluginInstanceImpl.
+ class GamepadImpl : public ::ppapi::thunk::PPB_Gamepad_API,
+ public ::ppapi::Resource {
+ public:
+ explicit GamepadImpl(PluginDelegate* delegate);
+ // Resource implementation.
+ virtual ::ppapi::thunk::PPB_Gamepad_API* AsPPB_Gamepad_API() OVERRIDE;
+ virtual void Sample(PP_Instance instance,
+ PP_GamepadsSampleData* data) OVERRIDE;
+ private:
+ virtual ~GamepadImpl();
+ PluginDelegate* delegate_;
+ };
+
+ // See the static Create functions above for creating PluginInstanceImpl
+ // objects. This constructor is private so that we can hide the
+ // PPP_Instance_Combined details while still having 1 constructor to maintain
+ // for member initialization.
+ PluginInstanceImpl(PluginDelegate* delegate,
+ content::RenderView* render_view,
+ PluginModule* module,
+ ::ppapi::PPP_Instance_Combined* instance_interface,
+ WebKit::WebPluginContainer* container,
+ const GURL& plugin_url);
+
+ bool LoadFindInterface();
+ bool LoadInputEventInterface();
+ bool LoadMessagingInterface();
+ bool LoadMouseLockInterface();
+ bool LoadPdfInterface();
+ bool LoadPrintInterface();
+ bool LoadPrivateInterface();
+ bool LoadSelectionInterface();
+ bool LoadTextInputInterface();
+ bool LoadZoomInterface();
+
+ // Determines if we think the plugin has focus, both content area and webkit
+ // (see has_webkit_focus_ below).
+ bool PluginHasFocus() const;
+ void SendFocusChangeNotification();
+
+ void UpdateTouchEventRequest();
+
+ // Returns true if the plugin has registered to accept wheel events.
+ bool IsAcceptingWheelEvents() const;
+
+ void ScheduleAsyncDidChangeView();
+ void SendAsyncDidChangeView();
+ void SendDidChangeView();
+
+ // Reports the current plugin geometry to the plugin by calling
+ // DidChangeView.
+ void ReportGeometry();
+
+ // Queries the plugin for supported print formats and sets |format| to the
+ // best format to use. Returns false if the plugin does not support any
+ // print format that we can handle (we can handle only PDF).
+ bool GetPreferredPrintOutputFormat(PP_PrintOutputFormat_Dev* format);
+ bool PrintPDFOutput(PP_Resource print_output, WebKit::WebCanvas* canvas);
+
+ // Get the bound graphics context as a concrete 2D graphics context or returns
+ // null if the context is not 2D.
+ PluginDelegate::PlatformGraphics2D* GetBoundGraphics2D() const;
+
+ // Updates the layer for compositing. This creates a layer and attaches to the
+ // container if:
+ // - we have a bound Graphics3D
+ // - the Graphics3D has a texture
+ // - we are not in Flash full-screen mode (or transitioning to it)
+ // Otherwise it destroys the layer.
+ // It does either operation lazily.
+ void UpdateLayer();
+
+ // Internal helper function for PrintPage().
+ bool PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges,
+ int num_ranges,
+ WebKit::WebCanvas* canvas);
+
+ void DoSetCursor(WebKit::WebCursorInfo* cursor);
+
+ // Internal helper functions for HandleCompositionXXX().
+ bool SendCompositionEventToPlugin(
+ PP_InputEvent_Type type,
+ const base::string16& text);
+ bool SendCompositionEventWithUnderlineInformationToPlugin(
+ PP_InputEvent_Type type,
+ const base::string16& text,
+ const std::vector<WebKit::WebCompositionUnderline>& underlines,
+ int selection_start,
+ int selection_end);
+
+ // Internal helper function for XXXInputEvents().
+ void RequestInputEventsHelper(uint32_t event_classes);
+
+ // Checks if the security origin of the document containing this instance can
+ // assess the security origin of the main frame document.
+ bool CanAccessMainFrame() const;
+
+ // Returns true if the WebView the plugin is in renders via the accelerated
+ // compositing path.
+ bool IsViewAccelerated();
+
+ // Track, set and reset size attributes to control the size of the plugin
+ // in and out of fullscreen mode.
+ void KeepSizeAttributesBeforeFullscreen();
+ void SetSizeAttributesForFullscreen();
+ void ResetSizeAttributesAfterFullscreen();
+
+ PluginDelegate* delegate_;
+ content::RenderView* render_view_;
+ scoped_refptr<PluginModule> module_;
+ scoped_ptr< ::ppapi::PPP_Instance_Combined> instance_interface_;
+ // If this is the NaCl plugin, we create a new module when we switch to the
+ // IPC-based PPAPI proxy. Store the original module and instance interface
+ // so we can shut down properly.
+ scoped_refptr<PluginModule> original_module_;
+ scoped_ptr< ::ppapi::PPP_Instance_Combined> original_instance_interface_;
+
+ PP_Instance pp_instance_;
+
+ // NULL until we have been initialized.
+ WebKit::WebPluginContainer* container_;
+ scoped_refptr<cc::TextureLayer> texture_layer_;
+ scoped_ptr<WebKit::WebLayer> web_layer_;
+ bool layer_bound_to_fullscreen_;
+
+ // Plugin URL.
+ GURL plugin_url_;
+
+ // Indicates whether this is a full frame instance, which means it represents
+ // an entire document rather than an embed tag.
+ bool full_frame_;
+
+ // Stores the current state of the plugin view.
+ ::ppapi::ViewData view_data_;
+ // 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_;
+
+ // 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
+ // same as the default values.
+ bool sent_initial_did_change_view_;
+
+ // 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
+ // view_data_ but not send updates. This also allows us to cancel scheduled
+ // view change events.
+ base::WeakPtrFactory<PluginInstanceImpl> view_change_weak_ptr_factory_;
+
+ // The current device context for painting in 2D and 3D.
+ scoped_refptr<PPB_Graphics3D_Impl> bound_graphics_3d_;
+ PluginDelegate::PlatformGraphics2D* bound_graphics_2d_platform_;
+
+ // We track two types of focus, one from WebKit, which is the focus among
+ // all elements of the page, one one from the browser, which is whether the
+ // tab/window has focus. We tell the plugin it has focus only when both of
+ // these values are set to true.
+ bool has_webkit_focus_;
+ bool has_content_area_focus_;
+
+ // The id of the current find operation, or -1 if none is in process.
+ int find_identifier_;
+
+ // Helper object that creates resources.
+ scoped_ptr< ::ppapi::thunk::ResourceCreationAPI> resource_creation_;
+
+ // The plugin-provided interfaces.
+ // When adding PPP interfaces, make sure to reset them in ResetAsProxied.
+ const PPP_Find_Dev* plugin_find_interface_;
+ const PPP_InputEvent* plugin_input_event_interface_;
+ const PPP_Messaging* plugin_messaging_interface_;
+ const PPP_MouseLock* plugin_mouse_lock_interface_;
+ const PPP_Pdf* plugin_pdf_interface_;
+ const PPP_Instance_Private* plugin_private_interface_;
+ const PPP_Selection_Dev* plugin_selection_interface_;
+ const PPP_TextInput_Dev* plugin_textinput_interface_;
+ const PPP_Zoom_Dev* plugin_zoom_interface_;
+
+ // Flags indicating whether we have asked this plugin instance for the
+ // corresponding interfaces, so that we can ask only once.
+ // When adding flags, make sure to reset them in ResetAsProxied.
+ bool checked_for_plugin_input_event_interface_;
+ bool checked_for_plugin_messaging_interface_;
+ bool checked_for_plugin_pdf_interface_;
+
+ // This is only valid between a successful PrintBegin call and a PrintEnd
+ // call.
+ PP_PrintSettings_Dev current_print_settings_;
+#if defined(OS_MACOSX)
+ // On the Mac, when we draw the bitmap to the PDFContext, it seems necessary
+ // to keep the pixels valid until CGContextEndPage is called. We use this
+ // variable to hold on to the pixels.
+ scoped_refptr<PPB_ImageData_Impl> last_printed_page_;
+#endif // defined(OS_MACOSX)
+ // Always when printing to PDF on Linux and when printing for preview on Mac
+ // and Win, the entire document goes into one metafile. However, when users
+ // print only a subset of all the pages, it is impossible to know if a call
+ // to PrintPage() is the last call. Thus in PrintPage(), just store the page
+ // number in |ranges_|. The hack is in PrintEnd(), where a valid |canvas_|
+ // is preserved in PrintWebViewHelper::PrintPages. This makes it possible
+ // to generate the entire PDF given the variables below:
+ //
+ // The most recently used WebCanvas, guaranteed to be valid.
+ skia::RefPtr<WebKit::WebCanvas> canvas_;
+ // An array of page ranges.
+ std::vector<PP_PrintPageNumberRange_Dev> ranges_;
+
+ scoped_refptr< ::ppapi::Resource> gamepad_impl_;
+
+ // The plugin print interface.
+ const PPP_Printing_Dev* plugin_print_interface_;
+
+ // The plugin 3D interface.
+ const PPP_Graphics3D* plugin_graphics_3d_interface_;
+
+ // Contains the cursor if it's set by the plugin.
+ scoped_ptr<WebKit::WebCursorInfo> cursor_;
+
+ // Set to true if this plugin thinks it will always be on top. This allows us
+ // to use a more optimized painting path in some cases.
+ bool always_on_top_;
+ // Even if |always_on_top_| is true, the plugin is not fully visible if there
+ // are some cut-out areas (occupied by iframes higher in the stacking order).
+ // This information is used in the optimized painting path.
+ std::vector<gfx::Rect> cut_outs_rects_;
+
+ // Implementation of PPB_FlashFullscreen.
+
+ // Plugin container for fullscreen mode. NULL if not in fullscreen mode. Note:
+ // there is a transition state where fullscreen_container_ is non-NULL but
+ // flash_fullscreen_ is false (see above).
+ FullscreenContainer* fullscreen_container_;
+
+ // True if we are in "flash" fullscreen mode. False if we are in normal mode
+ // or in transition to fullscreen. Normal fullscreen mode is indicated in
+ // the ViewData.
+ bool flash_fullscreen_;
+
+ // Implementation of PPB_Fullscreen.
+
+ // Since entering fullscreen mode is an asynchronous operation, we set this
+ // variable to the desired state at the time we issue the fullscreen change
+ // request. The plugin will receive a DidChangeView event when it goes
+ // fullscreen.
+ bool desired_fullscreen_state_;
+
+ // WebKit does not resize the plugin when going into fullscreen mode, so we do
+ // this here by modifying the various plugin attributes and then restoring
+ // them on exit.
+ WebKit::WebString width_before_fullscreen_;
+ WebKit::WebString height_before_fullscreen_;
+ WebKit::WebString border_before_fullscreen_;
+ WebKit::WebString style_before_fullscreen_;
+ gfx::Size screen_size_for_fullscreen_;
+
+ // The MessageChannel used to implement bidirectional postMessage for the
+ // instance.
+ scoped_ptr<MessageChannel> message_channel_;
+
+ // Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
+ SkBitmap* sad_plugin_;
+
+ typedef std::set<PluginObject*> PluginObjectSet;
+ PluginObjectSet live_plugin_objects_;
+
+ // Classes of events that the plugin has registered for, both for filtering
+ // and not. The bits are PP_INPUTEVENT_CLASS_*.
+ uint32_t input_event_mask_;
+ uint32_t filtered_input_event_mask_;
+
+ // Text composition status.
+ ui::TextInputType text_input_type_;
+ gfx::Rect text_input_caret_;
+ gfx::Rect text_input_caret_bounds_;
+ bool text_input_caret_set_;
+
+ // Text selection status.
+ std::string surrounding_text_;
+ size_t selection_caret_;
+ size_t selection_anchor_;
+
+ scoped_refptr< ::ppapi::TrackedCallback> lock_mouse_callback_;
+
+ // Track pending user gestures so out-of-process plugins can respond to
+ // a user gesture after it has been processed.
+ PP_TimeTicks pending_user_gesture_;
+ WebKit::WebUserGestureToken pending_user_gesture_token_;
+
+ // We store the arguments so we can re-send them if we are reset to talk to
+ // NaCl via the IPC NaCl proxy.
+ std::vector<std::string> argn_;
+ std::vector<std::string> argv_;
+
+ // Non-owning pointer to the document loader, if any.
+ WebKit::WebURLLoaderClient* document_loader_;
+ // State for deferring document loads. Used only by NaCl instances.
+ WebKit::WebURLResponse nacl_document_response_;
+ scoped_ptr<NaClDocumentLoader> nacl_document_loader_;
+ bool nacl_document_load_;
+
+ // The ContentDecryptorDelegate forwards PPP_ContentDecryptor_Private
+ // calls and handles PPB_ContentDecryptor_Private calls.
+ scoped_ptr<ContentDecryptorDelegate> content_decryptor_delegate_;
+
+ // Dummy NPP value used when calling in to WebBindings, to allow the bindings
+ // to correctly track NPObjects belonging to this plugin instance.
+ scoped_ptr<struct _NPP> npp_;
+
+ // We store the isolate at construction so that we can be sure to use the
+ // Isolate in which this Instance was created when interacting with v8.
+ v8::Isolate* isolate_;
+
+ friend class PpapiPluginInstanceTest;
+ DISALLOW_COPY_AND_ASSIGN(PluginInstanceImpl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPAPI_PLUGIN_INSTANCE_IMPL_H_
diff --git a/content/renderer/pepper/ppapi_plugin_instance_unittest.cc b/content/renderer/pepper/ppapi_plugin_instance_unittest.cc
new file mode 100644
index 0000000..ceaac04
--- /dev/null
+++ b/content/renderer/pepper/ppapi_plugin_instance_unittest.cc
@@ -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.
+
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppapi_unittest.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/safe_integer_conversions.h"
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+// A mock graphics object to bind. We only have to implement enough so that
+// GetBitmapForOptimizedPluginPaint runs.
+//
+// If this is eventually all moved to content, we can simplify this. The
+// point here is that we need to just have a bound graphics 2d resource host
+// with the right properties.
+class MockPlatformGraphics2D : public PluginDelegate::PlatformGraphics2D {
+ public:
+ // The image data pointer must outlive this class.
+ MockPlatformGraphics2D(PPB_ImageData_Impl* image_data, float scale)
+ : image_data_(image_data),
+ scale_(scale),
+ bound_instance_(NULL) {
+ }
+ virtual ~MockPlatformGraphics2D() {
+ if (bound_instance_)
+ bound_instance_->SetBoundGraphics2DForTest(NULL);
+ }
+
+ virtual bool ReadImageData(PP_Resource image,
+ const PP_Point* top_left) OVERRIDE {
+ return false;
+ }
+ virtual bool BindToInstance(PluginInstanceImpl* new_instance) OVERRIDE {
+ bound_instance_ = new_instance;
+ return true;
+ }
+ virtual void Paint(WebKit::WebCanvas* canvas,
+ const gfx::Rect& plugin_rect,
+ const gfx::Rect& paint_rect) OVERRIDE {}
+ virtual void ViewWillInitiatePaint() OVERRIDE {}
+ virtual void ViewInitiatedPaint() OVERRIDE {}
+ virtual void ViewFlushedPaint() OVERRIDE {}
+
+ virtual bool IsAlwaysOpaque() const OVERRIDE { return true; }
+ virtual void SetScale(float scale) OVERRIDE {}
+ virtual float GetScale() const OVERRIDE { return scale_; }
+ virtual PPB_ImageData_Impl* ImageData() OVERRIDE {
+ return image_data_;
+ }
+
+ private:
+ PPB_ImageData_Impl* image_data_;
+ float scale_;
+ PluginInstanceImpl* bound_instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPlatformGraphics2D);
+};
+
+} // namespace
+
+// This class is forward-declared as a friend so can't be in the anonymous
+// namespace.
+class PpapiPluginInstanceTest : public PpapiUnittest {
+ public:
+ bool GetBitmapForOptimizedPluginPaint(const gfx::Rect& paint_bounds,
+ TransportDIB** dib,
+ gfx::Rect* location,
+ gfx::Rect* clip,
+ float* scale_factor) {
+ return !!instance()->GetBitmapForOptimizedPluginPaint(
+ paint_bounds, dib, location, clip, scale_factor);
+ }
+};
+
+
+// Test that GetBitmapForOptimizedPluginPaint doesn't return a bitmap rect
+// that's bigger than the actual backing store bitmap.
+TEST_F(PpapiPluginInstanceTest, GetBitmap2xScale) {
+ PP_Size size;
+ size.width = 3;
+ size.height = 3;
+
+ scoped_refptr<PPB_ImageData_Impl> image_data = new PPB_ImageData_Impl(
+ instance()->pp_instance(), PPB_ImageData_Impl::PLATFORM);
+ image_data->Init(PPB_ImageData_Impl::GetNativeImageDataFormat(),
+ size.width, size.height, true);
+ ASSERT_TRUE(image_data->Map() != NULL);
+
+ float scale = 2.0;
+ MockPlatformGraphics2D mock_graphics_2d(image_data.get(), 1.0 / scale);
+ instance()->SetBoundGraphics2DForTest(&mock_graphics_2d);
+
+ instance()->SetAlwaysOnTop(true);
+ SetViewSize(size.width, size.height);
+
+ gfx::Rect bounds(0, 0, 1, 1);
+ gfx::Rect location;
+ gfx::Rect clip;
+ float bitmap_scale = 0;
+ TransportDIB* dib = NULL;
+ EXPECT_TRUE(GetBitmapForOptimizedPluginPaint(
+ bounds, &dib, &location, &clip, &bitmap_scale));
+
+ EXPECT_EQ(0, location.x());
+ EXPECT_EQ(0, location.y());
+ EXPECT_EQ(gfx::ToFlooredInt(size.width / scale), location.width());
+ EXPECT_EQ(gfx::ToFlooredInt(size.height / scale), location.height());
+ EXPECT_EQ(0, clip.x());
+ EXPECT_EQ(0, clip.y());
+ EXPECT_EQ(size.width, clip.width());
+ EXPECT_EQ(size.height, clip.height());
+ EXPECT_EQ(scale, bitmap_scale);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppapi_unittest.cc b/content/renderer/pepper/ppapi_unittest.cc
new file mode 100644
index 0000000..e6edf94
--- /dev/null
+++ b/content/renderer/pepper/ppapi_unittest.cc
@@ -0,0 +1,169 @@
+// 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/ppapi_unittest.h"
+
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/mock_plugin_delegate.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_interface_factory.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+PpapiUnittest* current_unittest = NULL;
+
+const void* MockGetInterface(const char* interface_name) {
+ return current_unittest->GetMockInterface(interface_name);
+}
+
+int MockInitializeModule(PP_Module, PPB_GetInterface) {
+ return PP_OK;
+}
+
+// PPP_Instance implementation ------------------------------------------------
+
+PP_Bool Instance_DidCreate(PP_Instance pp_instance,
+ uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+ return PP_TRUE;
+}
+
+void Instance_DidDestroy(PP_Instance instance) {
+}
+
+void Instance_DidChangeView(PP_Instance pp_instance, PP_Resource view) {
+}
+
+void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
+}
+
+PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
+ PP_Resource pp_url_loader) {
+ return PP_FALSE;
+}
+
+static PPP_Instance mock_instance_interface = {
+ &Instance_DidCreate,
+ &Instance_DidDestroy,
+ &Instance_DidChangeView,
+ &Instance_DidChangeFocus,
+ &Instance_HandleDocumentLoad
+};
+
+} // namespace
+
+// PpapiUnittest --------------------------------------------------------------
+
+PpapiUnittest::PpapiUnittest() {
+ DCHECK(!current_unittest);
+ current_unittest = this;
+}
+
+PpapiUnittest::~PpapiUnittest() {
+ DCHECK(current_unittest == this);
+ current_unittest = NULL;
+}
+
+void PpapiUnittest::SetUp() {
+ message_loop_.reset(new base::MessageLoop());
+ delegate_.reset(NewPluginDelegate());
+
+ // Initialize the mock module.
+ module_ = new PluginModule("Mock plugin", base::FilePath(),
+ ::ppapi::PpapiPermissions());
+ ::ppapi::PpapiGlobals::Get()->ResetMainThreadMessageLoopForTesting();
+ content::PepperPluginInfo::EntryPoints entry_points;
+ entry_points.get_interface = &MockGetInterface;
+ entry_points.initialize_module = &MockInitializeModule;
+ ASSERT_TRUE(module_->InitAsInternalPlugin(entry_points));
+
+ // Initialize the mock instance.
+ instance_ = PluginInstanceImpl::Create(
+ delegate_.get(), NULL, module(), NULL, GURL());
+}
+
+void PpapiUnittest::TearDown() {
+ instance_ = NULL;
+ module_ = NULL;
+ message_loop_.reset();
+ PluginModule::ResetHostGlobalsForTest();
+}
+
+MockPluginDelegate* PpapiUnittest::NewPluginDelegate() {
+ return new MockPluginDelegate;
+}
+
+const void* PpapiUnittest::GetMockInterface(const char* interface_name) const {
+ if (strcmp(interface_name, PPP_INSTANCE_INTERFACE_1_0) == 0)
+ return &mock_instance_interface;
+ return NULL;
+}
+
+void PpapiUnittest::ShutdownModule() {
+ DCHECK(instance_->HasOneRef());
+ instance_ = NULL;
+ DCHECK(module_->HasOneRef());
+ module_ = NULL;
+}
+
+void PpapiUnittest::SetViewSize(int width, int height) const {
+ instance_->view_data_.rect = PP_FromGfxRect(gfx::Rect(0, 0, width, height));
+ instance_->view_data_.clip_rect = instance_->view_data_.rect;
+}
+
+// Tests whether custom PPAPI interface factories are called when PPAPI
+// interfaces are requested.
+class PpapiCustomInterfaceFactoryTest : public PpapiUnittest {
+ public:
+ PpapiCustomInterfaceFactoryTest() {}
+ virtual ~PpapiCustomInterfaceFactoryTest() {}
+
+ bool result() {
+ return result_;
+ }
+
+ void reset_result() {
+ result_ = false;
+ }
+
+ static const void* InterfaceFactory(const std::string& interface_name) {
+ result_ = true;
+ return NULL;
+ }
+
+ private:
+ static bool result_;
+};
+
+bool PpapiCustomInterfaceFactoryTest::result_ = false;
+
+// This test validates whether custom PPAPI interface factories are invoked in
+// response to PluginModule::GetPluginInterface calls.
+TEST_F(PpapiCustomInterfaceFactoryTest, BasicFactoryTest) {
+ PpapiInterfaceFactoryManager::GetInstance()->RegisterFactory(
+ PpapiCustomInterfaceFactoryTest::InterfaceFactory);
+ (*PluginModule::GetLocalGetInterfaceFunc())("DummyInterface");
+ EXPECT_TRUE(result());
+
+ reset_result();
+ PpapiInterfaceFactoryManager::GetInstance()->UnregisterFactory(
+ PpapiCustomInterfaceFactoryTest::InterfaceFactory);
+
+ (*PluginModule::GetLocalGetInterfaceFunc())("DummyInterface");
+ EXPECT_FALSE(result());
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppapi_unittest.h b/content/renderer/pepper/ppapi_unittest.h
new file mode 100644
index 0000000..e7fd8f2
--- /dev/null
+++ b/content/renderer/pepper/ppapi_unittest.h
@@ -0,0 +1,65 @@
+// 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_PEPPER_PPAPI_UNITTEST_H_
+#define CONTENT_RENDERER_PEPPER_PPAPI_UNITTEST_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class MockPluginDelegate;
+class PluginInstanceImpl;
+class PluginModule;
+
+class PpapiUnittest : public testing::Test {
+ public:
+ PpapiUnittest();
+ virtual ~PpapiUnittest();
+
+ virtual void SetUp();
+ virtual void TearDown();
+
+ MockPluginDelegate* delegate() { return delegate_.get(); }
+ PluginModule* module() const { return module_.get(); }
+ PluginInstanceImpl* instance() const { return instance_.get(); }
+
+ // Provides access to the interfaces implemented by the test. The default one
+ // implements PPP_INSTANCE.
+ virtual const void* GetMockInterface(const char* interface_name) const;
+
+ // Deletes the instance and module to simulate module shutdown.
+ void ShutdownModule();
+
+ // Sets the view size of the plugin instance.
+ void SetViewSize(int width, int height) const;
+
+ protected:
+ virtual MockPluginDelegate* NewPluginDelegate();
+
+ private:
+ scoped_ptr<MockPluginDelegate> delegate_;
+
+ // Note: module must be declared first since we want it to get destroyed last.
+ scoped_refptr<PluginModule> module_;
+ scoped_refptr<PluginInstanceImpl> instance_;
+
+ scoped_ptr<base::MessageLoop> message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(PpapiUnittest);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPAPI_UNITTEST_H_
diff --git a/content/renderer/pepper/ppapi_webplugin_impl.cc b/content/renderer/pepper/ppapi_webplugin_impl.cc
new file mode 100644
index 0000000..a3bca36
--- /dev/null
+++ b/content/renderer/pepper/ppapi_webplugin_impl.cc
@@ -0,0 +1,308 @@
+// 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/ppapi_webplugin_impl.h"
+
+#include <cmath>
+
+#include "base/debug/crash_logging.h"
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/message_channel.h"
+#include "content/renderer/pepper/npobject_var.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "third_party/WebKit/public/platform/WebPoint.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#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/WebPrintScalingOption.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "url/gurl.h"
+
+using ppapi::NPObjectVar;
+using WebKit::WebCanvas;
+using WebKit::WebPlugin;
+using WebKit::WebPluginContainer;
+using WebKit::WebPluginParams;
+using WebKit::WebPoint;
+using WebKit::WebPrintParams;
+using WebKit::WebRect;
+using WebKit::WebSize;
+using WebKit::WebString;
+using WebKit::WebURL;
+using WebKit::WebVector;
+using WebKit::WebView;
+
+namespace webkit {
+namespace ppapi {
+
+struct WebPluginImpl::InitData {
+ scoped_refptr<PluginModule> module;
+ base::WeakPtr<PluginDelegate> delegate;
+ base::WeakPtr<content::RenderView> render_view;
+ std::vector<std::string> arg_names;
+ std::vector<std::string> arg_values;
+ GURL url;
+};
+
+WebPluginImpl::WebPluginImpl(
+ PluginModule* plugin_module,
+ const WebPluginParams& params,
+ const base::WeakPtr<PluginDelegate>& plugin_delegate,
+ const base::WeakPtr<content::RenderView>& render_view)
+ : init_data_(new InitData()),
+ full_frame_(params.loadManually),
+ instance_object_(PP_MakeUndefined()),
+ container_(NULL) {
+ DCHECK(plugin_module);
+ init_data_->module = plugin_module;
+ init_data_->delegate = plugin_delegate;
+ init_data_->render_view = render_view;
+ for (size_t i = 0; i < params.attributeNames.size(); ++i) {
+ init_data_->arg_names.push_back(params.attributeNames[i].utf8());
+ init_data_->arg_values.push_back(params.attributeValues[i].utf8());
+ }
+ init_data_->url = params.url;
+
+ // Set subresource URL for crash reporting.
+ base::debug::SetCrashKeyValue("subresource_url", init_data_->url.spec());
+}
+
+WebPluginImpl::~WebPluginImpl() {
+}
+
+WebKit::WebPluginContainer* WebPluginImpl::container() const {
+ return container_;
+}
+
+bool WebPluginImpl::initialize(WebPluginContainer* container) {
+ // The plugin delegate may have gone away.
+ if (!init_data_->delegate.get())
+ return false;
+
+ instance_ = init_data_->module->CreateInstance(
+ init_data_->delegate.get(), init_data_->render_view.get(), container,
+ init_data_->url);
+ if (!instance_.get())
+ return false;
+
+ // Enable script objects for this plugin.
+ container->allowScriptObjects();
+
+ bool success = instance_->Initialize(init_data_->arg_names,
+ init_data_->arg_values,
+ full_frame_);
+ if (!success) {
+ instance_->Delete();
+ instance_ = NULL;
+
+ WebKit::WebPlugin* replacement_plugin =
+ init_data_->delegate->CreatePluginReplacement(
+ init_data_->module->path());
+ if (!replacement_plugin || !replacement_plugin->initialize(container))
+ return false;
+
+ container->setPlugin(replacement_plugin);
+ return true;
+ }
+
+ init_data_.reset();
+ container_ = container;
+ return true;
+}
+
+void WebPluginImpl::destroy() {
+ // Tell |container_| to clear references to this plugin's script objects.
+ if (container_)
+ container_->clearScriptObjects();
+
+ if (instance_.get()) {
+ ::ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(instance_object_);
+ instance_object_ = PP_MakeUndefined();
+ instance_->Delete();
+ instance_ = NULL;
+ }
+
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+NPObject* WebPluginImpl::scriptableObject() {
+ // Call through the plugin to get its instance object. The plugin should pass
+ // us a reference which we release in destroy().
+ if (instance_object_.type == PP_VARTYPE_UNDEFINED)
+ instance_object_ = instance_->GetInstanceObject();
+ // GetInstanceObject talked to the plugin which may have removed the instance
+ // from the DOM, in which case instance_ would be NULL now.
+ if (!instance_.get())
+ return NULL;
+
+ scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(instance_object_));
+ // If there's an InstanceObject, tell the Instance's MessageChannel to pass
+ // any non-postMessage calls to it.
+ if (object.get()) {
+ instance_->message_channel().SetPassthroughObject(object->np_object());
+ }
+ NPObject* message_channel_np_object(instance_->message_channel().np_object());
+ // The object is expected to be retained before it is returned.
+ WebKit::WebBindings::retainObject(message_channel_np_object);
+ return message_channel_np_object;
+}
+
+NPP WebPluginImpl::pluginNPP() {
+ return instance_->instanceNPP();
+}
+
+bool WebPluginImpl::getFormValue(WebString& value) {
+ return false;
+}
+
+void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) {
+ if (!instance_->FlashIsFullscreenOrPending())
+ instance_->Paint(canvas, plugin_rect_, rect);
+}
+
+void WebPluginImpl::updateGeometry(
+ const WebRect& window_rect,
+ const WebRect& clip_rect,
+ const WebVector<WebRect>& cut_outs_rects,
+ bool is_visible) {
+ plugin_rect_ = window_rect;
+ if (!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);
+ }
+}
+
+void WebPluginImpl::updateFocus(bool focused) {
+ instance_->SetWebKitFocus(focused);
+}
+
+void WebPluginImpl::updateVisibility(bool visible) {
+}
+
+bool WebPluginImpl::acceptsInputEvents() {
+ return true;
+}
+
+bool WebPluginImpl::handleInputEvent(const WebKit::WebInputEvent& event,
+ WebKit::WebCursorInfo& cursor_info) {
+ if (instance_->FlashIsFullscreenOrPending())
+ return false;
+ return instance_->HandleInputEvent(event, &cursor_info);
+}
+
+void WebPluginImpl::didReceiveResponse(
+ const WebKit::WebURLResponse& response) {
+ DCHECK(!instance_->document_loader());
+ instance_->HandleDocumentLoad(response);
+}
+
+void WebPluginImpl::didReceiveData(const char* data, int data_length) {
+ WebKit::WebURLLoaderClient* document_loader = instance_->document_loader();
+ if (document_loader)
+ document_loader->didReceiveData(NULL, data, data_length, 0);
+}
+
+void WebPluginImpl::didFinishLoading() {
+ WebKit::WebURLLoaderClient* document_loader = instance_->document_loader();
+ if (document_loader)
+ document_loader->didFinishLoading(NULL, 0.0);
+}
+
+void WebPluginImpl::didFailLoading(const WebKit::WebURLError& error) {
+ WebKit::WebURLLoaderClient* document_loader = instance_->document_loader();
+ if (document_loader)
+ document_loader->didFail(NULL, error);
+}
+
+void WebPluginImpl::didFinishLoadingFrameRequest(const WebKit::WebURL& url,
+ void* notify_data) {
+}
+
+void WebPluginImpl::didFailLoadingFrameRequest(
+ const WebKit::WebURL& url,
+ void* notify_data,
+ const WebKit::WebURLError& error) {
+}
+
+bool WebPluginImpl::hasSelection() const {
+ return !selectionAsText().isEmpty();
+}
+
+WebString WebPluginImpl::selectionAsText() const {
+ return instance_->GetSelectedText(false);
+}
+
+WebString WebPluginImpl::selectionAsMarkup() const {
+ return instance_->GetSelectedText(true);
+}
+
+WebURL WebPluginImpl::linkAtPosition(const WebPoint& position) const {
+ return GURL(instance_->GetLinkAtPosition(position));
+}
+
+void WebPluginImpl::setZoomLevel(double level, bool text_only) {
+ instance_->Zoom(WebView::zoomLevelToZoomFactor(level), text_only);
+}
+
+bool WebPluginImpl::startFind(const WebKit::WebString& search_text,
+ bool case_sensitive,
+ int identifier) {
+ return instance_->StartFind(search_text, case_sensitive, identifier);
+}
+
+void WebPluginImpl::selectFindResult(bool forward) {
+ instance_->SelectFindResult(forward);
+}
+
+void WebPluginImpl::stopFind() {
+ instance_->StopFind();
+}
+
+bool WebPluginImpl::supportsPaginatedPrint() {
+ return instance_->SupportsPrintInterface();
+}
+
+bool WebPluginImpl::isPrintScalingDisabled() {
+ return instance_->IsPrintScalingDisabled();
+}
+
+int WebPluginImpl::printBegin(const WebPrintParams& print_params) {
+ return instance_->PrintBegin(print_params);
+}
+
+bool WebPluginImpl::printPage(int page_number,
+ WebKit::WebCanvas* canvas) {
+ return instance_->PrintPage(page_number, canvas);
+}
+
+void WebPluginImpl::printEnd() {
+ return instance_->PrintEnd();
+}
+
+bool WebPluginImpl::canRotateView() {
+ return instance_->CanRotateView();
+}
+
+void WebPluginImpl::rotateView(RotationType type) {
+ instance_->RotateView(type);
+}
+
+bool WebPluginImpl::isPlaceholder() {
+ return false;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppapi_webplugin_impl.h b/content/renderer/pepper/ppapi_webplugin_impl.h
new file mode 100644
index 0000000..ed26b75
--- /dev/null
+++ b/content/renderer/pepper/ppapi_webplugin_impl.h
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PPAPI_WEBPLUGIN_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPAPI_WEBPLUGIN_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#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"
+
+struct _NPP;
+
+namespace content {
+class RenderView;
+}
+
+namespace WebKit {
+struct WebPluginParams;
+struct WebPrintParams;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class PluginDelegate;
+class PluginInstanceImpl;
+class PluginModule;
+class PPB_URLLoader_Impl;
+
+class WebPluginImpl : public WebKit::WebPlugin {
+ public:
+ WebPluginImpl(PluginModule* module,
+ const WebKit::WebPluginParams& params,
+ const base::WeakPtr<PluginDelegate>& plugin_delegate,
+ const base::WeakPtr<content::RenderView>& render_view);
+
+ PluginInstanceImpl* instance() { return instance_.get(); }
+
+ // WebKit::WebPlugin implementation.
+ virtual WebKit::WebPluginContainer* container() const;
+ virtual bool initialize(WebKit::WebPluginContainer* container);
+ virtual void destroy();
+ virtual NPObject* scriptableObject();
+ virtual struct _NPP* pluginNPP();
+ virtual bool getFormValue(WebKit::WebString& value);
+ virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect);
+ virtual void updateGeometry(
+ const WebKit::WebRect& frame_rect,
+ const WebKit::WebRect& clip_rect,
+ const WebKit::WebVector<WebKit::WebRect>& cut_outs_rects,
+ bool is_visible);
+ virtual void updateFocus(bool focused);
+ virtual void updateVisibility(bool visible);
+ virtual bool acceptsInputEvents();
+ virtual bool handleInputEvent(const WebKit::WebInputEvent& event,
+ WebKit::WebCursorInfo& cursor_info);
+ virtual void didReceiveResponse(const WebKit::WebURLResponse& response);
+ virtual void didReceiveData(const char* data, int data_length);
+ virtual void didFinishLoading();
+ virtual void didFailLoading(const WebKit::WebURLError&);
+ virtual void didFinishLoadingFrameRequest(const WebKit::WebURL& url,
+ void* notify_data);
+ virtual void didFailLoadingFrameRequest(const WebKit::WebURL& url,
+ void* notify_data,
+ const WebKit::WebURLError& error);
+ virtual bool hasSelection() const;
+ virtual WebKit::WebString selectionAsText() const;
+ virtual WebKit::WebString selectionAsMarkup() const;
+ virtual WebKit::WebURL linkAtPosition(const WebKit::WebPoint& position) const;
+ virtual void setZoomLevel(double level, bool text_only);
+ virtual bool startFind(const WebKit::WebString& search_text,
+ bool case_sensitive,
+ int identifier);
+ virtual void selectFindResult(bool forward);
+ virtual void stopFind();
+ virtual bool supportsPaginatedPrint() OVERRIDE;
+ virtual bool isPrintScalingDisabled() OVERRIDE;
+
+ virtual int printBegin(const WebKit::WebPrintParams& print_params) OVERRIDE;
+ virtual bool printPage(int page_number, WebKit::WebCanvas* canvas) OVERRIDE;
+ virtual void printEnd() OVERRIDE;
+
+ virtual bool canRotateView() OVERRIDE;
+ virtual void rotateView(RotationType type) OVERRIDE;
+ virtual bool isPlaceholder() OVERRIDE;
+
+ private:
+ friend class base::DeleteHelper<WebPluginImpl>;
+
+ virtual ~WebPluginImpl();
+ struct InitData;
+
+ scoped_ptr<InitData> init_data_; // Cleared upon successful initialization.
+ // True if the instance represents the entire document in a frame instead of
+ // being an embedded resource.
+ bool full_frame_;
+ scoped_refptr<PluginInstanceImpl> instance_;
+ gfx::Rect plugin_rect_;
+ PP_Var instance_object_;
+ WebKit::WebPluginContainer* container_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebPluginImpl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPAPI_WEBPLUGIN_IMPL_H_
diff --git a/content/renderer/pepper/ppb_audio_impl.cc b/content/renderer/pepper/ppb_audio_impl.cc
new file mode 100644
index 0000000..5263826
--- /dev/null
+++ b/content/renderer/pepper/ppb_audio_impl.cc
@@ -0,0 +1,161 @@
+// 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/ppb_audio_impl.h"
+
+#include "base/logging.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "media/audio/audio_output_controller.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/ppb_audio.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_audio_config_api.h"
+#include "ppapi/thunk/thunk.h"
+
+using ppapi::PpapiGlobals;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Audio_API;
+using ppapi::thunk::PPB_AudioConfig_API;
+using ppapi::TrackedCallback;
+
+namespace webkit {
+namespace ppapi {
+
+// PPB_Audio_Impl --------------------------------------------------------------
+
+PPB_Audio_Impl::PPB_Audio_Impl(PP_Instance instance)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ audio_(NULL),
+ sample_frame_count_(0) {
+}
+
+PPB_Audio_Impl::~PPB_Audio_Impl() {
+ // 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
+ // OK since we'll just immediately clean up the data it stored later in this
+ // destructor.
+ if (audio_) {
+ audio_->ShutDown();
+ audio_ = NULL;
+ }
+}
+
+// static
+PP_Resource PPB_Audio_Impl::Create(PP_Instance instance,
+ PP_Resource config,
+ PPB_Audio_Callback audio_callback,
+ void* user_data) {
+ scoped_refptr<PPB_Audio_Impl> audio(new PPB_Audio_Impl(instance));
+ if (!audio->Init(config, audio_callback, user_data))
+ return 0;
+ return audio->GetReference();
+}
+
+PPB_Audio_API* PPB_Audio_Impl::AsPPB_Audio_API() {
+ return this;
+}
+
+bool PPB_Audio_Impl::Init(PP_Resource config,
+ PPB_Audio_Callback callback, void* user_data) {
+ // Validate the config and keep a reference to it.
+ EnterResourceNoLock<PPB_AudioConfig_API> enter(config, true);
+ if (enter.failed())
+ return false;
+ config_ = config;
+
+ if (!callback)
+ return false;
+ SetCallback(callback, user_data);
+
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return false;
+
+ // When the stream is created, we'll get called back on StreamCreated().
+ CHECK(!audio_);
+ audio_ = plugin_delegate->CreateAudioOutput(
+ enter.object()->GetSampleRate(), enter.object()->GetSampleFrameCount(),
+ this);
+ sample_frame_count_ = enter.object()->GetSampleFrameCount();
+ return audio_ != NULL;
+}
+
+PP_Resource PPB_Audio_Impl::GetCurrentConfig() {
+ // AddRef on behalf of caller, while keeping a ref for ourselves.
+ PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
+ return config_;
+}
+
+PP_Bool PPB_Audio_Impl::StartPlayback() {
+ if (!audio_)
+ return PP_FALSE;
+ if (playing())
+ return PP_TRUE;
+ SetStartPlaybackState();
+ return BoolToPPBool(audio_->StartPlayback());
+}
+
+PP_Bool PPB_Audio_Impl::StopPlayback() {
+ if (!audio_)
+ return PP_FALSE;
+ if (!playing())
+ return PP_TRUE;
+ if (!audio_->StopPlayback())
+ return PP_FALSE;
+ SetStopPlaybackState();
+ return PP_TRUE;
+}
+
+int32_t PPB_Audio_Impl::Open(
+ PP_Resource config,
+ scoped_refptr<TrackedCallback> create_callback) {
+ // Validate the config and keep a reference to it.
+ EnterResourceNoLock<PPB_AudioConfig_API> enter(config, true);
+ if (enter.failed())
+ return PP_ERROR_FAILED;
+ config_ = config;
+
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return PP_ERROR_FAILED;
+
+ // When the stream is created, we'll get called back on StreamCreated().
+ DCHECK(!audio_);
+ audio_ = plugin_delegate->CreateAudioOutput(
+ enter.object()->GetSampleRate(), enter.object()->GetSampleFrameCount(),
+ this);
+ if (!audio_)
+ return PP_ERROR_FAILED;
+
+ // At this point, we are guaranteeing ownership of the completion
+ // callback. Audio promises to fire the completion callback
+ // once and only once.
+ SetCreateCallback(create_callback);
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_Audio_Impl::GetSyncSocket(int* sync_socket) {
+ return GetSyncSocketImpl(sync_socket);
+}
+
+int32_t PPB_Audio_Impl::GetSharedMemory(int* shm_handle,
+ uint32_t* shm_size) {
+ return GetSharedMemoryImpl(shm_handle, shm_size);
+}
+
+void PPB_Audio_Impl::OnSetStreamInfo(
+ base::SharedMemoryHandle shared_memory_handle,
+ size_t shared_memory_size,
+ base::SyncSocket::Handle socket_handle) {
+ SetStreamInfo(pp_instance(), shared_memory_handle, shared_memory_size,
+ socket_handle, sample_frame_count_);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_audio_impl.h b/content/renderer/pepper/ppb_audio_impl.h
new file mode 100644
index 0000000..49146cb
--- /dev/null
+++ b/content/renderer/pepper/ppb_audio_impl.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PPB_AUDIO_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_AUDIO_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/sync_socket.h"
+#include "content/renderer/pepper/audio_helper.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/ppb_audio.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/shared_impl/ppb_audio_config_shared.h"
+#include "ppapi/shared_impl/ppb_audio_shared.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+
+namespace webkit {
+namespace ppapi {
+
+// Some of the backend functionality of this class is implemented by the
+// PPB_Audio_Shared so it can be shared with the proxy.
+class PPB_Audio_Impl : public ::ppapi::Resource,
+ public ::ppapi::PPB_Audio_Shared,
+ public AudioHelper {
+ public:
+ // Trusted initialization. You must call Init after this.
+ //
+ // Untrusted initialization should just call the static Create() function
+ // to properly create & initialize this class.
+ explicit PPB_Audio_Impl(PP_Instance instance);
+
+ // Creation function for untrusted plugins. This handles all initialization
+ // and will return 0 on failure.
+ static PP_Resource Create(PP_Instance instance,
+ PP_Resource config_id,
+ PPB_Audio_Callback audio_callback,
+ void* user_data);
+
+ // Initialization function for trusted init.
+ bool Init(PP_Resource config_id,
+ PPB_Audio_Callback user_callback,
+ void* user_data);
+
+ // Resource overrides.
+ virtual ::ppapi::thunk::PPB_Audio_API* AsPPB_Audio_API() OVERRIDE;
+
+ // PPB_Audio_API implementation.
+ virtual PP_Resource GetCurrentConfig() OVERRIDE;
+ virtual PP_Bool StartPlayback() OVERRIDE;
+ virtual PP_Bool StopPlayback() OVERRIDE;
+ virtual int32_t Open(
+ PP_Resource config_id,
+ scoped_refptr< ::ppapi::TrackedCallback> create_callback) OVERRIDE;
+ virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
+ virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
+
+ private:
+ virtual ~PPB_Audio_Impl();
+
+ // AudioHelper implementation.
+ virtual void OnSetStreamInfo(base::SharedMemoryHandle shared_memory_handle,
+ size_t shared_memory_size_,
+ base::SyncSocket::Handle socket) OVERRIDE;
+
+ // AudioConfig used for creating this Audio object. We own a ref.
+ ::ppapi::ScopedPPResource config_;
+
+ // PluginDelegate audio object that we delegate audio IPC through. We don't
+ // own this pointer but are responsible for calling Shutdown on it.
+ PluginDelegate::PlatformAudioOutput* audio_;
+
+ // Track frame count for passing on to PPB_Audio_Shared::SetStreamInfo().
+ int sample_frame_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_AUDIO_IMPL_H_
diff --git a/content/renderer/pepper/ppb_broker_impl.cc b/content/renderer/pepper/ppb_broker_impl.cc
new file mode 100644
index 0000000..7401b28
--- /dev/null
+++ b/content/renderer/pepper/ppb_broker_impl.cc
@@ -0,0 +1,103 @@
+// 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/ppb_broker_impl.h"
+
+#include "base/logging.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/shared_impl/platform_file.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"
+
+using ppapi::PlatformFileToInt;
+using ppapi::thunk::PPB_Broker_API;
+using ppapi::TrackedCallback;
+
+namespace webkit {
+namespace ppapi {
+
+// PPB_Broker_Impl ------------------------------------------------------
+
+PPB_Broker_Impl::PPB_Broker_Impl(PP_Instance instance)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ broker_(NULL),
+ connect_callback_(),
+ pipe_handle_(PlatformFileToInt(base::kInvalidPlatformFileValue)) {
+}
+
+PPB_Broker_Impl::~PPB_Broker_Impl() {
+ if (broker_) {
+ broker_->Disconnect(this);
+ broker_ = NULL;
+ }
+
+ // The plugin owns the handle.
+ pipe_handle_ = PlatformFileToInt(base::kInvalidPlatformFileValue);
+}
+
+PPB_Broker_API* PPB_Broker_Impl::AsPPB_Broker_API() {
+ return this;
+}
+
+int32_t PPB_Broker_Impl::Connect(
+ scoped_refptr<TrackedCallback> connect_callback) {
+ // TODO(ddorwin): Return PP_ERROR_FAILED if plugin is in-process.
+
+ if (broker_) {
+ // May only be called once.
+ return PP_ERROR_FAILED;
+ }
+
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return PP_ERROR_FAILED;
+
+ // The callback must be populated now in case we are connected to the broker
+ // and BrokerConnected is called before ConnectToBroker returns.
+ // Because it must be created now, it must be aborted and cleared if
+ // ConnectToBroker fails.
+ connect_callback_ = connect_callback;
+
+ broker_ = plugin_instance->delegate()->ConnectToBroker(this);
+ if (!broker_) {
+ connect_callback_->Abort();
+ return PP_ERROR_FAILED;
+ }
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_Broker_Impl::GetHandle(int32_t* handle) {
+ if (pipe_handle_ == PlatformFileToInt(base::kInvalidPlatformFileValue))
+ return PP_ERROR_FAILED; // Handle not set yet.
+ *handle = pipe_handle_;
+ return PP_OK;
+}
+
+GURL PPB_Broker_Impl::GetDocumentUrl() {
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ return plugin_instance->container()->element().document().url();
+}
+
+// Transfers ownership of the handle to the plugin.
+void PPB_Broker_Impl::BrokerConnected(int32_t handle, int32_t result) {
+ DCHECK(pipe_handle_ ==
+ PlatformFileToInt(base::kInvalidPlatformFileValue));
+ DCHECK(result == PP_OK ||
+ handle == PlatformFileToInt(base::kInvalidPlatformFileValue));
+
+ pipe_handle_ = handle;
+
+ // Synchronous calls are not supported.
+ DCHECK(TrackedCallback::IsPending(connect_callback_));
+
+ connect_callback_->Run(result);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_broker_impl.h b/content/renderer/pepper/ppb_broker_impl.h
new file mode 100644
index 0000000..0c7a76f
--- /dev/null
+++ b/content/renderer/pepper/ppb_broker_impl.h
@@ -0,0 +1,60 @@
+// 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_PPB_BROKER_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_BROKER_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/trusted/ppb_broker_trusted.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/ppb_broker_api.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Broker_Impl : public ::ppapi::Resource,
+ public ::ppapi::thunk::PPB_Broker_API,
+ public base::SupportsWeakPtr<PPB_Broker_Impl> {
+ public:
+ explicit PPB_Broker_Impl(PP_Instance instance);
+
+ // Resource override.
+ virtual ::ppapi::thunk::PPB_Broker_API* AsPPB_Broker_API() OVERRIDE;
+
+ // PPB_BrokerTrusted implementation.
+ virtual int32_t Connect(
+ scoped_refptr< ::ppapi::TrackedCallback> connect_callback) OVERRIDE;
+ virtual int32_t GetHandle(int32_t* handle) OVERRIDE;
+
+ // Returns the URL of the document this plug-in runs in. This is necessary to
+ // decide whether to grant access to the PPAPI broker.
+ GURL GetDocumentUrl();
+
+ void BrokerConnected(int32_t handle, int32_t result);
+
+ private:
+ virtual ~PPB_Broker_Impl();
+ // PluginDelegate ppapi broker object.
+ // We don't own this pointer but are responsible for calling Disconnect on it.
+ PluginDelegate::Broker* broker_;
+
+ // Callback invoked from BrokerConnected.
+ scoped_refptr< ::ppapi::TrackedCallback> connect_callback_;
+
+ // Pipe handle for the plugin instance to use to communicate with the broker.
+ // Never owned by this object.
+ int32_t pipe_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Broker_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_BROKER_IMPL_H_
diff --git a/content/renderer/pepper/ppb_buffer_impl.cc b/content/renderer/pepper/ppb_buffer_impl.cc
new file mode 100644
index 0000000..24599e7
--- /dev/null
+++ b/content/renderer/pepper/ppb_buffer_impl.cc
@@ -0,0 +1,113 @@
+// 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/ppb_buffer_impl.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/c/dev/ppb_buffer_dev.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+
+using ::ppapi::thunk::PPB_Buffer_API;
+
+namespace webkit {
+namespace ppapi {
+
+PPB_Buffer_Impl::PPB_Buffer_Impl(PP_Instance instance)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ size_(0),
+ map_count_(0) {
+}
+
+PPB_Buffer_Impl::~PPB_Buffer_Impl() {
+}
+
+// static
+PP_Resource PPB_Buffer_Impl::Create(PP_Instance instance, uint32_t size) {
+ scoped_refptr<PPB_Buffer_Impl> new_resource(CreateResource(instance, size));
+ if (new_resource.get())
+ return new_resource->GetReference();
+ return 0;
+}
+
+// static
+scoped_refptr<PPB_Buffer_Impl> PPB_Buffer_Impl::CreateResource(
+ PP_Instance instance,
+ uint32_t size) {
+ scoped_refptr<PPB_Buffer_Impl> buffer(new PPB_Buffer_Impl(instance));
+ if (!buffer->Init(size))
+ return scoped_refptr<PPB_Buffer_Impl>();
+ return buffer;
+}
+
+PPB_Buffer_Impl* PPB_Buffer_Impl::AsPPB_Buffer_Impl() {
+ return this;
+}
+
+PPB_Buffer_API* PPB_Buffer_Impl::AsPPB_Buffer_API() {
+ return this;
+}
+
+bool PPB_Buffer_Impl::Init(uint32_t size) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (size == 0 || !plugin_delegate)
+ return false;
+ size_ = size;
+ shared_memory_.reset(plugin_delegate->CreateAnonymousSharedMemory(size));
+ return shared_memory_.get() != NULL;
+}
+
+PP_Bool PPB_Buffer_Impl::Describe(uint32_t* size_in_bytes) {
+ *size_in_bytes = size_;
+ return PP_TRUE;
+}
+
+PP_Bool PPB_Buffer_Impl::IsMapped() {
+ return PP_FromBool(!!shared_memory_->memory());
+}
+
+void* PPB_Buffer_Impl::Map() {
+ DCHECK(size_);
+ DCHECK(shared_memory_.get());
+ if (map_count_++ == 0)
+ shared_memory_->Map(size_);
+ return shared_memory_->memory();
+}
+
+void PPB_Buffer_Impl::Unmap() {
+ if (--map_count_ == 0)
+ shared_memory_->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
+ return PP_OK;
+}
+
+BufferAutoMapper::BufferAutoMapper(PPB_Buffer_API* api) : api_(api) {
+ needs_unmap_ = !PP_ToBool(api->IsMapped());
+ data_ = api->Map();
+ api->Describe(&size_);
+}
+
+BufferAutoMapper::~BufferAutoMapper() {
+ if (needs_unmap_)
+ api_->Unmap();
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_buffer_impl.h b/content/renderer/pepper/ppb_buffer_impl.h
new file mode 100644
index 0000000..5da2c72
--- /dev/null
+++ b/content/renderer/pepper/ppb_buffer_impl.h
@@ -0,0 +1,80 @@
+// 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_PEPPER_PPB_BUFFER_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_BUFFER_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_buffer_api.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Buffer_Impl : public ::ppapi::Resource,
+ public ::ppapi::thunk::PPB_Buffer_API {
+ public:
+ static PP_Resource Create(PP_Instance instance, uint32_t size);
+ static scoped_refptr<PPB_Buffer_Impl> CreateResource(PP_Instance instance,
+ uint32_t size);
+
+ virtual PPB_Buffer_Impl* AsPPB_Buffer_Impl();
+
+ base::SharedMemory* shared_memory() const { return shared_memory_.get(); }
+ uint32_t size() const { return size_; }
+
+ // Resource overrides.
+ virtual ::ppapi::thunk::PPB_Buffer_API* AsPPB_Buffer_API() OVERRIDE;
+
+ // PPB_Buffer_API implementation.
+ virtual PP_Bool Describe(uint32_t* size_in_bytes) OVERRIDE;
+ virtual PP_Bool IsMapped() OVERRIDE;
+ virtual void* Map() OVERRIDE;
+ virtual void Unmap() OVERRIDE;
+
+ // Trusted.
+ virtual int32_t GetSharedMemory(int* handle) OVERRIDE;
+
+ private:
+ virtual ~PPB_Buffer_Impl();
+
+ explicit PPB_Buffer_Impl(PP_Instance instance);
+ bool Init(uint32_t size);
+
+ scoped_ptr<base::SharedMemory> shared_memory_;
+ uint32_t size_;
+ int map_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Buffer_Impl);
+};
+
+// Ensures that the given buffer is mapped, and returns it to its previous
+// mapped state in the destructor.
+class BufferAutoMapper {
+ public:
+ explicit BufferAutoMapper(::ppapi::thunk::PPB_Buffer_API* api);
+ ~BufferAutoMapper();
+
+ // Will be NULL on failure to map.
+ void* data() { return data_; }
+ uint32_t size() { return size_; }
+
+ private:
+ ::ppapi::thunk::PPB_Buffer_API* api_;
+
+ bool needs_unmap_;
+
+ void* data_;
+ uint32_t size_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferAutoMapper);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_BUFFER_IMPL_H_
diff --git a/content/renderer/pepper/ppb_file_ref_impl.cc b/content/renderer/pepper/ppb_file_ref_impl.cc
new file mode 100644
index 0000000..9a97bed
--- /dev/null
+++ b/content/renderer/pepper/ppb_file_ref_impl.cc
@@ -0,0 +1,511 @@
+// 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/ppb_file_ref_impl.h"
+
+#include "base/files/file_util_proxy.h"
+#include "base/platform_file.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "net/base/escape.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/file_type_conversion.h"
+#include "ppapi/shared_impl/time_conversion.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_file_system_api.h"
+#include "url/gurl.h"
+#include "webkit/common/fileapi/directory_entry.h"
+#include "webkit/common/fileapi/file_system_util.h"
+
+using ppapi::HostResource;
+using ppapi::PPB_FileRef_CreateInfo;
+using ppapi::PPTimeToTime;
+using ppapi::StringVar;
+using ppapi::TrackedCallback;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_FileRef_API;
+using ppapi::thunk::PPB_FileSystem_API;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+bool IsValidLocalPath(const std::string& path) {
+ // The path must start with '/'
+ if (path.empty() || path[0] != '/')
+ return false;
+
+ // The path must contain valid UTF-8 characters.
+ if (!IsStringUTF8(path))
+ return false;
+
+#if defined(OS_WIN)
+ base::FilePath::StringType path_win(path.begin(), path.end());
+ base::FilePath file_path(path_win);
+#else
+ base::FilePath file_path(path);
+#endif
+ if (file_path.ReferencesParent())
+ return false;
+
+ return true;
+}
+
+void TrimTrailingSlash(std::string* path) {
+ // If this path ends with a slash, then normalize it away unless path is the
+ // root path.
+ if (path->size() > 1 && path->at(path->size() - 1) == '/')
+ path->erase(path->size() - 1, 1);
+}
+
+std::string GetNameForExternalFilePath(const base::FilePath& in_path) {
+ const base::FilePath::StringType& path = in_path.value();
+ size_t pos = path.rfind(base::FilePath::kSeparators[0]);
+ CHECK(pos != base::FilePath::StringType::npos);
+#if defined(OS_WIN)
+ return WideToUTF8(path.substr(pos + 1));
+#elif defined(OS_POSIX)
+ return path.substr(pos + 1);
+#else
+#error "Unsupported platform."
+#endif
+}
+
+std::string GetNameForVirtualFilePath(const std::string& path) {
+ if (path.size() == 1 && path[0] == '/')
+ return path;
+
+ // There should always be a leading slash at least!
+ size_t pos = path.rfind('/');
+ CHECK(pos != std::string::npos);
+ return path.substr(pos + 1);
+}
+
+void IgnoreCloseCallback(base::PlatformFileError error_code) {
+}
+
+void PlatformFileInfoToPPFileInfo(
+ const base::PlatformFileInfo& file_info,
+ PP_FileSystemType file_system_type,
+ PP_FileInfo* info) {
+ DCHECK(info);
+ ::ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type, info);
+}
+
+void GetFileInfoCallback(
+ scoped_refptr<base::TaskRunner> task_runner,
+ base::PlatformFile file,
+ linked_ptr<PP_FileInfo> info,
+ scoped_refptr<TrackedCallback> callback,
+ base::PlatformFileError error_code,
+ const base::PlatformFileInfo& file_info) {
+ base::FileUtilProxy::Close(
+ task_runner.get(), file, base::Bind(&IgnoreCloseCallback));
+
+ if (!TrackedCallback::IsPending(callback))
+ return;
+
+ int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
+ if (pp_error != PP_OK) {
+ callback->Run(pp_error);
+ return;
+ }
+
+ PlatformFileInfoToPPFileInfo(
+ file_info, PP_FILESYSTEMTYPE_EXTERNAL, info.get());
+
+ callback->Run(PP_OK);
+}
+
+void QueryCallback(scoped_refptr<base::TaskRunner> task_runner,
+ linked_ptr<PP_FileInfo> info,
+ scoped_refptr<TrackedCallback> callback,
+ base::PlatformFileError error_code,
+ base::PassPlatformFile passed_file) {
+ if (!TrackedCallback::IsPending(callback))
+ return;
+
+ int32_t pp_error = ::ppapi::PlatformFileErrorToPepperError(error_code);
+ if (pp_error != PP_OK) {
+ callback->Run(pp_error);
+ return;
+ }
+ base::PlatformFile file = passed_file.ReleaseValue();
+
+ if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
+ task_runner.get(),
+ file,
+ base::Bind(
+ &GetFileInfoCallback, task_runner, file, info, callback))) {
+ base::FileUtilProxy::Close(
+ task_runner.get(), file, base::Bind(&IgnoreCloseCallback));
+ callback->Run(PP_ERROR_FAILED);
+ }
+}
+
+void DidReadMetadata(
+ scoped_refptr< ::ppapi::TrackedCallback> callback,
+ linked_ptr<PP_FileInfo> info,
+ PP_FileSystemType file_system_type,
+ const base::PlatformFileInfo& file_info) {
+ if (!TrackedCallback::IsPending(callback))
+ return;
+
+ PlatformFileInfoToPPFileInfo(file_info, file_system_type, info.get());
+ callback->Run(PP_OK);
+}
+
+void DidReadDirectory(
+ scoped_refptr< ::ppapi::TrackedCallback> callback,
+ PPB_FileRef_Impl* dir_ref,
+ linked_ptr<std::vector< ::ppapi::PPB_FileRef_CreateInfo> > dir_files,
+ linked_ptr<std::vector<PP_FileType> > dir_file_types,
+ const std::vector<fileapi::DirectoryEntry>& entries,
+ bool has_more) {
+ if (!TrackedCallback::IsPending(callback))
+ return;
+
+ // The current filesystem backend always returns false.
+ DCHECK(!has_more);
+
+ DCHECK(dir_ref);
+ DCHECK(dir_files.get());
+ DCHECK(dir_file_types.get());
+
+ std::string dir_path = dir_ref->GetCreateInfo().path;
+ if (dir_path.empty() || dir_path[dir_path.size() - 1] != '/')
+ dir_path += '/';
+
+ for (size_t i = 0; i < entries.size(); ++i) {
+ const fileapi::DirectoryEntry& entry = entries[i];
+ scoped_refptr<PPB_FileRef_Impl> file_ref(PPB_FileRef_Impl::CreateInternal(
+ dir_ref->pp_instance(),
+ dir_ref->file_system_resource(),
+ dir_path + fileapi::FilePathToString(base::FilePath(entry.name))));
+ dir_files->push_back(file_ref->GetCreateInfo());
+ dir_file_types->push_back(
+ entry.is_directory ? PP_FILETYPE_DIRECTORY : PP_FILETYPE_REGULAR);
+ // Add a ref count on behalf of the plugin side.
+ file_ref->GetReference();
+ }
+ CHECK_EQ(dir_files->size(), dir_file_types->size());
+
+ callback->Run(PP_OK);
+}
+
+void DidFinishFileOperation(
+ scoped_refptr< ::ppapi::TrackedCallback> callback,
+ base::PlatformFileError error_code) {
+ if (callback->completed())
+ return;
+ callback->Run(::ppapi::PlatformFileErrorToPepperError(error_code));
+}
+
+} // namespace
+
+PPB_FileRef_Impl::PPB_FileRef_Impl(const PPB_FileRef_CreateInfo& info,
+ PP_Resource file_system)
+ : PPB_FileRef_Shared(::ppapi::OBJECT_IS_IMPL, info),
+ file_system_(file_system),
+ external_file_system_path_() {
+}
+
+PPB_FileRef_Impl::PPB_FileRef_Impl(const PPB_FileRef_CreateInfo& info,
+ const base::FilePath& external_file_path)
+ : PPB_FileRef_Shared(::ppapi::OBJECT_IS_IMPL, info),
+ file_system_(),
+ external_file_system_path_(external_file_path) {
+}
+
+PPB_FileRef_Impl::~PPB_FileRef_Impl() {
+}
+
+// static
+PPB_FileRef_Impl* PPB_FileRef_Impl::CreateInternal(PP_Instance instance,
+ PP_Resource pp_file_system,
+ const std::string& path) {
+ PluginInstanceImpl* plugin_instance =
+ ResourceHelper::PPInstanceToPluginInstance(instance);
+ if (!plugin_instance || !plugin_instance->delegate())
+ return 0;
+
+ PP_FileSystemType type =
+ plugin_instance->delegate()->GetFileSystemType(instance, pp_file_system);
+ if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
+ type != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
+ type != PP_FILESYSTEMTYPE_EXTERNAL &&
+ type != PP_FILESYSTEMTYPE_ISOLATED)
+ return 0;
+
+ PPB_FileRef_CreateInfo info;
+ info.resource = HostResource::MakeInstanceOnly(instance);
+ info.file_system_plugin_resource = pp_file_system;
+ info.file_system_type = type;
+
+ // Validate the path.
+ info.path = path;
+ if (!IsValidLocalPath(info.path))
+ return 0;
+ TrimTrailingSlash(&info.path);
+
+ info.name = GetNameForVirtualFilePath(info.path);
+
+ PPB_FileRef_Impl* file_ref = new PPB_FileRef_Impl(info, pp_file_system);
+ if (plugin_instance->delegate()->IsRunningInProcess(instance))
+ file_ref->AddFileSystemRefCount();
+ return file_ref;
+}
+
+// static
+PPB_FileRef_Impl* PPB_FileRef_Impl::CreateExternal(
+ PP_Instance instance,
+ const base::FilePath& external_file_path,
+ const std::string& display_name) {
+ PPB_FileRef_CreateInfo info;
+ info.resource = HostResource::MakeInstanceOnly(instance);
+ info.file_system_plugin_resource = 0;
+ info.file_system_type = PP_FILESYSTEMTYPE_EXTERNAL;
+ if (display_name.empty())
+ info.name = GetNameForExternalFilePath(external_file_path);
+ else
+ info.name = display_name;
+
+ return new PPB_FileRef_Impl(info, external_file_path);
+}
+
+PP_Resource PPB_FileRef_Impl::GetParent() {
+ if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
+ return 0;
+
+ const std::string& virtual_path = GetCreateInfo().path;
+
+ // There should always be a leading slash at least!
+ size_t pos = virtual_path.rfind('/');
+ CHECK(pos != std::string::npos);
+
+ // If the path is "/foo", then we want to include the slash.
+ if (pos == 0)
+ pos++;
+ std::string parent_path = virtual_path.substr(0, pos);
+
+ scoped_refptr<PPB_FileRef_Impl> parent_ref(
+ CreateInternal(pp_instance(), file_system_, parent_path));
+ if (!parent_ref.get())
+ return 0;
+ return parent_ref->GetReference();
+}
+
+int32_t PPB_FileRef_Impl::MakeDirectory(
+ PP_Bool make_ancestors,
+ scoped_refptr<TrackedCallback> callback) {
+ if (!IsValidNonExternalFileSystem())
+ return PP_ERROR_NOACCESS;
+
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return PP_ERROR_FAILED;
+ plugin_instance->delegate()->MakeDirectory(
+ GetFileSystemURL(), PP_ToBool(make_ancestors),
+ base::Bind(&DidFinishFileOperation, callback));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_FileRef_Impl::Touch(PP_Time last_access_time,
+ PP_Time last_modified_time,
+ scoped_refptr<TrackedCallback> callback) {
+ if (!IsValidNonExternalFileSystem())
+ return PP_ERROR_NOACCESS;
+
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return PP_ERROR_FAILED;
+ plugin_instance->delegate()->Touch(
+ GetFileSystemURL(),
+ PPTimeToTime(last_access_time),
+ PPTimeToTime(last_modified_time),
+ base::Bind(&DidFinishFileOperation, callback));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_FileRef_Impl::Delete(scoped_refptr<TrackedCallback> callback) {
+ if (!IsValidNonExternalFileSystem())
+ return PP_ERROR_NOACCESS;
+
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return PP_ERROR_FAILED;
+ plugin_instance->delegate()->Delete(
+ GetFileSystemURL(),
+ base::Bind(&DidFinishFileOperation, callback));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_FileRef_Impl::Rename(PP_Resource new_pp_file_ref,
+ scoped_refptr<TrackedCallback> callback) {
+ EnterResourceNoLock<PPB_FileRef_API> enter(new_pp_file_ref, true);
+ if (enter.failed())
+ return PP_ERROR_BADRESOURCE;
+ PPB_FileRef_Impl* new_file_ref =
+ static_cast<PPB_FileRef_Impl*>(enter.object());
+
+ if (!IsValidNonExternalFileSystem() ||
+ file_system_ != new_file_ref->file_system_)
+ return PP_ERROR_NOACCESS;
+
+ // TODO(viettrungluu): Also cancel when the new file ref is destroyed?
+ // http://crbug.com/67624
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return PP_ERROR_FAILED;
+ plugin_instance->delegate()->Rename(
+ GetFileSystemURL(), new_file_ref->GetFileSystemURL(),
+ base::Bind(&DidFinishFileOperation, callback));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+PP_Var PPB_FileRef_Impl::GetAbsolutePath() {
+ if (GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL)
+ return GetPath();
+ if (!external_path_var_.get()) {
+ external_path_var_ =
+ new StringVar(external_file_system_path_.AsUTF8Unsafe());
+ }
+ return external_path_var_->GetPPVar();
+}
+
+base::FilePath PPB_FileRef_Impl::GetSystemPath() const {
+ if (GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL) {
+ NOTREACHED();
+ return base::FilePath();
+ }
+ return external_file_system_path_;
+}
+
+GURL PPB_FileRef_Impl::GetFileSystemURL() const {
+ if (GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALPERSISTENT &&
+ GetFileSystemType() != PP_FILESYSTEMTYPE_LOCALTEMPORARY &&
+ GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL &&
+ GetFileSystemType() != PP_FILESYSTEMTYPE_ISOLATED) {
+ NOTREACHED();
+ return GURL();
+ }
+
+ const std::string& virtual_path = GetCreateInfo().path;
+ CHECK(!virtual_path.empty()); // Should always be at least "/".
+
+ // Since |virtual_path_| starts with a '/', it looks like an absolute path.
+ // We need to trim off the '/' before calling Resolve, as FileSystem URLs
+ // start with a storage type identifier that looks like a path segment.
+
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ PluginDelegate* delegate =
+ plugin_instance ? plugin_instance->delegate() : NULL;
+ if (!delegate)
+ return GURL();
+ return GURL(delegate->GetFileSystemRootUrl(pp_instance(), file_system_))
+ .Resolve(net::EscapePath(virtual_path.substr(1)));
+}
+
+bool PPB_FileRef_Impl::IsValidNonExternalFileSystem() const {
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ PluginDelegate* delegate =
+ plugin_instance ? plugin_instance->delegate() : NULL;
+ return delegate &&
+ delegate->IsFileSystemOpened(pp_instance(), file_system_) &&
+ delegate->GetFileSystemType(pp_instance(), file_system_) !=
+ PP_FILESYSTEMTYPE_EXTERNAL;
+}
+
+bool PPB_FileRef_Impl::HasValidFileSystem() const {
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ PluginDelegate* delegate =
+ plugin_instance ? plugin_instance->delegate() : NULL;
+ return delegate && delegate->IsFileSystemOpened(pp_instance(), file_system_);
+}
+
+int32_t PPB_FileRef_Impl::Query(PP_FileInfo* info,
+ scoped_refptr<TrackedCallback> callback) {
+ NOTREACHED();
+ return PP_ERROR_FAILED;
+}
+
+int32_t PPB_FileRef_Impl::QueryInHost(
+ linked_ptr<PP_FileInfo> info,
+ scoped_refptr<TrackedCallback> callback) {
+ scoped_refptr<PluginInstanceImpl> plugin_instance =
+ ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance.get())
+ return PP_ERROR_FAILED;
+
+ if (!file_system_) {
+ // External file system
+ // We have to do something totally different for external file systems.
+
+ // TODO(teravest): Use the SequencedWorkerPool instead.
+ scoped_refptr<base::TaskRunner> task_runner =
+ plugin_instance->delegate()->GetFileThreadMessageLoopProxy();
+ if (!plugin_instance->delegate()->AsyncOpenFile(
+ GetSystemPath(),
+ base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+ base::Bind(&QueryCallback, task_runner, info, callback)))
+ return PP_ERROR_FAILED;
+ } else {
+ // Non-external file system
+ if (!HasValidFileSystem())
+ return PP_ERROR_NOACCESS;
+
+ PluginInstanceImpl* plugin_instance =
+ ResourceHelper::GetPluginInstance(this);
+ PluginDelegate* delegate =
+ plugin_instance ? plugin_instance->delegate() : NULL;
+ if (!delegate)
+ return PP_ERROR_FAILED;
+
+ PP_FileSystemType file_system_type =
+ delegate->GetFileSystemType(pp_instance(), file_system_);
+ plugin_instance->delegate()->Query(
+ GetFileSystemURL(),
+ base::Bind(&DidReadMetadata, callback, info, file_system_type),
+ base::Bind(&DidFinishFileOperation, callback));
+ }
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_FileRef_Impl::ReadDirectoryEntries(
+ const PP_ArrayOutput& output,
+ scoped_refptr<TrackedCallback> callback) {
+ NOTREACHED();
+ return PP_ERROR_FAILED;
+}
+
+int32_t PPB_FileRef_Impl::ReadDirectoryEntriesInHost(
+ linked_ptr<std::vector< ::ppapi::PPB_FileRef_CreateInfo> > files,
+ linked_ptr<std::vector<PP_FileType> > file_types,
+ scoped_refptr<TrackedCallback> callback) {
+ if (!IsValidNonExternalFileSystem())
+ return PP_ERROR_NOACCESS;
+
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return PP_ERROR_FAILED;
+
+ // TODO(yzshen): Passing base::Unretained(this) to the callback could
+ // be dangerous.
+ plugin_instance->delegate()->ReadDirectoryEntries(
+ GetFileSystemURL(),
+ base::Bind(&DidReadDirectory,
+ callback, base::Unretained(this), files, file_types),
+ base::Bind(&DidFinishFileOperation, callback));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_file_ref_impl.h b/content/renderer/pepper/ppb_file_ref_impl.h
new file mode 100644
index 0000000..30612cd
--- /dev/null
+++ b/content/renderer/pepper/ppb_file_ref_impl.h
@@ -0,0 +1,126 @@
+// 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_PPB_FILE_REF_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_FILE_REF_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/memory/linked_ptr.h"
+#include "ppapi/c/pp_file_info.h"
+#include "ppapi/c/ppb_file_ref.h"
+#include "ppapi/shared_impl/ppb_file_ref_shared.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/shared_impl/var.h"
+#include "url/gurl.h"
+
+namespace webkit {
+namespace ppapi {
+
+using ::ppapi::StringVar;
+
+class PPB_FileSystem_Impl;
+
+class PPB_FileRef_Impl : public ::ppapi::PPB_FileRef_Shared {
+ public:
+ PPB_FileRef_Impl(const ::ppapi::PPB_FileRef_CreateInfo& info,
+ PP_Resource file_system);
+ PPB_FileRef_Impl(const ::ppapi::PPB_FileRef_CreateInfo& info,
+ const base::FilePath& external_file_path);
+
+ // The returned object will have a refcount of 0 (just like "new").
+ static PPB_FileRef_Impl* CreateInternal(PP_Instance instance,
+ PP_Resource pp_file_system,
+ const std::string& path);
+
+ // The returned object will have a refcount of 0 (just like "new").
+ static PPB_FileRef_Impl* CreateExternal(
+ PP_Instance instance,
+ const base::FilePath& external_file_path,
+ const std::string& display_name);
+
+ // PPB_FileRef_API implementation (not provided by PPB_FileRef_Shared).
+ virtual PP_Resource GetParent() OVERRIDE;
+ virtual int32_t MakeDirectory(
+ PP_Bool make_ancestors,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Touch(
+ PP_Time last_access_time,
+ PP_Time last_modified_time,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Delete(
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Rename(
+ PP_Resource new_file_ref,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Query(
+ PP_FileInfo* info,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t ReadDirectoryEntries(
+ const PP_ArrayOutput& output,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t QueryInHost(
+ linked_ptr<PP_FileInfo> info,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t ReadDirectoryEntriesInHost(
+ linked_ptr<std::vector< ::ppapi::PPB_FileRef_CreateInfo> > files,
+ linked_ptr<std::vector<PP_FileType> > file_types,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual PP_Var GetAbsolutePath() OVERRIDE;
+
+ PP_Resource file_system_resource() const { return file_system_; }
+
+ // Returns the system path corresponding to this file. Valid only for
+ // external filesystems.
+ base::FilePath GetSystemPath() const;
+
+ // Returns the FileSystem API URL corresponding to this file.
+ GURL GetFileSystemURL() const;
+
+ // Checks if file ref has file system instance and if the instance is opened.
+ bool HasValidFileSystem() const;
+
+ void AddFileSystemRefCount() {
+ file_system_ref_ = file_system_;
+ }
+
+ private:
+ virtual ~PPB_FileRef_Impl();
+
+ // Many mutation functions are allow only to non-external filesystems, This
+ // function returns true if the filesystem is opened and isn't external as an
+ // access check for these functions.
+ bool IsValidNonExternalFileSystem() const;
+
+ // 0 for external filesystems. This is a plugin side resource that we don't
+ // hold a reference here, so file_system_ could be destroyed earlier than
+ // this object. Right now we checked the existance in plugin delegate before
+ // use. But it's better to hold a reference once we migrate FileRef to the
+ // new design.
+ PP_Resource file_system_;
+
+ // Holds a reference of FileSystem when running in process. See
+ // PPB_FileRef_Proxy for corresponding code for out-of-process mode. Note
+ // that this ScopedPPResource is only expected to be used when running in
+ // process (since PPB_FileRef_Proxy takes care of out-of-process case).
+ // Also note that this workaround will be no longer needed after FileRef
+ // refactoring.
+ ::ppapi::ScopedPPResource file_system_ref_;
+
+ // Used only for external filesystems.
+ base::FilePath external_file_system_path_;
+
+ // Lazily initialized var created from the external path. This is so we can
+ // return the identical string object every time it is requested.
+ scoped_refptr<StringVar> external_path_var_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_FileRef_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_FILE_REF_IMPL_H_
diff --git a/content/renderer/pepper/ppb_flash_message_loop_impl.cc b/content/renderer/pepper/ppb_flash_message_loop_impl.cc
new file mode 100644
index 0000000..105c5a0
--- /dev/null
+++ b/content/renderer/pepper/ppb_flash_message_loop_impl.cc
@@ -0,0 +1,116 @@
+// 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/ppb_flash_message_loop_impl.h"
+
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "ppapi/c/pp_errors.h"
+
+using ppapi::thunk::PPB_Flash_MessageLoop_API;
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Flash_MessageLoop_Impl::State
+ : public base::RefCounted<PPB_Flash_MessageLoop_Impl::State> {
+ public:
+ State() : result_(PP_OK), run_called_(false), quit_called_(false) {
+ }
+
+ int32_t result() const { return result_; }
+ void set_result(int32_t result) { result_ = result; }
+
+ bool run_called() const { return run_called_; }
+ void set_run_called() { run_called_ = true; }
+
+ bool quit_called() const { return quit_called_; }
+ void set_quit_called() { quit_called_ = true; }
+
+ const RunFromHostProxyCallback& run_callback() const { return run_callback_; }
+ void set_run_callback(const RunFromHostProxyCallback& run_callback) {
+ run_callback_ = run_callback;
+ }
+
+ private:
+ friend class base::RefCounted<State>;
+ virtual ~State() {}
+
+ int32_t result_;
+ bool run_called_;
+ bool quit_called_;
+ RunFromHostProxyCallback run_callback_;
+};
+
+PPB_Flash_MessageLoop_Impl::PPB_Flash_MessageLoop_Impl(PP_Instance instance)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ state_(new State()) {
+}
+
+PPB_Flash_MessageLoop_Impl::~PPB_Flash_MessageLoop_Impl() {
+ // It is a no-op if either Run() hasn't been called or Quit() has been called
+ // to balance the call to Run().
+ InternalQuit(PP_ERROR_ABORTED);
+}
+
+// static
+PP_Resource PPB_Flash_MessageLoop_Impl::Create(PP_Instance instance) {
+ return (new PPB_Flash_MessageLoop_Impl(instance))->GetReference();
+}
+
+PPB_Flash_MessageLoop_API*
+ PPB_Flash_MessageLoop_Impl::AsPPB_Flash_MessageLoop_API() {
+ return this;
+}
+
+int32_t PPB_Flash_MessageLoop_Impl::Run() {
+ return InternalRun(RunFromHostProxyCallback());
+}
+
+void PPB_Flash_MessageLoop_Impl::RunFromHostProxy(
+ const RunFromHostProxyCallback& callback) {
+ InternalRun(callback);
+}
+
+void PPB_Flash_MessageLoop_Impl::Quit() {
+ InternalQuit(PP_OK);
+}
+
+int32_t PPB_Flash_MessageLoop_Impl::InternalRun(
+ const RunFromHostProxyCallback& callback) {
+ if (state_->run_called()) {
+ if (!callback.is_null())
+ callback.Run(PP_ERROR_FAILED);
+ return PP_ERROR_FAILED;
+ }
+ state_->set_run_called();
+ state_->set_run_callback(callback);
+
+ // It is possible that the PPB_Flash_MessageLoop_Impl object has been
+ // destroyed when the nested message loop exits.
+ scoped_refptr<State> state_protector(state_);
+ {
+ base::MessageLoop::ScopedNestableTaskAllower allow(
+ base::MessageLoop::current());
+ base::MessageLoop::current()->Run();
+ }
+ // Don't access data members of the class below.
+
+ return state_protector->result();
+}
+
+void PPB_Flash_MessageLoop_Impl::InternalQuit(int32_t result) {
+ if (!state_->run_called() || state_->quit_called())
+ return;
+ state_->set_quit_called();
+ state_->set_result(result);
+
+ base::MessageLoop::current()->QuitNow();
+
+ if (!state_->run_callback().is_null())
+ state_->run_callback().Run(result);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_flash_message_loop_impl.h b/content/renderer/pepper/ppb_flash_message_loop_impl.h
new file mode 100644
index 0000000..ef6903c
--- /dev/null
+++ b/content/renderer/pepper/ppb_flash_message_loop_impl.h
@@ -0,0 +1,54 @@
+// 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_PPB_FLASH_MESSAGE_LOOP_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_FLASH_MESSAGE_LOOP_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_flash_message_loop_api.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Flash_MessageLoop_Impl
+ : public ::ppapi::Resource,
+ public ::ppapi::thunk::PPB_Flash_MessageLoop_API {
+ public:
+ static PP_Resource Create(PP_Instance instance);
+
+ // Resource.
+ virtual ::ppapi::thunk::PPB_Flash_MessageLoop_API*
+ AsPPB_Flash_MessageLoop_API() OVERRIDE;
+
+ // PPB_Flash_MessageLoop_API implementation.
+ virtual int32_t Run() OVERRIDE;
+ virtual void Quit() OVERRIDE;
+ virtual void RunFromHostProxy(
+ const RunFromHostProxyCallback& callback) OVERRIDE;
+
+ private:
+ class State;
+
+ explicit PPB_Flash_MessageLoop_Impl(PP_Instance instance);
+ virtual ~PPB_Flash_MessageLoop_Impl();
+
+ // If |callback| is valid, it will be called when the message loop is signaled
+ // to quit, and the result passed into it will be the same value as what this
+ // method returns.
+ // Please note that |callback| happens before this method returns.
+ int32_t InternalRun(const RunFromHostProxyCallback& callback);
+ void InternalQuit(int32_t result);
+
+ scoped_refptr<State> state_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Flash_MessageLoop_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_FLASH_MESSAGE_LOOP_IMPL_H_
diff --git a/content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc b/content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc
new file mode 100644
index 0000000..81c4292
--- /dev/null
+++ b/content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc
@@ -0,0 +1,40 @@
+// 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/pepper/ppb_gpu_blacklist_private_impl.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "webkit/plugins/plugin_switches.h"
+
+// todo(nfullagar): Remove this private interface when the SRPC proxy is
+// permanently disabled.
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+PP_Bool IsGpuBlacklisted() {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line)
+ return PP_FromBool(
+ command_line->HasSwitch(switches::kDisablePepper3d));
+ return PP_TRUE;
+}
+
+} // namespace
+
+const PPB_GpuBlacklist_Private ppb_gpu_blacklist = {
+ &IsGpuBlacklisted,
+};
+
+// static
+const PPB_GpuBlacklist_Private* PPB_GpuBlacklist_Private_Impl::GetInterface() {
+ return &ppb_gpu_blacklist;
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/content/renderer/pepper/ppb_gpu_blacklist_private_impl.h b/content/renderer/pepper/ppb_gpu_blacklist_private_impl.h
new file mode 100644
index 0000000..189afe31
--- /dev/null
+++ b/content/renderer/pepper/ppb_gpu_blacklist_private_impl.h
@@ -0,0 +1,22 @@
+// 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_PEPPER_PPB_GPU_BLACKLIST_PRIVATE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_GPU_BLACKLIST_PRIVATE_IMPL_H_
+
+#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_GpuBlacklist_Private_Impl {
+ public:
+ static const PPB_GpuBlacklist_Private* GetInterface();
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_GPU_BLACKLIST_PRIVATE_IMPL_H_
+
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
new file mode 100644
index 0000000..26a7789
--- /dev/null
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -0,0 +1,328 @@
+// 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/ppb_graphics_3d_impl.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "ppapi/c/ppp_graphics_3d.h"
+#include "ppapi/thunk/enter.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "webkit/plugins/plugin_switches.h"
+
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Graphics3D_API;
+using WebKit::WebConsoleMessage;
+using WebKit::WebFrame;
+using WebKit::WebPluginContainer;
+using WebKit::WebString;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+const int32 kCommandBufferSize = 1024 * 1024;
+const int32 kTransferBufferSize = 1024 * 1024;
+
+PP_Bool ShmToHandle(base::SharedMemory* shm,
+ size_t size,
+ int* shm_handle,
+ uint32_t* shm_size) {
+ if (!shm || !shm_handle || !shm_size)
+ return PP_FALSE;
+#if defined(OS_POSIX)
+ *shm_handle = shm->handle().fd;
+#elif defined(OS_WIN)
+ *shm_handle = reinterpret_cast<int>(shm->handle());
+#else
+ #error "Platform not supported."
+#endif
+ *shm_size = size;
+ return PP_TRUE;
+}
+
+} // namespace.
+
+PPB_Graphics3D_Impl::PPB_Graphics3D_Impl(PP_Instance instance)
+ : PPB_Graphics3D_Shared(instance),
+ bound_to_instance_(false),
+ commit_pending_(false),
+ weak_ptr_factory_(this) {
+}
+
+PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
+ DestroyGLES2Impl();
+}
+
+// static
+PP_Bool PPB_Graphics3D_Impl::IsGpuBlacklisted() {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line)
+ return PP_FromBool(
+ command_line->HasSwitch(switches::kDisablePepper3d));
+ return PP_TRUE;
+}
+
+// static
+PP_Resource PPB_Graphics3D_Impl::Create(PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list) {
+ PPB_Graphics3D_API* share_api = NULL;
+ if (IsGpuBlacklisted())
+ return 0;
+ if (share_context) {
+ EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
+ if (enter.failed())
+ return 0;
+ share_api = enter.object();
+ }
+ scoped_refptr<PPB_Graphics3D_Impl> graphics_3d(
+ new PPB_Graphics3D_Impl(instance));
+ if (!graphics_3d->Init(share_api, attrib_list))
+ return 0;
+ return graphics_3d->GetReference();
+}
+
+// static
+PP_Resource PPB_Graphics3D_Impl::CreateRaw(PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list) {
+ PPB_Graphics3D_API* share_api = NULL;
+ if (IsGpuBlacklisted())
+ return 0;
+ if (share_context) {
+ EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
+ if (enter.failed())
+ return 0;
+ share_api = enter.object();
+ }
+ scoped_refptr<PPB_Graphics3D_Impl> graphics_3d(
+ new PPB_Graphics3D_Impl(instance));
+ if (!graphics_3d->InitRaw(share_api, attrib_list))
+ return 0;
+ return graphics_3d->GetReference();
+}
+
+PP_Bool PPB_Graphics3D_Impl::SetGetBuffer(int32_t transfer_buffer_id) {
+ GetCommandBuffer()->SetGetBuffer(transfer_buffer_id);
+ return PP_TRUE;
+}
+
+gpu::CommandBuffer::State PPB_Graphics3D_Impl::GetState() {
+ return GetCommandBuffer()->GetState();
+}
+
+int32_t PPB_Graphics3D_Impl::CreateTransferBuffer(uint32_t size) {
+ int32_t id = -1;
+ GetCommandBuffer()->CreateTransferBuffer(size, &id);
+ return id;
+}
+
+PP_Bool PPB_Graphics3D_Impl::DestroyTransferBuffer(int32_t id) {
+ GetCommandBuffer()->DestroyTransferBuffer(id);
+ return PP_TRUE;
+}
+
+PP_Bool PPB_Graphics3D_Impl::GetTransferBuffer(int32_t id,
+ int* shm_handle,
+ uint32_t* shm_size) {
+ gpu::Buffer buffer = GetCommandBuffer()->GetTransferBuffer(id);
+ return ShmToHandle(buffer.shared_memory, buffer.size, shm_handle, shm_size);
+}
+
+PP_Bool PPB_Graphics3D_Impl::Flush(int32_t put_offset) {
+ GetCommandBuffer()->Flush(put_offset);
+ return PP_TRUE;
+}
+
+gpu::CommandBuffer::State PPB_Graphics3D_Impl::FlushSync(int32_t put_offset) {
+ gpu::CommandBuffer::State state = GetCommandBuffer()->GetState();
+ return GetCommandBuffer()->FlushSync(put_offset, state.get_offset);
+}
+
+gpu::CommandBuffer::State PPB_Graphics3D_Impl::FlushSyncFast(
+ int32_t put_offset,
+ int32_t last_known_get) {
+ return GetCommandBuffer()->FlushSync(put_offset, last_known_get);
+}
+
+uint32_t PPB_Graphics3D_Impl::InsertSyncPoint() {
+ return GetCommandBuffer()->InsertSyncPoint();
+}
+
+bool PPB_Graphics3D_Impl::BindToInstance(bool bind) {
+ bound_to_instance_ = bind;
+ return true;
+}
+
+bool PPB_Graphics3D_Impl::IsOpaque() {
+ return platform_context_->IsOpaque();
+}
+
+void PPB_Graphics3D_Impl::ViewWillInitiatePaint() {
+}
+
+void PPB_Graphics3D_Impl::ViewInitiatedPaint() {
+ commit_pending_ = false;
+
+ if (HasPendingSwap())
+ SwapBuffersACK(PP_OK);
+}
+
+void PPB_Graphics3D_Impl::ViewFlushedPaint() {
+}
+
+gpu::CommandBuffer* PPB_Graphics3D_Impl::GetCommandBuffer() {
+ return platform_context_->GetCommandBuffer();
+}
+
+int32 PPB_Graphics3D_Impl::DoSwapBuffers() {
+ // We do not have a GLES2 implementation when using an OOP proxy.
+ // The plugin-side proxy is responsible for adding the SwapBuffers command
+ // to the command buffer in that case.
+ if (gles2_impl())
+ gles2_impl()->SwapBuffers();
+
+ if (bound_to_instance_) {
+ // If we are bound to the instance, we need to ask the compositor
+ // to commit our backing texture so that the graphics appears on the page.
+ // When the backing texture will be committed we get notified via
+ // ViewFlushedPaint().
+ //
+ // Don't need to check for NULL from GetPluginInstance since when we're
+ // bound, we know our instance is valid.
+ ResourceHelper::GetPluginInstance(this)->CommitBackingTexture();
+ commit_pending_ = true;
+ } else {
+ // Wait for the command to complete on the GPU to allow for throttling.
+ platform_context_->Echo(base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+bool PPB_Graphics3D_Impl::Init(PPB_Graphics3D_API* share_context,
+ const int32_t* attrib_list) {
+ if (!InitRaw(share_context, attrib_list))
+ return false;
+
+ gpu::CommandBuffer* command_buffer = GetCommandBuffer();
+ if (!command_buffer->Initialize())
+ return false;
+
+ gpu::gles2::GLES2Implementation* share_gles2 = NULL;
+ if (share_context) {
+ share_gles2 =
+ static_cast<PPB_Graphics3D_Shared*>(share_context)->gles2_impl();
+ }
+
+ return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize,
+ share_gles2);
+}
+
+bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context,
+ const int32_t* attrib_list) {
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return false;
+
+ PluginDelegate::PlatformContext3D* share_platform_context = NULL;
+ if (share_context) {
+ PPB_Graphics3D_Impl* share_graphics =
+ static_cast<PPB_Graphics3D_Impl*>(share_context);
+ share_platform_context = share_graphics->platform_context();
+ }
+
+ platform_context_.reset(plugin_instance->CreateContext3D());
+ if (!platform_context_)
+ return false;
+
+ if (!platform_context_->Init(attrib_list, share_platform_context))
+ return false;
+
+ platform_context_->SetContextLostCallback(
+ base::Bind(&PPB_Graphics3D_Impl::OnContextLost,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ platform_context_->SetOnConsoleMessageCallback(
+ base::Bind(&PPB_Graphics3D_Impl::OnConsoleMessage,
+ weak_ptr_factory_.GetWeakPtr()));
+ return true;
+}
+
+void PPB_Graphics3D_Impl::OnConsoleMessage(const std::string& message,
+ int id) {
+ if (!bound_to_instance_)
+ return;
+ WebPluginContainer* container =
+ ResourceHelper::GetPluginInstance(this)->container();
+ if (!container)
+ return;
+ WebFrame* frame = container->element().document().frame();
+ if (!frame)
+ return;
+ WebConsoleMessage console_message = WebConsoleMessage(
+ WebConsoleMessage::LevelError, WebString(UTF8ToUTF16(message)));
+ frame->addMessageToConsole(console_message);
+}
+
+void PPB_Graphics3D_Impl::OnSwapBuffers() {
+ if (HasPendingSwap()) {
+ // If we're off-screen, no need to trigger and wait for compositing.
+ // Just send the swap-buffers ACK to the plugin immediately.
+ commit_pending_ = false;
+ SwapBuffersACK(PP_OK);
+ }
+}
+
+void PPB_Graphics3D_Impl::OnContextLost() {
+ // Don't need to check for NULL from GetPluginInstance since when we're
+ // bound, we know our instance is valid.
+ if (bound_to_instance_)
+ ResourceHelper::GetPluginInstance(this)->BindGraphics(pp_instance(), 0);
+
+ // Send context lost to plugin. This may have been caused by a PPAPI call, so
+ // avoid re-entering.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PPB_Graphics3D_Impl::SendContextLost,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PPB_Graphics3D_Impl::SendContextLost() {
+ // By the time we run this, the instance may have been deleted, or in the
+ // process of being deleted. Even in the latter case, we don't want to send a
+ // callback after DidDestroy.
+ PluginInstanceImpl* instance = ResourceHelper::GetPluginInstance(this);
+ if (!instance || !instance->container())
+ return;
+
+ // This PPB_Graphics3D_Impl could be deleted during the call to
+ // GetPluginInterface (which sends a sync message in some cases). We still
+ // send the Graphics3DContextLost to the plugin; the instance may care about
+ // that event even though this context has been destroyed.
+ PP_Instance this_pp_instance = pp_instance();
+ const PPP_Graphics3D* ppp_graphics_3d =
+ static_cast<const PPP_Graphics3D*>(
+ instance->module()->GetPluginInterface(
+ PPP_GRAPHICS_3D_INTERFACE));
+ if (ppp_graphics_3d)
+ ppp_graphics_3d->Graphics3DContextLost(this_pp_instance);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.h b/content/renderer/pepper/ppb_graphics_3d_impl.h
new file mode 100644
index 0000000..e84a766
--- /dev/null
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PPB_GRAPHICS_3D_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_GRAPHICS_3D_IMPL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/shared_impl/ppb_graphics_3d_shared.h"
+#include "ppapi/shared_impl/resource.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Graphics3D_Impl : public ::ppapi::PPB_Graphics3D_Shared {
+ public:
+ static PP_Resource Create(PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list);
+ static PP_Resource CreateRaw(PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list);
+
+ // PPB_Graphics3D_API trusted implementation.
+ virtual PP_Bool SetGetBuffer(int32_t transfer_buffer_id) OVERRIDE;
+ virtual gpu::CommandBuffer::State GetState() OVERRIDE;
+ virtual int32_t CreateTransferBuffer(uint32_t size) OVERRIDE;
+ virtual PP_Bool DestroyTransferBuffer(int32_t id) OVERRIDE;
+ virtual PP_Bool GetTransferBuffer(int32_t id,
+ int* shm_handle,
+ uint32_t* shm_size) OVERRIDE;
+ virtual PP_Bool Flush(int32_t put_offset) OVERRIDE;
+ virtual gpu::CommandBuffer::State FlushSync(int32_t put_offset) OVERRIDE;
+ virtual gpu::CommandBuffer::State FlushSyncFast(
+ int32_t put_offset,
+ int32_t last_known_get) OVERRIDE;
+ virtual uint32_t InsertSyncPoint() OVERRIDE;
+
+ // Binds/unbinds the graphics of this context with the associated instance.
+ // Returns true if binding/unbinding is successful.
+ bool BindToInstance(bool bind);
+
+ // Returns true if the backing texture is always opaque.
+ bool IsOpaque();
+
+ // Notifications about the view's progress painting. See PluginInstance.
+ // These messages are used to send Flush callbacks to the plugin.
+ void ViewWillInitiatePaint();
+ void ViewInitiatedPaint();
+ void ViewFlushedPaint();
+
+ PluginDelegate::PlatformContext3D* platform_context() {
+ return platform_context_.get();
+ }
+
+ protected:
+ virtual ~PPB_Graphics3D_Impl();
+ // ppapi::PPB_Graphics3D_Shared overrides.
+ virtual gpu::CommandBuffer* GetCommandBuffer() OVERRIDE;
+ virtual int32 DoSwapBuffers() OVERRIDE;
+
+ private:
+ explicit PPB_Graphics3D_Impl(PP_Instance instance);
+
+ static PP_Bool IsGpuBlacklisted();
+
+ bool Init(PPB_Graphics3D_API* share_context,
+ const int32_t* attrib_list);
+ bool InitRaw(PPB_Graphics3D_API* share_context,
+ const int32_t* attrib_list);
+
+ // Notifications received from the GPU process.
+ void OnSwapBuffers();
+ void OnContextLost();
+ void OnConsoleMessage(const std::string& msg, int id);
+ // Notifications sent to plugin.
+ void SendContextLost();
+
+ // True if context is bound to instance.
+ bool bound_to_instance_;
+ // True when waiting for compositor to commit our backing texture.
+ bool commit_pending_;
+ // PluginDelegate's 3D Context. Responsible for providing the command buffer.
+ scoped_ptr<PluginDelegate::PlatformContext3D> platform_context_;
+ base::WeakPtrFactory<PPB_Graphics3D_Impl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Graphics3D_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_GRAPHICS_3D_IMPL_H_
diff --git a/content/renderer/pepper/ppb_image_data_impl.cc b/content/renderer/pepper/ppb_image_data_impl.cc
new file mode 100644
index 0000000..e17b348
--- /dev/null
+++ b/content/renderer/pepper/ppb_image_data_impl.cc
@@ -0,0 +1,278 @@
+// 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/ppb_image_data_impl.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "skia/ext/platform_canvas.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/thunk/thunk.h"
+#include "third_party/skia/include/core/SkColorPriv.h"
+
+using ::ppapi::thunk::PPB_ImageData_API;
+
+namespace webkit {
+namespace ppapi {
+
+PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance,
+ PPB_ImageData_Shared::ImageDataType type)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL),
+ width_(0),
+ height_(0) {
+ switch (type) {
+ case PPB_ImageData_Shared::PLATFORM:
+ backend_.reset(new ImageDataPlatformBackend);
+ return;
+ case PPB_ImageData_Shared::SIMPLE:
+ backend_.reset(new ImageDataSimpleBackend);
+ return;
+ // No default: so that we get a compiler warning if any types are added.
+ }
+ NOTREACHED();
+}
+
+PPB_ImageData_Impl::~PPB_ImageData_Impl() {
+}
+
+bool PPB_ImageData_Impl::Init(PP_ImageDataFormat format,
+ int width, int height,
+ bool init_to_zero) {
+ // TODO(brettw) this should be called only on the main thread!
+ if (!IsImageDataFormatSupported(format))
+ return false; // Only support this one format for now.
+ if (width <= 0 || height <= 0)
+ return false;
+ if (static_cast<int64>(width) * static_cast<int64>(height) >=
+ std::numeric_limits<int32>::max() / 4)
+ return false; // Prevent overflow of signed 32-bit ints.
+
+ format_ = format;
+ width_ = width;
+ height_ = height;
+ return backend_->Init(this, format, width, height, init_to_zero);
+}
+
+// static
+PP_Resource PPB_ImageData_Impl::Create(PP_Instance instance,
+ PPB_ImageData_Shared::ImageDataType type,
+ PP_ImageDataFormat format,
+ const PP_Size& size,
+ PP_Bool init_to_zero) {
+ scoped_refptr<PPB_ImageData_Impl>
+ data(new PPB_ImageData_Impl(instance, type));
+ if (!data->Init(format, size.width, size.height, !!init_to_zero))
+ return 0;
+ return data->GetReference();
+}
+
+PPB_ImageData_API* PPB_ImageData_Impl::AsPPB_ImageData_API() {
+ return this;
+}
+
+bool PPB_ImageData_Impl::IsMapped() const {
+ return backend_->IsMapped();
+}
+
+PluginDelegate::PlatformImage2D* PPB_ImageData_Impl::PlatformImage() const {
+ return backend_->PlatformImage();
+}
+
+PP_Bool PPB_ImageData_Impl::Describe(PP_ImageDataDesc* desc) {
+ desc->format = format_;
+ desc->size.width = width_;
+ desc->size.height = height_;
+ desc->stride = width_ * 4;
+ return PP_TRUE;
+}
+
+void* PPB_ImageData_Impl::Map() {
+ return backend_->Map();
+}
+
+void PPB_ImageData_Impl::Unmap() {
+ backend_->Unmap();
+}
+
+int32_t PPB_ImageData_Impl::GetSharedMemory(int* handle, uint32_t* byte_count) {
+ return backend_->GetSharedMemory(handle, byte_count);
+}
+
+skia::PlatformCanvas* PPB_ImageData_Impl::GetPlatformCanvas() {
+ return backend_->GetPlatformCanvas();
+}
+
+SkCanvas* PPB_ImageData_Impl::GetCanvas() {
+ return backend_->GetCanvas();
+}
+
+void PPB_ImageData_Impl::SetIsCandidateForReuse() {
+ // Nothing to do since we don't support image data re-use in-process.
+}
+
+const SkBitmap* PPB_ImageData_Impl::GetMappedBitmap() const {
+ return backend_->GetMappedBitmap();
+}
+
+// ImageDataPlatformBackend ----------------------------------------------------
+
+ImageDataPlatformBackend::ImageDataPlatformBackend() {
+}
+
+ImageDataPlatformBackend::~ImageDataPlatformBackend() {
+}
+
+bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl* impl,
+ PP_ImageDataFormat format,
+ int width, int height,
+ bool init_to_zero) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(impl);
+ if (!plugin_delegate)
+ return false;
+
+ // TODO(brettw) use init_to_zero when we implement caching.
+ platform_image_.reset(plugin_delegate->CreateImage2D(width, height));
+ return !!platform_image_.get();
+}
+
+bool ImageDataPlatformBackend::IsMapped() const {
+ return !!mapped_canvas_.get();
+}
+
+PluginDelegate::PlatformImage2D*
+ImageDataPlatformBackend::PlatformImage() const {
+ return platform_image_.get();
+}
+
+void* ImageDataPlatformBackend::Map() {
+ if (!mapped_canvas_) {
+ mapped_canvas_.reset(platform_image_->Map());
+ if (!mapped_canvas_)
+ return NULL;
+ }
+ const SkBitmap& bitmap =
+ skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true);
+
+ // Our platform bitmaps are set to opaque by default, which we don't want.
+ const_cast<SkBitmap&>(bitmap).setIsOpaque(false);
+
+ bitmap.lockPixels();
+ return bitmap.getAddr32(0, 0);
+}
+
+void ImageDataPlatformBackend::Unmap() {
+ // This is currently unimplemented, which is OK. The data will just always
+ // be around once it's mapped. Chrome's TransportDIB isn't currently
+ // unmappable without freeing it, but this may be something we want to support
+ // in the future to save some memory.
+}
+
+int32_t ImageDataPlatformBackend::GetSharedMemory(int* handle,
+ uint32_t* byte_count) {
+ *handle = platform_image_->GetSharedMemoryHandle(byte_count);
+ return PP_OK;
+}
+
+skia::PlatformCanvas* ImageDataPlatformBackend::GetPlatformCanvas() {
+ return mapped_canvas_.get();
+}
+
+SkCanvas* ImageDataPlatformBackend::GetCanvas() {
+ return mapped_canvas_.get();
+}
+
+const SkBitmap* ImageDataPlatformBackend::GetMappedBitmap() const {
+ if (!mapped_canvas_)
+ return NULL;
+ return &skia::GetTopDevice(*mapped_canvas_)->accessBitmap(false);
+}
+
+// ImageDataSimpleBackend ------------------------------------------------------
+
+ImageDataSimpleBackend::ImageDataSimpleBackend()
+ : map_count_(0) {
+}
+
+ImageDataSimpleBackend::~ImageDataSimpleBackend() {
+}
+
+bool ImageDataSimpleBackend::Init(PPB_ImageData_Impl* impl,
+ PP_ImageDataFormat format,
+ int width, int height,
+ bool init_to_zero) {
+ skia_bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
+ impl->width(), impl->height());
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(impl);
+ if (!plugin_delegate)
+ return false;
+ shared_memory_.reset(
+ plugin_delegate->CreateAnonymousSharedMemory(skia_bitmap_.getSize()));
+ return !!shared_memory_.get();
+}
+
+bool ImageDataSimpleBackend::IsMapped() const {
+ return map_count_ > 0;
+}
+
+PluginDelegate::PlatformImage2D* ImageDataSimpleBackend::PlatformImage() const {
+ return NULL;
+}
+
+void* ImageDataSimpleBackend::Map() {
+ DCHECK(shared_memory_.get());
+ if (map_count_++ == 0) {
+ shared_memory_->Map(skia_bitmap_.getSize());
+ skia_bitmap_.setPixels(shared_memory_->memory());
+ // Our platform bitmaps are set to opaque by default, which we don't want.
+ skia_bitmap_.setIsOpaque(false);
+ skia_canvas_.reset(new SkCanvas(skia_bitmap_));
+ return skia_bitmap_.getAddr32(0, 0);
+ }
+ return shared_memory_->memory();
+}
+
+void ImageDataSimpleBackend::Unmap() {
+ if (--map_count_ == 0)
+ shared_memory_->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
+ return PP_OK;
+}
+
+skia::PlatformCanvas* ImageDataSimpleBackend::GetPlatformCanvas() {
+ return NULL;
+}
+
+SkCanvas* ImageDataSimpleBackend::GetCanvas() {
+ if (!IsMapped())
+ return NULL;
+ return skia_canvas_.get();
+}
+
+const SkBitmap* ImageDataSimpleBackend::GetMappedBitmap() const {
+ if (!IsMapped())
+ return NULL;
+ return &skia_bitmap_;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_image_data_impl.h b/content/renderer/pepper/ppb_image_data_impl.h
new file mode 100644
index 0000000..58cba82
--- /dev/null
+++ b/content/renderer/pepper/ppb_image_data_impl.h
@@ -0,0 +1,197 @@
+// 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_PPB_IMAGE_DATA_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_IMAGE_DATA_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/shared_impl/ppb_image_data_shared.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_image_data_api.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+class SkBitmap;
+class SkCanvas;
+
+namespace webkit {
+namespace ppapi {
+
+class CONTENT_EXPORT PPB_ImageData_Impl
+ : public ::ppapi::Resource,
+ public ::ppapi::PPB_ImageData_Shared,
+ public NON_EXPORTED_BASE(::ppapi::thunk::PPB_ImageData_API) {
+ public:
+ // We delegate most of our implementation to a back-end class that either uses
+ // a PlatformCanvas (for most trusted stuff) or bare shared memory (for use by
+ // NaCl, or trusted plugins when the PlatformCanvas isn't needed). This makes
+ // it cheap & easy to implement Swap.
+ class Backend {
+ public:
+ virtual ~Backend() {};
+ virtual bool Init(PPB_ImageData_Impl* impl, PP_ImageDataFormat format,
+ int width, int height, bool init_to_zero) = 0;
+ virtual bool IsMapped() const = 0;
+ virtual PluginDelegate::PlatformImage2D* PlatformImage() const = 0;
+ virtual void* Map() = 0;
+ virtual void Unmap() = 0;
+ virtual int32_t GetSharedMemory(int* handle, uint32_t* byte_count) = 0;
+ virtual SkCanvas* GetPlatformCanvas() = 0;
+ virtual SkCanvas* GetCanvas() = 0;
+ virtual const SkBitmap* GetMappedBitmap() const = 0;
+ };
+
+ // If you call this constructor, you must also call Init before use. Normally
+ // you should use the static Create function, but this constructor is needed
+ // for some internal uses of ImageData (like Graphics2D).
+ PPB_ImageData_Impl(PP_Instance instance,
+ PPB_ImageData_Shared::ImageDataType type);
+
+ bool Init(PP_ImageDataFormat format,
+ int width, int height,
+ bool init_to_zero);
+
+ static PP_Resource Create(PP_Instance pp_instance,
+ PPB_ImageData_Shared::ImageDataType type,
+ PP_ImageDataFormat format,
+ const PP_Size& size,
+ PP_Bool init_to_zero);
+
+ int width() const { return width_; }
+ int height() const { return height_; }
+
+ // Returns the image format.
+ PP_ImageDataFormat format() const { return format_; }
+
+ // Returns true if this image is mapped. False means that the image is either
+ // invalid or not mapped. See ImageDataAutoMapper below.
+ bool IsMapped() const;
+ PluginDelegate::PlatformImage2D* PlatformImage() const;
+
+ // Resource override.
+ virtual ::ppapi::thunk::PPB_ImageData_API* AsPPB_ImageData_API() OVERRIDE;
+
+ // PPB_ImageData_API implementation.
+ virtual PP_Bool Describe(PP_ImageDataDesc* desc) OVERRIDE;
+ virtual void* Map() OVERRIDE;
+ virtual void Unmap() OVERRIDE;
+ virtual int32_t GetSharedMemory(int* handle, uint32_t* byte_count) OVERRIDE;
+ virtual SkCanvas* GetPlatformCanvas() OVERRIDE;
+ virtual SkCanvas* GetCanvas() OVERRIDE;
+ virtual void SetIsCandidateForReuse() OVERRIDE;
+
+ const SkBitmap* GetMappedBitmap() const;
+
+ private:
+ virtual ~PPB_ImageData_Impl();
+
+ PP_ImageDataFormat format_;
+ int width_;
+ int height_;
+ scoped_ptr<Backend> backend_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_ImageData_Impl);
+};
+
+class ImageDataPlatformBackend : public PPB_ImageData_Impl::Backend {
+ public:
+ ImageDataPlatformBackend();
+ virtual ~ImageDataPlatformBackend();
+
+ // PPB_ImageData_Impl::Backend implementation.
+ virtual bool Init(PPB_ImageData_Impl* impl, PP_ImageDataFormat format,
+ int width, int height, bool init_to_zero) OVERRIDE;
+ virtual bool IsMapped() const OVERRIDE;
+ virtual PluginDelegate::PlatformImage2D* PlatformImage() const OVERRIDE;
+ virtual void* Map() OVERRIDE;
+ virtual void Unmap() OVERRIDE;
+ virtual int32_t GetSharedMemory(int* handle, uint32_t* byte_count) OVERRIDE;
+ virtual SkCanvas* GetPlatformCanvas() OVERRIDE;
+ virtual SkCanvas* GetCanvas() OVERRIDE;
+ virtual const SkBitmap* GetMappedBitmap() const OVERRIDE;
+
+ private:
+ // This will be NULL before initialization, and if this PPB_ImageData_Impl is
+ // swapped with another.
+ scoped_ptr<PluginDelegate::PlatformImage2D> platform_image_;
+
+ // When the device is mapped, this is the image. Null when umapped.
+ scoped_ptr<SkCanvas> mapped_canvas_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDataPlatformBackend);
+};
+
+class ImageDataSimpleBackend : public PPB_ImageData_Impl::Backend {
+ public:
+ ImageDataSimpleBackend();
+ virtual ~ImageDataSimpleBackend();
+
+ // PPB_ImageData_Impl::Backend implementation.
+ virtual bool Init(PPB_ImageData_Impl* impl, PP_ImageDataFormat format,
+ int width, int height, bool init_to_zero) OVERRIDE;
+ virtual bool IsMapped() const OVERRIDE;
+ virtual PluginDelegate::PlatformImage2D* PlatformImage() const OVERRIDE;
+ virtual void* Map() OVERRIDE;
+ virtual void Unmap() OVERRIDE;
+ virtual int32_t GetSharedMemory(int* handle, uint32_t* byte_count) OVERRIDE;
+ virtual SkCanvas* GetPlatformCanvas() OVERRIDE;
+ virtual SkCanvas* GetCanvas() OVERRIDE;
+ virtual const SkBitmap* GetMappedBitmap() const OVERRIDE;
+
+ private:
+ scoped_ptr<base::SharedMemory> shared_memory_;
+ // skia_bitmap_ is backed by shared_memory_.
+ SkBitmap skia_bitmap_;
+ scoped_ptr<SkCanvas> skia_canvas_;
+ uint32 map_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDataSimpleBackend);
+};
+
+// Manages mapping an image resource if necessary. Use this to ensure the
+// image is mapped. The destructor will put the image back into the previous
+// state. You must check is_valid() to make sure the image was successfully
+// mapped before using it.
+//
+// Example:
+// ImageDataAutoMapper mapper(image_data);
+// if (!mapper.is_valid())
+// return utter_failure;
+// image_data->mapped_canvas()->blah(); // Guaranteed valid.
+class ImageDataAutoMapper {
+ public:
+ explicit ImageDataAutoMapper(PPB_ImageData_Impl* image_data)
+ : image_data_(image_data) {
+ if (image_data_->IsMapped()) {
+ is_valid_ = true;
+ needs_unmap_ = false;
+ } else {
+ is_valid_ = needs_unmap_ = !!image_data_->Map();
+ }
+ }
+
+ ~ImageDataAutoMapper() {
+ if (needs_unmap_)
+ image_data_->Unmap();
+ }
+
+ // Check this to see if the image was successfully mapped. If this is false,
+ // the image could not be mapped and is unusable.
+ bool is_valid() const { return is_valid_; }
+
+ private:
+ PPB_ImageData_Impl* image_data_;
+ bool is_valid_;
+ bool needs_unmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDataAutoMapper);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_IMAGE_DATA_IMPL_H_
diff --git a/content/renderer/pepper/ppb_network_monitor_private_impl.cc b/content/renderer/pepper/ppb_network_monitor_private_impl.cc
new file mode 100644
index 0000000..75a8935
--- /dev/null
+++ b/content/renderer/pepper/ppb_network_monitor_private_impl.cc
@@ -0,0 +1,89 @@
+// 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/ppb_network_monitor_private_impl.h"
+
+#include "base/bind.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/shared_impl/ppb_network_list_private_shared.h"
+#include "ppapi/shared_impl/private/net_address_private_impl.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_util.h"
+
+namespace webkit {
+namespace ppapi {
+
+PPB_NetworkMonitor_Private_Impl::PPB_NetworkMonitor_Private_Impl(
+ PP_Instance instance,
+ PPB_NetworkMonitor_Callback callback,
+ void* user_data)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ callback_(callback),
+ user_data_(user_data),
+ started_(false) {
+}
+
+PPB_NetworkMonitor_Private_Impl::~PPB_NetworkMonitor_Private_Impl() {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (plugin_delegate && started_) {
+ plugin_delegate->RemoveNetworkListObserver(this);
+ }
+}
+
+// static
+PP_Resource PPB_NetworkMonitor_Private_Impl::Create(
+ PP_Instance instance,
+ PPB_NetworkMonitor_Callback callback,
+ void* user_data) {
+ scoped_refptr<PPB_NetworkMonitor_Private_Impl> result(
+ new PPB_NetworkMonitor_Private_Impl(instance, callback, user_data));
+ if (!result->Start())
+ return 0;
+ return result->GetReference();
+}
+
+::ppapi::thunk::PPB_NetworkMonitor_Private_API*
+PPB_NetworkMonitor_Private_Impl::AsPPB_NetworkMonitor_Private_API() {
+ return this;
+}
+
+bool PPB_NetworkMonitor_Private_Impl::Start() {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return false;
+ started_ = plugin_delegate->AddNetworkListObserver(this);
+ return started_;
+}
+
+void PPB_NetworkMonitor_Private_Impl::OnNetworkListChanged(
+ const net::NetworkInterfaceList& list) {
+ ::ppapi::NetworkList list_copy(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ ::ppapi::NetworkInfo& network = list_copy.at(i);
+ network.name = list[i].name;
+
+ network.addresses.resize(
+ 1, ::ppapi::NetAddressPrivateImpl::kInvalidNetAddress);
+ bool result = ::ppapi::NetAddressPrivateImpl::IPEndPointToNetAddress(
+ list[i].address, 0, &(network.addresses[0]));
+ DCHECK(result);
+
+ // TODO(sergeyu): Currently net::NetworkInterfaceList provides
+ // only name and one IP address. Add all other fields and copy
+ // them here.
+ network.type = PP_NETWORKLIST_UNKNOWN;
+ network.state = PP_NETWORKLIST_UP;
+ network.display_name = list[i].name;
+ network.mtu = 0;
+ }
+ scoped_refptr< ::ppapi::NetworkListStorage> list_storage(
+ new ::ppapi::NetworkListStorage(list_copy));
+ PP_Resource list_resource =
+ ::ppapi::PPB_NetworkList_Private_Shared::Create(
+ ::ppapi::OBJECT_IS_IMPL, pp_instance(), list_storage);
+ callback_(user_data_, list_resource);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_network_monitor_private_impl.h b/content/renderer/pepper/ppb_network_monitor_private_impl.h
new file mode 100644
index 0000000..c603eb1
--- /dev/null
+++ b/content/renderer/pepper/ppb_network_monitor_private_impl.h
@@ -0,0 +1,53 @@
+// 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_PPB_NETWORK_MONITOR_PRIVATE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_NETWORK_MONITOR_PRIVATE_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/private/ppb_network_monitor_private.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_network_monitor_private_api.h"
+#include "webkit/glue/network_list_observer.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_NetworkMonitor_Private_Impl
+ : public ::ppapi::Resource,
+ public ::ppapi::thunk::PPB_NetworkMonitor_Private_API,
+ public webkit_glue::NetworkListObserver {
+ public:
+ static PP_Resource Create(PP_Instance instance,
+ PPB_NetworkMonitor_Callback callback,
+ void* user_data);
+
+ virtual ::ppapi::thunk::PPB_NetworkMonitor_Private_API*
+ AsPPB_NetworkMonitor_Private_API() OVERRIDE;
+
+ // NetworkListObserver interface.
+ virtual void OnNetworkListChanged(
+ const net::NetworkInterfaceList& list) OVERRIDE;
+
+ private:
+ PPB_NetworkMonitor_Private_Impl(PP_Instance instance,
+ PPB_NetworkMonitor_Callback callback,
+ void* user_data);
+ virtual ~PPB_NetworkMonitor_Private_Impl();
+
+ bool Start();
+
+ PPB_NetworkMonitor_Callback callback_;
+ void* user_data_;
+ bool started_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_NetworkMonitor_Private_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_NETWORK_MONITOR_PRIVATE_IMPL_H_
diff --git a/content/renderer/pepper/ppb_proxy_impl.cc b/content/renderer/pepper/ppb_proxy_impl.cc
new file mode 100644
index 0000000..caf63f7
--- /dev/null
+++ b/content/renderer/pepper/ppb_proxy_impl.cc
@@ -0,0 +1,79 @@
+// 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/pepper/ppb_proxy_impl.h"
+
+#include "ppapi/c/private/ppb_proxy_private.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_image_data_api.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/plugin_module.h"
+
+using ppapi::PpapiGlobals;
+using ppapi::thunk::EnterResource;
+using ppapi::thunk::PPB_URLLoader_API;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+void PluginCrashed(PP_Module module) {
+ PluginModule* plugin_module = HostGlobals::Get()->GetModule(module);
+ if (plugin_module)
+ plugin_module->PluginCrashed();
+}
+
+PP_Instance GetInstanceForResource(PP_Resource resource) {
+ ::ppapi::Resource* obj =
+ PpapiGlobals::Get()->GetResourceTracker()->GetResource(resource);
+ if (!obj)
+ return 0;
+ return obj->pp_instance();
+}
+
+void SetReserveInstanceIDCallback(PP_Module module,
+ PP_Bool (*reserve)(PP_Module, PP_Instance)) {
+ PluginModule* plugin_module = HostGlobals::Get()->GetModule(module);
+ if (plugin_module)
+ plugin_module->SetReserveInstanceIDCallback(reserve);
+}
+
+void AddRefModule(PP_Module module) {
+ PluginModule* plugin_module = HostGlobals::Get()->GetModule(module);
+ if (plugin_module)
+ plugin_module->AddRef();
+}
+
+void ReleaseModule(PP_Module module) {
+ PluginModule* plugin_module = HostGlobals::Get()->GetModule(module);
+ if (plugin_module)
+ plugin_module->Release();
+}
+
+PP_Bool IsInModuleDestructor(PP_Module module) {
+ PluginModule* plugin_module = HostGlobals::Get()->GetModule(module);
+ if (plugin_module)
+ return PP_FromBool(plugin_module->is_in_destructor());
+ return PP_FALSE;
+}
+
+const PPB_Proxy_Private ppb_proxy = {
+ &PluginCrashed,
+ &GetInstanceForResource,
+ &SetReserveInstanceIDCallback,
+ &AddRefModule,
+ &ReleaseModule,
+ &IsInModuleDestructor
+};
+
+} // namespace
+
+// static
+const PPB_Proxy_Private* PPB_Proxy_Impl::GetInterface() {
+ return &ppb_proxy;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_proxy_impl.h b/content/renderer/pepper/ppb_proxy_impl.h
new file mode 100644
index 0000000..04e12fc
--- /dev/null
+++ b/content/renderer/pepper/ppb_proxy_impl.h
@@ -0,0 +1,22 @@
+// 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_PEPPER_PPB_PROXY_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_PROXY_IMPL_H_
+
+struct PPB_Proxy_Private;
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Proxy_Impl {
+ public:
+ static const PPB_Proxy_Private* GetInterface();
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_PROXY_IMPL_H_
+
diff --git a/content/renderer/pepper/ppb_scrollbar_impl.cc b/content/renderer/pepper/ppb_scrollbar_impl.cc
new file mode 100644
index 0000000..a326cad
--- /dev/null
+++ b/content/renderer/pepper/ppb_scrollbar_impl.cc
@@ -0,0 +1,251 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/ppb_scrollbar_impl.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/event_conversion.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/c/dev/ppp_scrollbar_dev.h"
+#include "ppapi/thunk/thunk.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/public/platform/WebCanvas.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebPluginScrollbar.h"
+#include "webkit/glue/webkit_glue.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+using ppapi::thunk::PPB_Scrollbar_API;
+using WebKit::WebInputEvent;
+using WebKit::WebRect;
+using WebKit::WebScrollbar;
+using WebKit::WebPluginScrollbar;
+
+namespace webkit {
+namespace ppapi {
+
+// static
+PP_Resource PPB_Scrollbar_Impl::Create(PP_Instance instance,
+ bool vertical) {
+ scoped_refptr<PPB_Scrollbar_Impl> scrollbar(
+ new PPB_Scrollbar_Impl(instance));
+ scrollbar->Init(vertical);
+ return scrollbar->GetReference();
+}
+
+PPB_Scrollbar_Impl::PPB_Scrollbar_Impl(PP_Instance instance)
+ : PPB_Widget_Impl(instance),
+ weak_ptr_factory_(this) {
+}
+
+PPB_Scrollbar_Impl::~PPB_Scrollbar_Impl() {
+}
+
+void PPB_Scrollbar_Impl::Init(bool vertical) {
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return;
+ scrollbar_.reset(WebPluginScrollbar::createForPlugin(
+ vertical ? WebScrollbar::Vertical : WebScrollbar::Horizontal,
+ ResourceHelper::GetPluginInstance(this)->container(),
+ static_cast<WebKit::WebPluginScrollbarClient*>(this)));
+}
+
+PPB_Scrollbar_API* PPB_Scrollbar_Impl::AsPPB_Scrollbar_API() {
+ return this;
+}
+
+void PPB_Scrollbar_Impl::InstanceWasDeleted() {
+ scrollbar_.reset();
+}
+
+uint32_t PPB_Scrollbar_Impl::GetThickness() {
+ return WebPluginScrollbar::defaultThickness();
+}
+
+bool PPB_Scrollbar_Impl::IsOverlay() {
+ return scrollbar_->isOverlay();
+}
+
+uint32_t PPB_Scrollbar_Impl::GetValue() {
+ return scrollbar_->value();
+}
+
+void PPB_Scrollbar_Impl::SetValue(uint32_t value) {
+ if (scrollbar_)
+ scrollbar_->setValue(value);
+}
+
+void PPB_Scrollbar_Impl::SetDocumentSize(uint32_t size) {
+ if (scrollbar_)
+ scrollbar_->setDocumentSize(size);
+}
+
+void PPB_Scrollbar_Impl::SetTickMarks(const PP_Rect* tick_marks,
+ uint32_t count) {
+ if (!scrollbar_)
+ return;
+ tickmarks_.resize(count);
+ for (uint32 i = 0; i < count; ++i) {
+ tickmarks_[i] = WebRect(tick_marks[i].point.x,
+ tick_marks[i].point.y,
+ tick_marks[i].size.width,
+ tick_marks[i].size.height);;
+ }
+ PP_Rect rect = location();
+ Invalidate(&rect);
+}
+
+void PPB_Scrollbar_Impl::ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier) {
+ if (!scrollbar_)
+ return;
+
+ WebScrollbar::ScrollDirection direction = multiplier >= 0 ?
+ WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward;
+ float fmultiplier = 1.0;
+
+ WebScrollbar::ScrollGranularity granularity;
+ if (unit == PP_SCROLLBY_LINE) {
+ granularity = WebScrollbar::ScrollByLine;
+ } else if (unit == PP_SCROLLBY_PAGE) {
+ granularity = WebScrollbar::ScrollByPage;
+ } else if (unit == PP_SCROLLBY_DOCUMENT) {
+ granularity = WebScrollbar::ScrollByDocument;
+ } else {
+ granularity = WebScrollbar::ScrollByPixel;
+ fmultiplier = static_cast<float>(multiplier);
+ if (fmultiplier < 0)
+ fmultiplier *= -1;
+ }
+ scrollbar_->scroll(direction, granularity, fmultiplier);
+}
+
+PP_Bool PPB_Scrollbar_Impl::PaintInternal(const gfx::Rect& rect,
+ PPB_ImageData_Impl* image) {
+ ImageDataAutoMapper mapper(image);
+ skia::PlatformCanvas* canvas = image->GetPlatformCanvas();
+ if (!canvas || !scrollbar_)
+ return PP_FALSE;
+ canvas->save();
+ canvas->scale(scale(), scale());
+ scrollbar_->paint(canvas, rect);
+ canvas->restore();
+
+#if defined(OS_WIN)
+ if (base::win::GetVersion() == base::win::VERSION_XP)
+ skia::MakeOpaque(canvas, rect.x(), rect.y(), rect.width(), rect.height());
+#endif
+
+ return PP_TRUE;
+}
+
+PP_Bool PPB_Scrollbar_Impl::HandleEventInternal(
+ const ::ppapi::InputEventData& data) {
+ scoped_ptr<WebInputEvent> web_input_event(CreateWebInputEvent(data));
+ if (!web_input_event.get() || !scrollbar_)
+ return PP_FALSE;
+
+ return PP_FromBool(scrollbar_->handleInputEvent(*web_input_event.get()));
+}
+
+void PPB_Scrollbar_Impl::SetLocationInternal(const PP_Rect* location) {
+ if (!scrollbar_)
+ return;
+ scrollbar_->setLocation(WebRect(location->point.x,
+ location->point.y,
+ location->size.width,
+ location->size.height));
+}
+
+void PPB_Scrollbar_Impl::valueChanged(WebKit::WebPluginScrollbar* scrollbar) {
+ PluginModule* plugin_module = ResourceHelper::GetPluginModule(this);
+ if (!plugin_module)
+ return;
+
+ const PPP_Scrollbar_Dev* ppp_scrollbar =
+ static_cast<const PPP_Scrollbar_Dev*>(plugin_module->GetPluginInterface(
+ PPP_SCROLLBAR_DEV_INTERFACE));
+ if (!ppp_scrollbar) {
+ // Try the old version. This is ok because the old interface is a subset of
+ // the new one, and ValueChanged didn't change.
+ ppp_scrollbar =
+ static_cast<const PPP_Scrollbar_Dev*>(plugin_module->GetPluginInterface(
+ PPP_SCROLLBAR_DEV_INTERFACE_0_2));
+ if (!ppp_scrollbar)
+ return;
+ }
+ ppp_scrollbar->ValueChanged(pp_instance(), pp_resource(),
+ scrollbar_->value());
+}
+
+void PPB_Scrollbar_Impl::overlayChanged(WebPluginScrollbar* scrollbar) {
+ PluginModule* plugin_module = ResourceHelper::GetPluginModule(this);
+ if (!plugin_module)
+ return;
+
+ const PPP_Scrollbar_Dev* ppp_scrollbar =
+ static_cast<const PPP_Scrollbar_Dev*>(plugin_module->GetPluginInterface(
+ PPP_SCROLLBAR_DEV_INTERFACE));
+ if (!ppp_scrollbar)
+ return;
+ ppp_scrollbar->OverlayChanged(pp_instance(), pp_resource(),
+ PP_FromBool(IsOverlay()));
+}
+
+void PPB_Scrollbar_Impl::invalidateScrollbarRect(
+ WebKit::WebPluginScrollbar* scrollbar,
+ const WebKit::WebRect& rect) {
+ gfx::Rect gfx_rect(rect.x,
+ rect.y,
+ rect.width,
+ rect.height);
+ dirty_.Union(gfx_rect);
+ // Can't call into the client to tell them about the invalidate right away,
+ // since the PPB_Scrollbar_Impl code is still in the middle of updating its
+ // internal state.
+ // Note: we use a WeakPtrFactory here so that a lingering callback can not
+ // modify the lifetime of this object. Otherwise, WebKit::WebPluginScrollbar
+ // could outlive WebKit::WebPluginContainer, which is against its contract.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PPB_Scrollbar_Impl::NotifyInvalidate,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PPB_Scrollbar_Impl::getTickmarks(
+ WebKit::WebPluginScrollbar* scrollbar,
+ WebKit::WebVector<WebKit::WebRect>* tick_marks) const {
+ if (tickmarks_.empty()) {
+ WebRect* rects = NULL;
+ tick_marks->assign(rects, 0);
+ } else {
+ tick_marks->assign(&tickmarks_[0], tickmarks_.size());
+ }
+}
+
+void PPB_Scrollbar_Impl::NotifyInvalidate() {
+ if (dirty_.IsEmpty())
+ return;
+ PP_Rect pp_rect;
+ pp_rect.point.x = dirty_.x();
+ pp_rect.point.y = dirty_.y();
+ pp_rect.size.width = dirty_.width();
+ pp_rect.size.height = dirty_.height();
+ dirty_ = gfx::Rect();
+ Invalidate(&pp_rect);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_scrollbar_impl.h b/content/renderer/pepper/ppb_scrollbar_impl.h
new file mode 100644
index 0000000..eed236f
--- /dev/null
+++ b/content/renderer/pepper/ppb_scrollbar_impl.h
@@ -0,0 +1,78 @@
+// 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_PPB_SCROLLBAR_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_SCROLLBAR_IMPL_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/renderer/pepper/ppb_widget_impl.h"
+#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"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Scrollbar_Impl : public PPB_Widget_Impl,
+ public ::ppapi::thunk::PPB_Scrollbar_API,
+ public WebKit::WebPluginScrollbarClient {
+ public:
+ static PP_Resource Create(PP_Instance instance, bool vertical);
+
+ // Resource overrides.
+ virtual PPB_Scrollbar_API* AsPPB_Scrollbar_API() OVERRIDE;
+ virtual void InstanceWasDeleted() OVERRIDE;
+
+ // PPB_Scrollbar_API implementation.
+ virtual uint32_t GetThickness() OVERRIDE;
+ virtual bool IsOverlay() OVERRIDE;
+ virtual uint32_t GetValue() OVERRIDE;
+ virtual void SetValue(uint32_t value) OVERRIDE;
+ virtual void SetDocumentSize(uint32_t size) OVERRIDE;
+ virtual void SetTickMarks(const PP_Rect* tick_marks, uint32_t count) OVERRIDE;
+ virtual void ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier) OVERRIDE;
+
+ private:
+ virtual ~PPB_Scrollbar_Impl();
+
+ explicit PPB_Scrollbar_Impl(PP_Instance instance);
+ void Init(bool vertical);
+
+ // PPB_Widget private implementation.
+ virtual PP_Bool PaintInternal(const gfx::Rect& rect,
+ PPB_ImageData_Impl* image) OVERRIDE;
+ virtual PP_Bool HandleEventInternal(
+ const ::ppapi::InputEventData& data) OVERRIDE;
+ virtual void SetLocationInternal(const PP_Rect* location) OVERRIDE;
+
+ // WebKit::WebPluginScrollbarClient implementation.
+ virtual void valueChanged(WebKit::WebPluginScrollbar* scrollbar) OVERRIDE;
+ virtual void overlayChanged(WebKit::WebPluginScrollbar* scrollbar) OVERRIDE;
+ virtual void invalidateScrollbarRect(WebKit::WebPluginScrollbar* scrollbar,
+ const WebKit::WebRect& rect) OVERRIDE;
+ virtual void getTickmarks(
+ WebKit::WebPluginScrollbar* scrollbar,
+ WebKit::WebVector<WebKit::WebRect>* tick_marks) const OVERRIDE;
+
+ void NotifyInvalidate();
+
+ gfx::Rect dirty_;
+ std::vector<WebKit::WebRect> tickmarks_;
+ scoped_ptr<WebKit::WebPluginScrollbar> scrollbar_;
+
+ // Used so that the post task for Invalidate doesn't keep an extra reference.
+ base::WeakPtrFactory<PPB_Scrollbar_Impl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Scrollbar_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_SCROLLBAR_IMPL_H_
diff --git a/content/renderer/pepper/ppb_tcp_server_socket_private_impl.cc b/content/renderer/pepper/ppb_tcp_server_socket_private_impl.cc
new file mode 100644
index 0000000..2e8ceda
--- /dev/null
+++ b/content/renderer/pepper/ppb_tcp_server_socket_private_impl.cc
@@ -0,0 +1,82 @@
+// 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/ppb_tcp_server_socket_private_impl.h"
+
+#include "base/logging.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppb_tcp_socket_private_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+
+namespace webkit {
+namespace ppapi {
+
+PPB_TCPServerSocket_Private_Impl::PPB_TCPServerSocket_Private_Impl(
+ PP_Instance instance)
+ : ::ppapi::PPB_TCPServerSocket_Shared(instance) {
+}
+
+PPB_TCPServerSocket_Private_Impl::~PPB_TCPServerSocket_Private_Impl() {
+ StopListening();
+}
+
+PP_Resource PPB_TCPServerSocket_Private_Impl::CreateResource(
+ PP_Instance instance) {
+ PPB_TCPServerSocket_Private_Impl* socket =
+ new PPB_TCPServerSocket_Private_Impl(instance);
+ return socket->GetReference();
+}
+
+void PPB_TCPServerSocket_Private_Impl::OnAcceptCompleted(
+ bool succeeded,
+ uint32 accepted_socket_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) {
+ if (!::ppapi::TrackedCallback::IsPending(accept_callback_) ||
+ !tcp_socket_buffer_) {
+ NOTREACHED();
+ return;
+ }
+
+ if (succeeded) {
+ *tcp_socket_buffer_ =
+ PPB_TCPSocket_Private_Impl::CreateConnectedSocket(pp_instance(),
+ accepted_socket_id,
+ local_addr,
+ remote_addr);
+ }
+ tcp_socket_buffer_ = NULL;
+
+ accept_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
+}
+
+void PPB_TCPServerSocket_Private_Impl::SendListen(
+ const PP_NetAddress_Private& addr,
+ int32_t backlog) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPServerSocketListen(pp_resource(), addr, backlog);
+}
+
+void PPB_TCPServerSocket_Private_Impl::SendAccept() {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPServerSocketAccept(socket_id_);
+}
+
+void PPB_TCPServerSocket_Private_Impl::SendStopListening() {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPServerSocketStopListening(pp_resource(), socket_id_);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_tcp_server_socket_private_impl.h b/content/renderer/pepper/ppb_tcp_server_socket_private_impl.h
new file mode 100644
index 0000000..f048c7b
--- /dev/null
+++ b/content/renderer/pepper/ppb_tcp_server_socket_private_impl.h
@@ -0,0 +1,40 @@
+// 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_PPB_TCP_SERVER_SOCKET_PRIVATE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_TCP_SERVER_SOCKET_PRIVATE_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_TCPServerSocket_Private_Impl
+ : public ::ppapi::PPB_TCPServerSocket_Shared {
+ public:
+ static PP_Resource CreateResource(PP_Instance instance);
+
+ virtual void OnAcceptCompleted(
+ bool succeeded,
+ uint32 accepted_socket_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) OVERRIDE;
+
+ virtual void SendListen(const PP_NetAddress_Private& addr,
+ int32_t backlog) OVERRIDE;
+ virtual void SendAccept() OVERRIDE;
+ virtual void SendStopListening() OVERRIDE;
+
+ private:
+ PPB_TCPServerSocket_Private_Impl(PP_Instance instance);
+ virtual ~PPB_TCPServerSocket_Private_Impl();
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_TCPServerSocket_Private_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_TCP_SERVER_SOCKET_PRIVATE_IMPL_H_
diff --git a/content/renderer/pepper/ppb_tcp_socket_private_impl.cc b/content/renderer/pepper/ppb_tcp_socket_private_impl.cc
new file mode 100644
index 0000000..7ebcc64
--- /dev/null
+++ b/content/renderer/pepper/ppb_tcp_socket_private_impl.cc
@@ -0,0 +1,134 @@
+// 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/ppb_tcp_socket_private_impl.h"
+
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/shared_impl/socket_option_data.h"
+
+namespace webkit {
+namespace ppapi {
+
+PPB_TCPSocket_Private_Impl::PPB_TCPSocket_Private_Impl(
+ PP_Instance instance, uint32 socket_id)
+ : ::ppapi::TCPSocketPrivateImpl(instance, socket_id) {
+}
+
+PPB_TCPSocket_Private_Impl::~PPB_TCPSocket_Private_Impl() {
+ Disconnect();
+}
+
+PP_Resource PPB_TCPSocket_Private_Impl::CreateResource(PP_Instance instance) {
+ PluginDelegate* plugin_delegate = GetPluginDelegate(instance);
+ if (!plugin_delegate)
+ return 0;
+
+ uint32 socket_id = plugin_delegate->TCPSocketCreate();
+ if (!socket_id)
+ return 0;
+
+ return (new PPB_TCPSocket_Private_Impl(instance, socket_id))->GetReference();
+}
+
+PP_Resource PPB_TCPSocket_Private_Impl::CreateConnectedSocket(
+ PP_Instance instance,
+ uint32 socket_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) {
+ PluginDelegate* plugin_delegate = GetPluginDelegate(instance);
+ if (!plugin_delegate)
+ return 0;
+
+ PPB_TCPSocket_Private_Impl* socket =
+ new PPB_TCPSocket_Private_Impl(instance, socket_id);
+
+ socket->connection_state_ = PPB_TCPSocket_Private_Impl::CONNECTED;
+ socket->local_addr_ = local_addr;
+ socket->remote_addr_ = remote_addr;
+
+ plugin_delegate->RegisterTCPSocket(socket, socket_id);
+
+ return socket->GetReference();
+}
+
+void PPB_TCPSocket_Private_Impl::SendConnect(const std::string& host,
+ uint16_t port) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketConnect(this, socket_id_, host, port);
+}
+
+void PPB_TCPSocket_Private_Impl::SendConnectWithNetAddress(
+ const PP_NetAddress_Private& addr) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketConnectWithNetAddress(this, socket_id_, addr);
+}
+
+void PPB_TCPSocket_Private_Impl::SendSSLHandshake(
+ const std::string& server_name,
+ uint16_t server_port,
+ const std::vector<std::vector<char> >& trusted_certs,
+ const std::vector<std::vector<char> >& untrusted_certs) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketSSLHandshake(socket_id_, server_name, server_port,
+ trusted_certs, untrusted_certs);
+}
+
+void PPB_TCPSocket_Private_Impl::SendRead(int32_t bytes_to_read) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketRead(socket_id_, bytes_to_read);
+}
+
+
+void PPB_TCPSocket_Private_Impl::SendWrite(const std::string& buffer) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketWrite(socket_id_, buffer);
+}
+
+void PPB_TCPSocket_Private_Impl::SendDisconnect() {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketDisconnect(socket_id_);
+}
+
+void PPB_TCPSocket_Private_Impl::SendSetOption(
+ PP_TCPSocket_Option name,
+ const ::ppapi::SocketOptionData& value) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return;
+
+ plugin_delegate->TCPSocketSetOption(socket_id_, name, value);
+}
+
+PluginDelegate* PPB_TCPSocket_Private_Impl::GetPluginDelegate(
+ PP_Instance instance) {
+ PluginInstanceImpl* plugin_instance =
+ HostGlobals::Get()->GetInstance(instance);
+ if (!plugin_instance)
+ return NULL;
+ return plugin_instance->delegate();
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_tcp_socket_private_impl.h b/content/renderer/pepper/ppb_tcp_socket_private_impl.h
new file mode 100644
index 0000000..7295094
--- /dev/null
+++ b/content/renderer/pepper/ppb_tcp_socket_private_impl.h
@@ -0,0 +1,53 @@
+// 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_PPB_TCP_SOCKET_PRIVATE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_TCP_SOCKET_PRIVATE_IMPL_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "ppapi/shared_impl/private/tcp_socket_private_impl.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PluginDelegate;
+
+class PPB_TCPSocket_Private_Impl : public ::ppapi::TCPSocketPrivateImpl {
+ public:
+ static PP_Resource CreateResource(PP_Instance instance);
+ static PP_Resource CreateConnectedSocket(
+ PP_Instance instance,
+ uint32 socket_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr);
+
+ virtual void SendConnect(const std::string& host, uint16_t port) OVERRIDE;
+ virtual void SendConnectWithNetAddress(
+ const PP_NetAddress_Private& addr) OVERRIDE;
+ virtual void SendSSLHandshake(
+ const std::string& server_name,
+ uint16_t server_port,
+ const std::vector<std::vector<char> >& trusted_certs,
+ const std::vector<std::vector<char> >& untrusted_certs) OVERRIDE;
+ virtual void SendRead(int32_t bytes_to_read) OVERRIDE;
+ virtual void SendWrite(const std::string& buffer) OVERRIDE;
+ virtual void SendDisconnect() OVERRIDE;
+ virtual void SendSetOption(PP_TCPSocket_Option name,
+ const ::ppapi::SocketOptionData& value) OVERRIDE;
+
+ private:
+ PPB_TCPSocket_Private_Impl(PP_Instance instance, uint32 socket_id);
+ virtual ~PPB_TCPSocket_Private_Impl();
+
+ static PluginDelegate* GetPluginDelegate(PP_Instance instance);
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_TCPSocket_Private_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_TCP_SOCKET_PRIVATE_IMPL_H_
diff --git a/content/renderer/pepper/ppb_uma_private_impl.cc b/content/renderer/pepper/ppb_uma_private_impl.cc
new file mode 100644
index 0000000..8468dd7
--- /dev/null
+++ b/content/renderer/pepper/ppb_uma_private_impl.cc
@@ -0,0 +1,100 @@
+// 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/pepper/ppb_uma_private_impl.h"
+
+#include "base/metrics/histogram.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/private/ppb_uma_private.h"
+#include "ppapi/shared_impl/var.h"
+#include "webkit/glue/webkit_glue.h"
+
+using ppapi::StringVar;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+#define RETURN_IF_BAD_ARGS(_name, _sample, _min, _max, _bucket_count) \
+ do { \
+ if (_name.type != PP_VARTYPE_STRING || _name.value.as_id == 0) \
+ return; \
+ if (_min >= _max) \
+ return; \
+ if (_bucket_count <= 1) \
+ return; \
+ } while (0)
+
+void HistogramCustomTimes(PP_Var name,
+ int64_t sample,
+ int64_t min, int64_t max,
+ uint32_t bucket_count) {
+ RETURN_IF_BAD_ARGS(name, sample, min, max, bucket_count);
+
+ StringVar* name_string = StringVar::FromPPVar(name);
+ if (name_string == NULL)
+ return;
+ base::HistogramBase* counter =
+ base::Histogram::FactoryTimeGet(
+ name_string->value(),
+ base::TimeDelta::FromMilliseconds(min),
+ base::TimeDelta::FromMilliseconds(max),
+ bucket_count,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ counter->AddTime(base::TimeDelta::FromMilliseconds(sample));
+}
+
+void HistogramCustomCounts(PP_Var name,
+ int32_t sample,
+ int32_t min, int32_t max,
+ uint32_t bucket_count) {
+ RETURN_IF_BAD_ARGS(name, sample, min, max, bucket_count);
+
+ StringVar* name_string = StringVar::FromPPVar(name);
+ if (name_string == NULL)
+ return;
+ base::HistogramBase* counter =
+ base::Histogram::FactoryGet(
+ name_string->value(),
+ min,
+ max,
+ bucket_count,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ counter->Add(sample);
+}
+
+void HistogramEnumeration(PP_Var name,
+ int32_t sample,
+ int32_t boundary_value) {
+ RETURN_IF_BAD_ARGS(name, sample, 1, boundary_value, boundary_value + 1);
+
+ StringVar* name_string = StringVar::FromPPVar(name);
+ if (name_string == NULL)
+ return;
+ base::HistogramBase* counter =
+ base::LinearHistogram::FactoryGet(
+ name_string->value(),
+ 1,
+ boundary_value,
+ boundary_value + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ counter->Add(sample);
+}
+
+} // namespace
+
+const PPB_UMA_Private ppb_uma = {
+ &HistogramCustomTimes,
+ &HistogramCustomCounts,
+ &HistogramEnumeration,
+};
+
+// static
+const PPB_UMA_Private* PPB_UMA_Private_Impl::GetInterface() {
+ return &ppb_uma;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_uma_private_impl.h b/content/renderer/pepper/ppb_uma_private_impl.h
new file mode 100644
index 0000000..55a94f4
--- /dev/null
+++ b/content/renderer/pepper/ppb_uma_private_impl.h
@@ -0,0 +1,21 @@
+// 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_PEPPER_PPB_UMA_PRIVATE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_UMA_PRIVATE_IMPL_H_
+
+#include "ppapi/c/private/ppb_uma_private.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_UMA_Private_Impl {
+ public:
+ static const PPB_UMA_Private* GetInterface();
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_UMA_PRIVATE_IMPL_H_
diff --git a/content/renderer/pepper/ppb_var_deprecated_impl.cc b/content/renderer/pepper/ppb_var_deprecated_impl.cc
new file mode 100644
index 0000000..cbfc6f9
--- /dev/null
+++ b/content/renderer/pepper/ppb_var_deprecated_impl.cc
@@ -0,0 +1,437 @@
+// 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/ppb_var_deprecated_impl.h"
+
+#include <limits>
+
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/npapi_glue.h"
+#include "content/renderer/pepper/npobject_var.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/plugin_object.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/c/dev/ppb_var_deprecated.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/shared_impl/ppb_var_shared.h"
+#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+
+using ppapi::NPObjectVar;
+using ppapi::PpapiGlobals;
+using ppapi::StringVar;
+using ppapi::Var;
+using WebKit::WebBindings;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+const char kInvalidObjectException[] = "Error: Invalid object";
+const char kInvalidPropertyException[] = "Error: Invalid property";
+const char kInvalidValueException[] = "Error: Invalid value";
+const char kUnableToGetPropertyException[] = "Error: Unable to get property";
+const char kUnableToSetPropertyException[] = "Error: Unable to set property";
+const char kUnableToRemovePropertyException[] =
+ "Error: Unable to remove property";
+const char kUnableToGetAllPropertiesException[] =
+ "Error: Unable to get all properties";
+const char kUnableToCallMethodException[] = "Error: Unable to call method";
+const char kUnableToConstructException[] = "Error: Unable to construct";
+
+// ---------------------------------------------------------------------------
+// Utilities
+
+// Converts the given PP_Var to an NPVariant, returning true on success.
+// False means that the given variant is invalid. In this case, the result
+// NPVariant will be set to a void one.
+//
+// The contents of the PP_Var will NOT be copied, so you need to ensure that
+// the PP_Var remains valid while the resultant NPVariant is in use.
+bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
+ switch (var.type) {
+ case PP_VARTYPE_UNDEFINED:
+ VOID_TO_NPVARIANT(*result);
+ break;
+ case PP_VARTYPE_NULL:
+ NULL_TO_NPVARIANT(*result);
+ break;
+ case PP_VARTYPE_BOOL:
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
+ break;
+ case PP_VARTYPE_INT32:
+ INT32_TO_NPVARIANT(var.value.as_int, *result);
+ break;
+ case PP_VARTYPE_DOUBLE:
+ DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
+ break;
+ case PP_VARTYPE_STRING: {
+ StringVar* string = StringVar::FromPPVar(var);
+ if (!string) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ const std::string& value = string->value();
+ STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
+ break;
+ }
+ case PP_VARTYPE_OBJECT: {
+ scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
+ if (!object.get()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ OBJECT_TO_NPVARIANT(object->np_object(), *result);
+ break;
+ }
+ default:
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ return true;
+}
+
+// ObjectAccessorTryCatch ------------------------------------------------------
+
+// Automatically sets up a TryCatch for accessing the object identified by the
+// given PP_Var. The module from the object will be used for the exception
+// strings generated by the TryCatch.
+//
+// This will automatically retrieve the ObjectVar from the object and throw
+// an exception if it's invalid. At the end of construction, if there is no
+// exception, you know that there is no previously set exception, that the
+// object passed in is valid and ready to use (via the object() getter), and
+// that the TryCatch's pp_module() getter is also set up properly and ready to
+// use.
+class ObjectAccessorTryCatch : public TryCatch {
+ public:
+ ObjectAccessorTryCatch(PP_Var object, PP_Var* exception)
+ : TryCatch(exception),
+ object_(NPObjectVar::FromPPVar(object)) {
+ if (!object_.get()) {
+ SetException(kInvalidObjectException);
+ }
+ }
+
+ NPObjectVar* object() { return object_.get(); }
+
+ PluginInstanceImpl* GetPluginInstance() {
+ return HostGlobals::Get()->GetInstance(object()->pp_instance());
+ }
+
+ protected:
+ scoped_refptr<NPObjectVar> object_;
+
+ DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
+};
+
+// ObjectAccessiorWithIdentifierTryCatch ---------------------------------------
+
+// Automatically sets up a TryCatch for accessing the identifier on the given
+// object. This just extends ObjectAccessorTryCatch to additionally convert
+// the given identifier to an NPIdentifier and validate it, throwing an
+// exception if it's invalid.
+//
+// At the end of construction, if there is no exception, you know that there is
+// no previously set exception, that the object passed in is valid and ready to
+// use (via the object() getter), that the identifier is valid and ready to
+// use (via the identifier() getter), and that the TryCatch's pp_module() getter
+// is also set up properly and ready to use.
+class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch {
+ public:
+ ObjectAccessorWithIdentifierTryCatch(PP_Var object,
+ PP_Var identifier,
+ PP_Var* exception)
+ : ObjectAccessorTryCatch(object, exception),
+ identifier_(0) {
+ if (!has_exception()) {
+ identifier_ = PPVarToNPIdentifier(identifier);
+ if (!identifier_)
+ SetException(kInvalidPropertyException);
+ }
+ }
+
+ NPIdentifier identifier() const { return identifier_; }
+
+ private:
+ NPIdentifier identifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
+};
+
+PP_Bool HasProperty(PP_Var var,
+ PP_Var name,
+ PP_Var* exception) {
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
+ return PP_FALSE;
+ return BoolToPPBool(WebBindings::hasProperty(NULL,
+ accessor.object()->np_object(),
+ accessor.identifier()));
+}
+
+bool HasPropertyDeprecated(PP_Var var,
+ PP_Var name,
+ PP_Var* exception) {
+ return PPBoolToBool(HasProperty(var, name, exception));
+}
+
+bool HasMethodDeprecated(PP_Var var,
+ PP_Var name,
+ PP_Var* exception) {
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
+ return false;
+ return WebBindings::hasMethod(NULL, accessor.object()->np_object(),
+ accessor.identifier());
+}
+
+PP_Var GetProperty(PP_Var var,
+ PP_Var name,
+ PP_Var* exception) {
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
+ return PP_MakeUndefined();
+
+ NPVariant result;
+ if (!WebBindings::getProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier(), &result)) {
+ // An exception may have been raised.
+ accessor.SetException(kUnableToGetPropertyException);
+ return PP_MakeUndefined();
+ }
+
+ PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
+ WebBindings::releaseVariantValue(&result);
+ return ret;
+}
+
+void EnumerateProperties(PP_Var var,
+ uint32_t* property_count,
+ PP_Var** properties,
+ PP_Var* exception) {
+ *properties = NULL;
+ *property_count = 0;
+
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
+ return;
+
+ NPIdentifier* identifiers = NULL;
+ uint32_t count = 0;
+ if (!WebBindings::enumerate(NULL, accessor.object()->np_object(),
+ &identifiers, &count)) {
+ accessor.SetException(kUnableToGetAllPropertiesException);
+ return;
+ }
+
+ if (count == 0)
+ return;
+
+ *property_count = count;
+ *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
+ for (uint32_t i = 0; i < count; ++i) {
+ (*properties)[i] = NPIdentifierToPPVar(identifiers[i]);
+ }
+ free(identifiers);
+}
+
+void SetPropertyDeprecated(PP_Var var,
+ PP_Var name,
+ PP_Var value,
+ PP_Var* exception) {
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
+ return;
+
+ NPVariant variant;
+ if (!PPVarToNPVariantNoCopy(value, &variant)) {
+ accessor.SetException(kInvalidValueException);
+ return;
+ }
+ if (!WebBindings::setProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier(), &variant))
+ accessor.SetException(kUnableToSetPropertyException);
+}
+
+void DeletePropertyDeprecated(PP_Var var,
+ PP_Var name,
+ PP_Var* exception) {
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
+ return;
+
+ if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier()))
+ accessor.SetException(kUnableToRemovePropertyException);
+}
+
+PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor,
+ PP_Var method_name,
+ uint32_t argc,
+ PP_Var* argv,
+ PP_Var* exception) {
+ NPIdentifier identifier;
+ if (method_name.type == PP_VARTYPE_UNDEFINED) {
+ identifier = NULL;
+ } else if (method_name.type == PP_VARTYPE_STRING) {
+ // Specifically allow only string functions to be called.
+ identifier = PPVarToNPIdentifier(method_name);
+ if (!identifier) {
+ accessor->SetException(kInvalidPropertyException);
+ return PP_MakeUndefined();
+ }
+ } else {
+ accessor->SetException(kInvalidPropertyException);
+ return PP_MakeUndefined();
+ }
+
+ scoped_ptr<NPVariant[]> args;
+ if (argc) {
+ args.reset(new NPVariant[argc]);
+ for (uint32_t i = 0; i < argc; ++i) {
+ if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
+ // This argument was invalid, throw an exception & give up.
+ accessor->SetException(kInvalidValueException);
+ return PP_MakeUndefined();
+ }
+ }
+ }
+
+ bool ok;
+
+ NPVariant result;
+ if (identifier) {
+ ok = WebBindings::invoke(NULL, accessor->object()->np_object(),
+ identifier, args.get(), argc, &result);
+ } else {
+ ok = WebBindings::invokeDefault(NULL, accessor->object()->np_object(),
+ args.get(), argc, &result);
+ }
+
+ if (!ok) {
+ // An exception may have been raised.
+ accessor->SetException(kUnableToCallMethodException);
+ return PP_MakeUndefined();
+ }
+
+ PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result);
+ WebBindings::releaseVariantValue(&result);
+ return ret;
+}
+
+PP_Var CallDeprecated(PP_Var var,
+ PP_Var method_name,
+ uint32_t argc,
+ PP_Var* argv,
+ PP_Var* exception) {
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
+ return PP_MakeUndefined();
+ PluginInstanceImpl* plugin = accessor.GetPluginInstance();
+ if (plugin && plugin->IsProcessingUserGesture()) {
+ WebKit::WebScopedUserGesture user_gesture(
+ plugin->CurrentUserGestureToken());
+ return InternalCallDeprecated(&accessor, method_name, argc, argv,
+ exception);
+ }
+ return InternalCallDeprecated(&accessor, method_name, argc, argv, exception);
+}
+
+PP_Var Construct(PP_Var var,
+ uint32_t argc,
+ PP_Var* argv,
+ PP_Var* exception) {
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
+ return PP_MakeUndefined();
+
+ scoped_ptr<NPVariant[]> args;
+ if (argc) {
+ args.reset(new NPVariant[argc]);
+ for (uint32_t i = 0; i < argc; ++i) {
+ if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
+ // This argument was invalid, throw an exception & give up.
+ accessor.SetException(kInvalidValueException);
+ return PP_MakeUndefined();
+ }
+ }
+ }
+
+ NPVariant result;
+ if (!WebBindings::construct(NULL, accessor.object()->np_object(),
+ args.get(), argc, &result)) {
+ // An exception may have been raised.
+ accessor.SetException(kUnableToConstructException);
+ return PP_MakeUndefined();
+ }
+
+ PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
+ WebBindings::releaseVariantValue(&result);
+ return ret;
+}
+
+bool IsInstanceOfDeprecated(PP_Var var,
+ const PPP_Class_Deprecated* ppp_class,
+ void** ppp_class_data) {
+ scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
+ if (!object.get())
+ return false; // Not an object at all.
+
+ return PluginObject::IsInstanceOf(object->np_object(),
+ ppp_class, ppp_class_data);
+}
+
+PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
+ const PPP_Class_Deprecated* ppp_class,
+ void* ppp_class_data) {
+ PluginInstanceImpl* instance = HostGlobals::Get()->GetInstance(pp_instance);
+ if (!instance) {
+ DLOG(ERROR) << "Create object passed an invalid instance.";
+ return PP_MakeNull();
+ }
+ return PluginObject::Create(instance, ppp_class, ppp_class_data);
+}
+
+PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
+ const PPP_Class_Deprecated* ppp_class,
+ void* ppp_class_data) {
+ PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
+ if (!module)
+ return PP_MakeNull();
+ return PluginObject::Create(module->GetSomeInstance(),
+ ppp_class, ppp_class_data);
+}
+
+} // namespace
+
+// static
+const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
+ static const PPB_Var_Deprecated var_deprecated_interface = {
+ ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
+ ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
+ ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
+ ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
+ &HasPropertyDeprecated,
+ &HasMethodDeprecated,
+ &GetProperty,
+ &EnumerateProperties,
+ &SetPropertyDeprecated,
+ &DeletePropertyDeprecated,
+ &CallDeprecated,
+ &Construct,
+ &IsInstanceOfDeprecated,
+ &CreateObjectDeprecated,
+ &CreateObjectWithModuleDeprecated,
+ };
+
+ return &var_deprecated_interface;
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/content/renderer/pepper/ppb_var_deprecated_impl.h b/content/renderer/pepper/ppb_var_deprecated_impl.h
new file mode 100644
index 0000000..459acfa
--- /dev/null
+++ b/content/renderer/pepper/ppb_var_deprecated_impl.h
@@ -0,0 +1,21 @@
+// 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_PEPPER_PPB_VAR_DEPRECATED_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_VAR_DEPRECATED_IMPL_H_
+
+struct PPB_Var_Deprecated;
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Var_Deprecated_Impl {
+ public:
+ static const PPB_Var_Deprecated* GetVarDeprecatedInterface();
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_VAR_DEPRECATED_IMPL_H_
diff --git a/content/renderer/pepper/ppb_video_decoder_impl.cc b/content/renderer/pepper/ppb_video_decoder_impl.cc
new file mode 100644
index 0000000..c71f618
--- /dev/null
+++ b/content/renderer/pepper/ppb_video_decoder_impl.cc
@@ -0,0 +1,303 @@
+// 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/ppb_video_decoder_impl.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppb_buffer_impl.h"
+#include "content/renderer/pepper/ppb_graphics_3d_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "media/video/picture.h"
+#include "media/video/video_decode_accelerator.h"
+#include "ppapi/c/dev/pp_video_dev.h"
+#include "ppapi/c/dev/ppb_video_decoder_dev.h"
+#include "ppapi/c/dev/ppp_video_decoder_dev.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/thunk/enter.h"
+
+using ppapi::TrackedCallback;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Buffer_API;
+using ppapi::thunk::PPB_Graphics3D_API;
+using ppapi::thunk::PPB_VideoDecoder_API;
+
+namespace {
+
+// Convert PP_VideoDecoder_Profile to media::VideoCodecProfile.
+media::VideoCodecProfile PPToMediaProfile(
+ const PP_VideoDecoder_Profile pp_profile) {
+ switch (pp_profile) {
+ case PP_VIDEODECODER_H264PROFILE_NONE:
+ // HACK: PPAPI contains a bogus "none" h264 profile that doesn't
+ // correspond to anything in h.264; but a number of released chromium
+ // versions silently promoted this to Baseline profile, so we retain that
+ // behavior here. Fall through.
+ case PP_VIDEODECODER_H264PROFILE_BASELINE:
+ return media::H264PROFILE_BASELINE;
+ case PP_VIDEODECODER_H264PROFILE_MAIN:
+ return media::H264PROFILE_MAIN;
+ case PP_VIDEODECODER_H264PROFILE_EXTENDED:
+ return media::H264PROFILE_EXTENDED;
+ case PP_VIDEODECODER_H264PROFILE_HIGH:
+ return media::H264PROFILE_HIGH;
+ case PP_VIDEODECODER_H264PROFILE_HIGH10PROFILE:
+ return media::H264PROFILE_HIGH10PROFILE;
+ case PP_VIDEODECODER_H264PROFILE_HIGH422PROFILE:
+ return media::H264PROFILE_HIGH422PROFILE;
+ case PP_VIDEODECODER_H264PROFILE_HIGH444PREDICTIVEPROFILE:
+ return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
+ case PP_VIDEODECODER_H264PROFILE_SCALABLEBASELINE:
+ return media::H264PROFILE_SCALABLEBASELINE;
+ case PP_VIDEODECODER_H264PROFILE_SCALABLEHIGH:
+ return media::H264PROFILE_SCALABLEHIGH;
+ case PP_VIDEODECODER_H264PROFILE_STEREOHIGH:
+ return media::H264PROFILE_STEREOHIGH;
+ case PP_VIDEODECODER_H264PROFILE_MULTIVIEWHIGH:
+ return media::H264PROFILE_MULTIVIEWHIGH;
+ case PP_VIDEODECODER_VP8PROFILE_MAIN:
+ return media::VP8PROFILE_MAIN;
+ default:
+ return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+ }
+}
+
+PP_VideoDecodeError_Dev MediaToPPError(
+ media::VideoDecodeAccelerator::Error error) {
+ switch (error) {
+ case media::VideoDecodeAccelerator::ILLEGAL_STATE :
+ return PP_VIDEODECODERERROR_ILLEGAL_STATE;
+ case media::VideoDecodeAccelerator::INVALID_ARGUMENT :
+ return PP_VIDEODECODERERROR_INVALID_ARGUMENT;
+ case media::VideoDecodeAccelerator::UNREADABLE_INPUT :
+ return PP_VIDEODECODERERROR_UNREADABLE_INPUT;
+ case media::VideoDecodeAccelerator::PLATFORM_FAILURE :
+ return PP_VIDEODECODERERROR_PLATFORM_FAILURE;
+ default:
+ NOTREACHED();
+ return PP_VIDEODECODERERROR_ILLEGAL_STATE;
+ }
+}
+
+} // namespace
+
+namespace webkit {
+namespace ppapi {
+
+PPB_VideoDecoder_Impl::PPB_VideoDecoder_Impl(PP_Instance instance)
+ : PPB_VideoDecoder_Shared(instance),
+ ppp_videodecoder_(NULL) {
+ PluginModule* plugin_module = ResourceHelper::GetPluginModule(this);
+ 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();
+}
+
+// static
+PP_Resource PPB_VideoDecoder_Impl::Create(
+ PP_Instance instance,
+ PP_Resource graphics_context,
+ PP_VideoDecoder_Profile profile) {
+ EnterResourceNoLock<PPB_Graphics3D_API> enter_context(graphics_context, true);
+ if (enter_context.failed())
+ return 0;
+ PPB_Graphics3D_Impl* graphics3d_impl =
+ static_cast<PPB_Graphics3D_Impl*>(enter_context.object());
+
+ scoped_refptr<PPB_VideoDecoder_Impl> decoder(
+ new PPB_VideoDecoder_Impl(instance));
+ if (decoder->Init(graphics_context, graphics3d_impl->platform_context(),
+ graphics3d_impl->gles2_impl(), profile))
+ return decoder->GetReference();
+ return 0;
+}
+
+bool PPB_VideoDecoder_Impl::Init(
+ PP_Resource graphics_context,
+ PluginDelegate::PlatformContext3D* context,
+ gpu::gles2::GLES2Implementation* gles2_impl,
+ PP_VideoDecoder_Profile profile) {
+ InitCommon(graphics_context, gles2_impl);
+
+ int command_buffer_route_id = context->GetCommandBufferRouteId();
+ if (command_buffer_route_id == 0)
+ return false;
+
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return false;
+
+ platform_video_decoder_.reset(plugin_delegate->CreateVideoDecoder(
+ this, command_buffer_route_id));
+ if (!platform_video_decoder_)
+ return false;
+
+ FlushCommandBuffer();
+ return platform_video_decoder_->Initialize(PPToMediaProfile(profile));
+}
+
+int32_t PPB_VideoDecoder_Impl::Decode(
+ const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
+ scoped_refptr<TrackedCallback> callback) {
+ if (!platform_video_decoder_)
+ return PP_ERROR_BADRESOURCE;
+
+ EnterResourceNoLock<PPB_Buffer_API> enter(bitstream_buffer->data, true);
+ if (enter.failed())
+ return PP_ERROR_FAILED;
+
+ PPB_Buffer_Impl* buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
+ DCHECK_GE(bitstream_buffer->id, 0);
+ media::BitstreamBuffer decode_buffer(
+ bitstream_buffer->id,
+ buffer->shared_memory()->handle(),
+ bitstream_buffer->size);
+ if (!SetBitstreamBufferCallback(bitstream_buffer->id, callback))
+ return PP_ERROR_BADARGUMENT;
+
+ FlushCommandBuffer();
+ platform_video_decoder_->Decode(decode_buffer);
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PPB_VideoDecoder_Impl::AssignPictureBuffers(
+ uint32_t no_of_buffers,
+ const PP_PictureBuffer_Dev* buffers) {
+ if (!platform_video_decoder_)
+ return;
+ UMA_HISTOGRAM_COUNTS_100("Media.PepperVideoDecoderPictureCount",
+ no_of_buffers);
+
+ std::vector<media::PictureBuffer> wrapped_buffers;
+ for (uint32 i = 0; i < no_of_buffers; i++) {
+ PP_PictureBuffer_Dev in_buf = buffers[i];
+ DCHECK_GE(in_buf.id, 0);
+ media::PictureBuffer buffer(
+ in_buf.id,
+ gfx::Size(in_buf.size.width, in_buf.size.height),
+ in_buf.texture_id);
+ wrapped_buffers.push_back(buffer);
+ UMA_HISTOGRAM_COUNTS_10000("Media.PepperVideoDecoderPictureHeight",
+ in_buf.size.height);
+ }
+
+ FlushCommandBuffer();
+ platform_video_decoder_->AssignPictureBuffers(wrapped_buffers);
+}
+
+void PPB_VideoDecoder_Impl::ReusePictureBuffer(int32_t picture_buffer_id) {
+ if (!platform_video_decoder_)
+ return;
+
+ FlushCommandBuffer();
+ platform_video_decoder_->ReusePictureBuffer(picture_buffer_id);
+}
+
+int32_t PPB_VideoDecoder_Impl::Flush(scoped_refptr<TrackedCallback> callback) {
+ if (!platform_video_decoder_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (!SetFlushCallback(callback))
+ return PP_ERROR_INPROGRESS;
+
+ FlushCommandBuffer();
+ platform_video_decoder_->Flush();
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PPB_VideoDecoder_Impl::Reset(scoped_refptr<TrackedCallback> callback) {
+ if (!platform_video_decoder_)
+ return PP_ERROR_BADRESOURCE;
+
+ if (!SetResetCallback(callback))
+ return PP_ERROR_INPROGRESS;
+
+ FlushCommandBuffer();
+ platform_video_decoder_->Reset();
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PPB_VideoDecoder_Impl::Destroy() {
+ FlushCommandBuffer();
+
+ if (platform_video_decoder_)
+ platform_video_decoder_.release()->Destroy();
+ ppp_videodecoder_ = NULL;
+
+ ::ppapi::PPB_VideoDecoder_Shared::Destroy();
+}
+
+void PPB_VideoDecoder_Impl::ProvidePictureBuffers(
+ uint32 requested_num_of_buffers,
+ const gfx::Size& dimensions,
+ uint32 texture_target) {
+ if (!ppp_videodecoder_)
+ 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);
+}
+
+void PPB_VideoDecoder_Impl::PictureReady(const media::Picture& picture) {
+ if (!ppp_videodecoder_)
+ 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);
+}
+
+void PPB_VideoDecoder_Impl::DismissPictureBuffer(int32 picture_buffer_id) {
+ if (!ppp_videodecoder_)
+ return;
+ ppp_videodecoder_->DismissPictureBuffer(pp_instance(), pp_resource(),
+ picture_buffer_id);
+}
+
+void PPB_VideoDecoder_Impl::NotifyError(
+ media::VideoDecodeAccelerator::Error error) {
+ if (!ppp_videodecoder_)
+ return;
+
+ PP_VideoDecodeError_Dev pp_error = MediaToPPError(error);
+ ppp_videodecoder_->NotifyError(pp_instance(), pp_resource(), pp_error);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.PepperVideoDecoderError", error,
+ media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM);
+}
+
+void PPB_VideoDecoder_Impl::NotifyResetDone() {
+ RunResetCallback(PP_OK);
+}
+
+void PPB_VideoDecoder_Impl::NotifyEndOfBitstreamBuffer(
+ int32 bitstream_buffer_id) {
+ RunBitstreamBufferCallback(bitstream_buffer_id, PP_OK);
+}
+
+void PPB_VideoDecoder_Impl::NotifyFlushDone() {
+ RunFlushCallback(PP_OK);
+}
+
+void PPB_VideoDecoder_Impl::NotifyInitializeDone() {
+ NOTREACHED() << "PlatformVideoDecoder::Initialize() is synchronous!";
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_video_decoder_impl.h b/content/renderer/pepper/ppb_video_decoder_impl.h
new file mode 100644
index 0000000..d2d07b8
--- /dev/null
+++ b/content/renderer/pepper/ppb_video_decoder_impl.h
@@ -0,0 +1,88 @@
+// 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_PPB_VIDEO_DECODER_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_VIDEO_DECODER_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "ppapi/c/dev/pp_video_dev.h"
+#include "ppapi/c/dev/ppp_video_decoder_dev.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/shared_impl/ppb_video_decoder_shared.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_video_decoder_api.h"
+
+struct PP_PictureBuffer_Dev;
+struct PP_VideoBitstreamBuffer_Dev;
+
+namespace gpu {
+namespace gles2 {
+class GLES2Implementation;
+} // namespace gles2
+} // namespace gpu
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_VideoDecoder_Impl : public ::ppapi::PPB_VideoDecoder_Shared,
+ public media::VideoDecodeAccelerator::Client {
+ public:
+ // See PPB_VideoDecoder_Dev::Create. Returns 0 on failure to create &
+ // initialize.
+ static PP_Resource Create(PP_Instance instance,
+ PP_Resource graphics_context,
+ PP_VideoDecoder_Profile profile);
+
+ // PPB_VideoDecoder_API implementation.
+ virtual int32_t Decode(
+ const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual void AssignPictureBuffers(
+ uint32_t no_of_buffers, const PP_PictureBuffer_Dev* buffers) OVERRIDE;
+ virtual void ReusePictureBuffer(int32_t picture_buffer_id) OVERRIDE;
+ virtual int32_t Flush(
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Reset(
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
+ virtual void Destroy() OVERRIDE;
+
+ // media::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 NotifyInitializeDone() OVERRIDE;
+ virtual void NotifyError(
+ media::VideoDecodeAccelerator::Error error) OVERRIDE;
+ virtual void NotifyFlushDone() OVERRIDE;
+ virtual void NotifyEndOfBitstreamBuffer(int32 buffer_id) OVERRIDE;
+ virtual void NotifyResetDone() OVERRIDE;
+
+ private:
+ virtual ~PPB_VideoDecoder_Impl();
+
+ explicit PPB_VideoDecoder_Impl(PP_Instance instance);
+ bool Init(PP_Resource graphics_context,
+ PluginDelegate::PlatformContext3D* context,
+ gpu::gles2::GLES2Implementation* gles2_impl,
+ PP_VideoDecoder_Profile profile);
+
+ // This is NULL before initialization, and if this PPB_VideoDecoder_Impl is
+ // swapped with another.
+ scoped_ptr<PluginDelegate::PlatformVideoDecoder> platform_video_decoder_;
+
+ // Reference to the plugin requesting this interface.
+ const PPP_VideoDecoder_Dev* ppp_videodecoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_VideoDecoder_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_VIDEO_DECODER_IMPL_H_
diff --git a/content/renderer/pepper/ppb_widget_impl.cc b/content/renderer/pepper/ppb_widget_impl.cc
new file mode 100644
index 0000000..5854f01
--- /dev/null
+++ b/content/renderer/pepper/ppb_widget_impl.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/ppb_widget_impl.h"
+
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/c/dev/ppp_widget_dev.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_input_event_api.h"
+#include "ppapi/thunk/ppb_widget_api.h"
+
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_ImageData_API;
+using ppapi::thunk::PPB_InputEvent_API;
+using ppapi::thunk::PPB_Widget_API;
+
+namespace webkit {
+namespace ppapi {
+
+PPB_Widget_Impl::PPB_Widget_Impl(PP_Instance instance)
+ : Resource(::ppapi::OBJECT_IS_IMPL, instance),
+ scale_(1.0f) {
+ memset(&location_, 0, sizeof(location_));
+}
+
+PPB_Widget_Impl::~PPB_Widget_Impl() {
+}
+
+PPB_Widget_API* PPB_Widget_Impl::AsPPB_Widget_API() {
+ return this;
+}
+
+PP_Bool PPB_Widget_Impl::Paint(const PP_Rect* rect, PP_Resource image_id) {
+ EnterResourceNoLock<PPB_ImageData_API> enter(image_id, true);
+ if (enter.failed())
+ return PP_FALSE;
+ return PaintInternal(gfx::Rect(rect->point.x, rect->point.y,
+ rect->size.width, rect->size.height),
+ static_cast<PPB_ImageData_Impl*>(enter.object()));
+}
+
+PP_Bool PPB_Widget_Impl::HandleEvent(PP_Resource pp_input_event) {
+ EnterResourceNoLock<PPB_InputEvent_API> enter(pp_input_event, true);
+ if (enter.failed())
+ return PP_FALSE;
+ return HandleEventInternal(enter.object()->GetInputEventData());
+}
+
+PP_Bool PPB_Widget_Impl::GetLocation(PP_Rect* location) {
+ *location = location_;
+ return PP_TRUE;
+}
+
+void PPB_Widget_Impl::SetLocation(const PP_Rect* location) {
+ location_ = *location;
+ SetLocationInternal(location);
+}
+
+void PPB_Widget_Impl::SetScale(float scale) {
+ scale_ = scale;
+}
+
+void PPB_Widget_Impl::Invalidate(const PP_Rect* dirty) {
+ PluginInstanceImpl* plugin_instance = ResourceHelper::GetPluginInstance(this);
+ if (!plugin_instance)
+ return;
+ const PPP_Widget_Dev* widget = static_cast<const PPP_Widget_Dev*>(
+ plugin_instance->module()->GetPluginInterface(PPP_WIDGET_DEV_INTERFACE));
+ if (!widget)
+ return;
+ widget->Invalidate(pp_instance(), pp_resource(), dirty);
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/content/renderer/pepper/ppb_widget_impl.h b/content/renderer/pepper/ppb_widget_impl.h
new file mode 100644
index 0000000..7b1e950
--- /dev/null
+++ b/content/renderer/pepper/ppb_widget_impl.h
@@ -0,0 +1,65 @@
+// 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_PPB_WIDGET_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_WIDGET_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ppapi/c/pp_rect.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/thunk/ppb_widget_api.h"
+
+namespace gfx {
+class Rect;
+}
+namespace ppapi {
+struct InputEventData;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_ImageData_Impl;
+
+class PPB_Widget_Impl : public ::ppapi::Resource,
+ public ::ppapi::thunk::PPB_Widget_API {
+ public:
+ explicit PPB_Widget_Impl(PP_Instance instance);
+
+ // Resource overrides.
+ virtual ::ppapi::thunk::PPB_Widget_API* AsPPB_Widget_API() OVERRIDE;
+
+ // PPB_WidgetAPI implementation.
+ virtual PP_Bool Paint(const PP_Rect* rect, PP_Resource ) OVERRIDE;
+ virtual PP_Bool HandleEvent(PP_Resource pp_input_event) OVERRIDE;
+ virtual PP_Bool GetLocation(PP_Rect* location) OVERRIDE;
+ virtual void SetLocation(const PP_Rect* location) OVERRIDE;
+ virtual void SetScale(float scale) OVERRIDE;
+
+ // Notifies the plugin instance that the given rect needs to be repainted.
+ void Invalidate(const PP_Rect* dirty);
+
+ protected:
+ virtual ~PPB_Widget_Impl();
+
+ virtual PP_Bool PaintInternal(const gfx::Rect& rect,
+ PPB_ImageData_Impl* image) = 0;
+ virtual PP_Bool HandleEventInternal(const ::ppapi::InputEventData& data) = 0;
+ virtual void SetLocationInternal(const PP_Rect* location) = 0;
+
+ PP_Rect location() const { return location_; }
+ float scale() const { return scale_; }
+
+ private:
+ PP_Rect location_;
+ float scale_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_Widget_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_WIDGET_IMPL_H_
diff --git a/content/renderer/pepper/ppb_x509_certificate_private_impl.cc b/content/renderer/pepper/ppb_x509_certificate_private_impl.cc
new file mode 100644
index 0000000..0b848d2
--- /dev/null
+++ b/content/renderer/pepper/ppb_x509_certificate_private_impl.cc
@@ -0,0 +1,38 @@
+// 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/ppb_x509_certificate_private_impl.h"
+
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/resource_helper.h"
+
+namespace webkit {
+namespace ppapi {
+
+PPB_X509Certificate_Private_Impl::PPB_X509Certificate_Private_Impl(
+ PP_Instance instance) :
+ PPB_X509Certificate_Private_Shared(::ppapi::OBJECT_IS_IMPL, instance) {
+}
+
+// static
+PP_Resource PPB_X509Certificate_Private_Impl::CreateResource(
+ PP_Instance instance) {
+ return (new PPB_X509Certificate_Private_Impl(instance))->GetReference();
+}
+
+bool PPB_X509Certificate_Private_Impl::ParseDER(
+ const std::vector<char>& der,
+ ::ppapi::PPB_X509Certificate_Fields* result) {
+ PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this);
+ if (!plugin_delegate)
+ return false;
+
+ return plugin_delegate->X509CertificateParseDER(der, result);
+}
+
+PPB_X509Certificate_Private_Impl::~PPB_X509Certificate_Private_Impl() {
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/ppb_x509_certificate_private_impl.h b/content/renderer/pepper/ppb_x509_certificate_private_impl.h
new file mode 100644
index 0000000..6b8d856
--- /dev/null
+++ b/content/renderer/pepper/ppb_x509_certificate_private_impl.h
@@ -0,0 +1,37 @@
+// 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_PPB_X509_CERTIFICATE_PRIVATE_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_PPB_X509_CERTIFICATE_PRIVATE_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
+#include "ppapi/shared_impl/resource.h"
+
+namespace ppapi {
+class PPB_X509Certificate_Fields;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_X509Certificate_Private_Impl :
+ public ::ppapi::PPB_X509Certificate_Private_Shared {
+ public:
+ PPB_X509Certificate_Private_Impl(PP_Instance instance);
+ static PP_Resource CreateResource(PP_Instance instance);
+ virtual bool ParseDER(const std::vector<char>& der,
+ ::ppapi::PPB_X509Certificate_Fields* result) OVERRIDE;
+
+ private:
+ virtual ~PPB_X509Certificate_Private_Impl();
+
+ DISALLOW_COPY_AND_ASSIGN(PPB_X509Certificate_Private_Impl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_X509_CERTIFICATE_PRIVATE_IMPL_H_
diff --git a/content/renderer/pepper/ppp_pdf.h b/content/renderer/pepper/ppp_pdf.h
new file mode 100644
index 0000000..6ad67bf
--- /dev/null
+++ b/content/renderer/pepper/ppp_pdf.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_RENDERER_PEPPER_PPP_PDF_H_
+#define CONTENT_RENDERER_PEPPER_PPP_PDF_H_
+
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_point.h"
+#include "ppapi/c/pp_var.h"
+
+#define PPP_PDF_INTERFACE_1 "PPP_Pdf;1"
+#define PPP_PDF_INTERFACE PPP_PDF_INTERFACE_1
+
+typedef enum {
+ // Rotates the page 90 degrees clockwise from its current orientation.
+ PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CW,
+ // Rotates the page 90 degrees counterclockwise from its current orientation.
+ PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CCW
+} PP_PrivatePageTransformType;
+PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_PrivatePageTransformType, 4);
+
+struct PPP_Pdf_1 {
+ // Returns an absolute URL if the position is over a link.
+ PP_Var (*GetLinkAtPosition)(PP_Instance instance,
+ PP_Point point);
+
+ // Requests that the plugin apply the given transform to its view.
+ void (*Transform)(PP_Instance instance, PP_PrivatePageTransformType type);
+};
+
+typedef PPP_Pdf_1 PPP_Pdf;
+
+#endif // CONTENT_RENDERER_PEPPER_PPP_PDF_H_
diff --git a/content/renderer/pepper/quota_file_io.cc b/content/renderer/pepper/quota_file_io.cc
new file mode 100644
index 0000000..64d26a9
--- /dev/null
+++ b/content/renderer/pepper/quota_file_io.cc
@@ -0,0 +1,424 @@
+// 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/quota_file_io.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/stl_util.h"
+#include "base/task_runner_util.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+
+using base::PlatformFile;
+using base::PlatformFileError;
+using quota::StorageType;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+StorageType PPFileSystemTypeToQuotaStorageType(PP_FileSystemType type) {
+ switch (type) {
+ case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
+ return quota::kStorageTypePersistent;
+ case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
+ return quota::kStorageTypeTemporary;
+ default:
+ return quota::kStorageTypeUnknown;
+ }
+ NOTREACHED();
+ return quota::kStorageTypeUnknown;
+}
+
+int WriteAdapter(PlatformFile file, int64 offset,
+ scoped_ptr<char[]> data, int size) {
+ return base::WritePlatformFile(file, offset, data.get(), size);
+}
+
+} // namespace
+
+class QuotaFileIO::PendingOperationBase {
+ public:
+ virtual ~PendingOperationBase() {}
+
+ // Either one of Run() or DidFail() is called (the latter is called when
+ // there was more than one error during quota queries).
+ virtual void Run() = 0;
+ virtual void DidFail(PlatformFileError error) = 0;
+
+ protected:
+ PendingOperationBase(QuotaFileIO* quota_io, bool is_will_operation)
+ : quota_io_(quota_io), is_will_operation_(is_will_operation) {
+ DCHECK(quota_io_);
+ quota_io_->WillUpdate();
+ }
+
+ QuotaFileIO* quota_io_;
+ const bool is_will_operation_;
+};
+
+class QuotaFileIO::WriteOperation : public PendingOperationBase {
+ public:
+ WriteOperation(QuotaFileIO* quota_io,
+ bool is_will_operation,
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ const WriteCallback& callback)
+ : PendingOperationBase(quota_io, is_will_operation),
+ offset_(offset),
+ bytes_to_write_(bytes_to_write),
+ callback_(callback),
+ finished_(false),
+ status_(base::PLATFORM_FILE_OK),
+ bytes_written_(0),
+ weak_factory_(this) {
+ if (!is_will_operation) {
+ // TODO(kinuko): Check the API convention if we really need to keep a copy
+ // of the buffer during the async write operations.
+ buffer_.reset(new char[bytes_to_write]);
+ memcpy(buffer_.get(), buffer, bytes_to_write);
+ }
+ }
+ virtual ~WriteOperation() {}
+ virtual void Run() OVERRIDE {
+ DCHECK(quota_io_);
+ if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
+ DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
+ return;
+ }
+ if (is_will_operation_) {
+ // Assuming the write will succeed.
+ DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
+ return;
+ }
+ DCHECK(buffer_.get());
+
+ PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
+ if (!plugin_delegate) {
+ DidFail(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+
+ if (!base::PostTaskAndReplyWithResult(
+ plugin_delegate->GetFileThreadMessageLoopProxy().get(),
+ FROM_HERE,
+ base::Bind(&WriteAdapter,
+ quota_io_->file_,
+ offset_,
+ base::Passed(&buffer_),
+ bytes_to_write_),
+ base::Bind(&WriteOperation::DidWrite,
+ weak_factory_.GetWeakPtr()))) {
+ DidFail(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+ }
+
+ virtual void DidFail(PlatformFileError error) OVERRIDE {
+ DidFinish(error, 0);
+ }
+
+ bool finished() const { return finished_; }
+
+ virtual void WillRunCallback() {
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WriteOperation::RunCallback, weak_factory_.GetWeakPtr()));
+ }
+
+ private:
+ void DidWrite(int bytes_written) {
+ base::PlatformFileError error = bytes_written > 0 ?
+ base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_FAILED;
+ DidFinish(error, bytes_written);
+ }
+
+ void DidFinish(PlatformFileError status, int bytes_written) {
+ finished_ = true;
+ status_ = status;
+ bytes_written_ = bytes_written;
+ int64_t max_offset =
+ (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
+ // This may delete itself by calling RunCallback.
+ quota_io_->DidWrite(this, max_offset);
+ }
+
+ virtual void RunCallback() {
+ DCHECK_EQ(false, callback_.is_null());
+ callback_.Run(status_, bytes_written_);
+ delete this;
+ }
+
+ const int64_t offset_;
+ scoped_ptr<char[]> buffer_;
+ const int32_t bytes_to_write_;
+ WriteCallback callback_;
+ bool finished_;
+ PlatformFileError status_;
+ int64_t bytes_written_;
+ base::WeakPtrFactory<WriteOperation> weak_factory_;
+};
+
+class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
+ public:
+ SetLengthOperation(QuotaFileIO* quota_io,
+ bool is_will_operation,
+ int64_t length,
+ const StatusCallback& callback)
+ : PendingOperationBase(quota_io, is_will_operation),
+ length_(length),
+ callback_(callback),
+ weak_factory_(this) {}
+
+ virtual ~SetLengthOperation() {}
+
+ virtual void Run() OVERRIDE {
+ DCHECK(quota_io_);
+ if (quota_io_->CheckIfExceedsQuota(length_)) {
+ DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
+ return;
+ }
+ if (is_will_operation_) {
+ DidFinish(base::PLATFORM_FILE_OK);
+ return;
+ }
+
+ PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
+ if (!plugin_delegate) {
+ DidFail(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+
+ if (!base::FileUtilProxy::Truncate(
+ plugin_delegate->GetFileThreadMessageLoopProxy().get(),
+ quota_io_->file_,
+ length_,
+ base::Bind(&SetLengthOperation::DidFinish,
+ weak_factory_.GetWeakPtr()))) {
+ DidFail(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+ }
+
+ virtual void DidFail(PlatformFileError error) OVERRIDE {
+ DidFinish(error);
+ }
+
+ private:
+ void DidFinish(PlatformFileError status) {
+ quota_io_->DidSetLength(status, length_);
+ DCHECK_EQ(false, callback_.is_null());
+ callback_.Run(status);
+ delete this;
+ }
+
+ int64_t length_;
+ StatusCallback callback_;
+ base::WeakPtrFactory<SetLengthOperation> weak_factory_;
+};
+
+// QuotaFileIO --------------------------------------------------------------
+
+QuotaFileIO::QuotaFileIO(
+ PP_Instance instance,
+ PlatformFile file,
+ const GURL& file_url,
+ PP_FileSystemType type)
+ : pp_instance_(instance),
+ file_(file),
+ file_url_(file_url),
+ storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
+ cached_file_size_(0),
+ cached_available_space_(0),
+ outstanding_quota_queries_(0),
+ outstanding_errors_(0),
+ max_written_offset_(0),
+ inflight_operations_(0),
+ weak_factory_(this) {
+ DCHECK_NE(base::kInvalidPlatformFileValue, file_);
+ DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
+}
+
+QuotaFileIO::~QuotaFileIO() {
+ // Note that this doesn't dispatch pending callbacks.
+ STLDeleteContainerPointers(pending_operations_.begin(),
+ pending_operations_.end());
+ STLDeleteContainerPointers(pending_callbacks_.begin(),
+ pending_callbacks_.end());
+}
+
+bool QuotaFileIO::Write(
+ int64_t offset, const char* buffer, int32_t bytes_to_write,
+ const WriteCallback& callback) {
+ if (bytes_to_write <= 0)
+ return false;
+
+ WriteOperation* op = new WriteOperation(
+ this, false, offset, buffer, bytes_to_write, callback);
+ return RegisterOperationForQuotaChecks(op);
+}
+
+bool QuotaFileIO::SetLength(int64_t length, const StatusCallback& callback) {
+ DCHECK(pending_operations_.empty());
+ SetLengthOperation* op = new SetLengthOperation(
+ this, false, length, callback);
+ return RegisterOperationForQuotaChecks(op);
+}
+
+bool QuotaFileIO::WillWrite(
+ int64_t offset, int32_t bytes_to_write, const WriteCallback& callback) {
+ WriteOperation* op = new WriteOperation(
+ this, true, offset, NULL, bytes_to_write, callback);
+ return RegisterOperationForQuotaChecks(op);
+}
+
+bool QuotaFileIO::WillSetLength(int64_t length,
+ const StatusCallback& callback) {
+ DCHECK(pending_operations_.empty());
+ SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
+ return RegisterOperationForQuotaChecks(op);
+}
+
+PluginDelegate* QuotaFileIO::GetPluginDelegate() const {
+ PluginInstanceImpl* instance = HostGlobals::Get()->GetInstance(pp_instance_);
+ if (instance)
+ return instance->delegate();
+ return NULL;
+}
+
+bool QuotaFileIO::RegisterOperationForQuotaChecks(
+ PendingOperationBase* op_ptr) {
+ scoped_ptr<PendingOperationBase> op(op_ptr);
+ if (pending_operations_.empty()) {
+ // This is the first pending quota check. Run querying the file size
+ // and available space.
+ outstanding_quota_queries_ = 0;
+ outstanding_errors_ = 0;
+
+ PluginDelegate* plugin_delegate = GetPluginDelegate();
+ if (!plugin_delegate)
+ return false;
+
+ // Query the file size.
+ ++outstanding_quota_queries_;
+ if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
+ plugin_delegate->GetFileThreadMessageLoopProxy().get(),
+ file_,
+ base::Bind(&QuotaFileIO::DidQueryInfoForQuota,
+ weak_factory_.GetWeakPtr()))) {
+ // This makes the call fail synchronously; we do not fire the callback
+ // here but just delete the operation and return false.
+ return false;
+ }
+
+ // Query the current available space.
+ ++outstanding_quota_queries_;
+ plugin_delegate->QueryAvailableSpace(
+ file_url_.GetOrigin(), storage_type_,
+ base::Bind(&QuotaFileIO::DidQueryAvailableSpace,
+ weak_factory_.GetWeakPtr()));
+ }
+ pending_operations_.push_back(op.release());
+ return true;
+}
+
+void QuotaFileIO::DidQueryInfoForQuota(
+ base::PlatformFileError error_code,
+ const base::PlatformFileInfo& file_info) {
+ if (error_code != base::PLATFORM_FILE_OK)
+ ++outstanding_errors_;
+ cached_file_size_ = file_info.size;
+ DCHECK_GT(outstanding_quota_queries_, 0);
+ if (--outstanding_quota_queries_ == 0)
+ DidQueryForQuotaCheck();
+}
+
+void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
+ cached_available_space_ = avail_space;
+ DCHECK_GT(outstanding_quota_queries_, 0);
+ if (--outstanding_quota_queries_ == 0)
+ DidQueryForQuotaCheck();
+}
+
+void QuotaFileIO::DidQueryForQuotaCheck() {
+ DCHECK(!pending_operations_.empty());
+ DCHECK_GT(inflight_operations_, 0);
+ while (!pending_operations_.empty()) {
+ PendingOperationBase* op = pending_operations_.front();
+ pending_operations_.pop_front();
+ pending_callbacks_.push_back(op);
+ if (outstanding_errors_ > 0) {
+ op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
+ continue;
+ }
+ op->Run();
+ }
+}
+
+bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
+ DCHECK_GE(cached_file_size_, 0);
+ DCHECK_GE(cached_available_space_, 0);
+ return new_file_size - cached_file_size_ > cached_available_space_;
+}
+
+void QuotaFileIO::WillUpdate() {
+ if (inflight_operations_++ == 0) {
+ PluginDelegate* plugin_delegate = GetPluginDelegate();
+ if (plugin_delegate)
+ plugin_delegate->WillUpdateFile(file_url_);
+ DCHECK_EQ(0, max_written_offset_);
+ }
+}
+
+void QuotaFileIO::DidWrite(WriteOperation* op,
+ int64_t written_offset_end) {
+ max_written_offset_ = std::max(max_written_offset_, written_offset_end);
+ DCHECK_GT(inflight_operations_, 0);
+ DCHECK(!pending_callbacks_.empty());
+ // Fire callbacks for finished operations.
+ while (!pending_callbacks_.empty()) {
+ WriteOperation* op = static_cast<WriteOperation*>(
+ pending_callbacks_.front());
+ if (!op->finished())
+ break;
+ pending_callbacks_.pop_front();
+ op->WillRunCallback();
+ }
+ // If we have no more pending writes, notify the browser that we did
+ // update the file.
+ if (--inflight_operations_ == 0) {
+ DCHECK(pending_operations_.empty());
+ int64_t growth = max_written_offset_ - cached_file_size_;
+ growth = growth < 0 ? 0 : growth;
+
+ PluginDelegate* plugin_delegate = GetPluginDelegate();
+ if (plugin_delegate)
+ plugin_delegate->DidUpdateFile(file_url_, growth);
+ max_written_offset_ = 0;
+ }
+}
+
+void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
+ DCHECK_EQ(1, inflight_operations_);
+ pending_callbacks_.pop_front();
+ DCHECK(pending_callbacks_.empty());
+ int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
+ new_file_size - cached_file_size_;
+
+
+ PluginDelegate* plugin_delegate = GetPluginDelegate();
+ if (plugin_delegate)
+ plugin_delegate->DidUpdateFile(file_url_, delta);
+ inflight_operations_ = 0;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/quota_file_io.h b/content/renderer/pepper/quota_file_io.h
new file mode 100644
index 0000000..7c95464
--- /dev/null
+++ b/content/renderer/pepper/quota_file_io.h
@@ -0,0 +1,117 @@
+// 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_PEPPER_QUOTA_FILE_IO_H_
+#define CONTENT_RENDERER_PEPPER_QUOTA_FILE_IO_H_
+
+#include <deque>
+
+#include "base/files/file_util_proxy.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "content/common/content_export.h"
+#include "ppapi/c/pp_file_info.h"
+#include "ppapi/c/pp_instance.h"
+#include "url/gurl.h"
+#include "webkit/common/quota/quota_types.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PluginDelegate;
+
+// This class is created per PPB_FileIO_Impl instance and provides
+// write operations for quota-managed files (i.e. files of
+// PP_FILESYSTEMTYPE_LOCAL{PERSISTENT,TEMPORARY}).
+class QuotaFileIO {
+ public:
+ typedef base::FileUtilProxy::WriteCallback WriteCallback;
+ typedef base::FileUtilProxy::StatusCallback StatusCallback;
+
+ CONTENT_EXPORT QuotaFileIO(PP_Instance instance,
+ base::PlatformFile file,
+ const GURL& path_url,
+ PP_FileSystemType type);
+ CONTENT_EXPORT ~QuotaFileIO();
+
+ // Performs write or setlength operation with quota checks.
+ // Returns true when the operation is successfully dispatched.
+ // |bytes_to_write| must be geater than zero.
+ // |callback| will be dispatched when the operation completes.
+ // Otherwise it returns false and |callback| will not be dispatched.
+ // |callback| will not be dispatched either when this instance is
+ // destroyed before the operation completes.
+ // SetLength/WillSetLength cannot be called while there're any in-flight
+ // operations. For Write/WillWrite it is guaranteed that |callback| are
+ // always dispatched in the same order as Write being called.
+ CONTENT_EXPORT bool Write(int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ const WriteCallback& callback);
+ CONTENT_EXPORT bool WillWrite(int64_t offset,
+ int32_t bytes_to_write,
+ const WriteCallback& callback);
+
+ CONTENT_EXPORT bool SetLength(int64_t length,
+ const StatusCallback& callback);
+ CONTENT_EXPORT bool WillSetLength(int64_t length,
+ const StatusCallback& callback);
+
+ // Returns the plugin delegate or NULL if the resource has outlived the
+ // instance.
+ PluginDelegate* GetPluginDelegate() const;
+
+ private:
+ class PendingOperationBase;
+ class WriteOperation;
+ class SetLengthOperation;
+
+ bool CheckIfExceedsQuota(int64_t new_file_size) const;
+ void WillUpdate();
+ void DidWrite(WriteOperation* op, int64_t written_offset_end);
+ void DidSetLength(base::PlatformFileError error, int64_t new_file_size);
+
+ bool RegisterOperationForQuotaChecks(PendingOperationBase* op);
+ void DidQueryInfoForQuota(base::PlatformFileError error_code,
+ const base::PlatformFileInfo& file_info);
+ void DidQueryAvailableSpace(int64_t avail_space);
+ void DidQueryForQuotaCheck();
+
+ // The plugin instance that owns this (via PPB_FileIO_Impl).
+ PP_Instance pp_instance_;
+
+ // The file information associated to this instance.
+ base::PlatformFile file_;
+ GURL file_url_;
+ quota::StorageType storage_type_;
+
+ // Pending operations that are waiting quota checks and pending
+ // callbacks that are to be fired after the operation;
+ // we use two separate queues for them so that we can safely dequeue the
+ // pending callbacks while enqueueing new operations. (This could
+ // happen when callbacks are dispatched synchronously due to error etc.)
+ std::deque<PendingOperationBase*> pending_operations_;
+ std::deque<PendingOperationBase*> pending_callbacks_;
+
+ // Valid only while there're pending quota checks.
+ int64_t cached_file_size_;
+ int64_t cached_available_space_;
+
+ // Quota-related queries and errors occurred during in-flight quota checks.
+ int outstanding_quota_queries_;
+ int outstanding_errors_;
+
+ // For parallel writes bookkeeping.
+ int64_t max_written_offset_;
+ int inflight_operations_;
+
+ base::WeakPtrFactory<QuotaFileIO> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuotaFileIO);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_QUOTA_FILE_IO_H_
diff --git a/content/renderer/pepper/quota_file_io_unittest.cc b/content/renderer/pepper/quota_file_io_unittest.cc
new file mode 100644
index 0000000..ad66e52
--- /dev/null
+++ b/content/renderer/pepper/quota_file_io_unittest.cc
@@ -0,0 +1,501 @@
+// 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 <deque>
+#include <limits>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/platform_file.h"
+#include "content/renderer/pepper/mock_plugin_delegate.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "content/renderer/pepper/ppapi_unittest.h"
+#include "content/renderer/pepper/quota_file_io.h"
+
+using base::MessageLoopProxy;
+using base::PlatformFile;
+using base::PlatformFileError;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+class QuotaMockPluginDelegate : public MockPluginDelegate {
+ public:
+ typedef PluginDelegate::AvailableSpaceCallback Callback;
+
+ QuotaMockPluginDelegate()
+ : available_space_(0),
+ will_update_count_(0),
+ file_thread_(MessageLoopProxy::current()),
+ weak_factory_(this) {
+ }
+ virtual ~QuotaMockPluginDelegate() {}
+
+ virtual scoped_refptr<MessageLoopProxy>
+ GetFileThreadMessageLoopProxy() OVERRIDE {
+ return file_thread_;
+ }
+
+ virtual void QueryAvailableSpace(
+ const GURL& origin,
+ quota::StorageType type,
+ const Callback& callback) OVERRIDE {
+ DCHECK_EQ(false, callback.is_null());
+ MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(
+ &QuotaMockPluginDelegate::RunAvailableSpaceCallback,
+ weak_factory_.GetWeakPtr(), callback));
+ }
+
+ virtual void WillUpdateFile(const GURL& file_path) OVERRIDE {
+ file_path_ = file_path;
+ ++will_update_count_;
+ }
+
+ virtual void DidUpdateFile(const GURL& file_path, int64_t delta) OVERRIDE {
+ ASSERT_EQ(file_path_, file_path);
+ ASSERT_GT(will_update_count_, 0);
+ --will_update_count_;
+ available_space_ -= delta;
+ }
+
+ void set_available_space(int64 available) { available_space_ = available; }
+ int64_t available_space() const { return available_space_; }
+
+ private:
+ void RunAvailableSpaceCallback(const Callback& callback) {
+ callback.Run(available_space_);
+ }
+
+ int64_t available_space_;
+ int will_update_count_;
+ GURL file_path_;
+ scoped_refptr<MessageLoopProxy> file_thread_;
+ base::WeakPtrFactory<QuotaMockPluginDelegate> weak_factory_;
+};
+} // namespace
+
+class QuotaFileIOTest : public PpapiUnittest {
+ public:
+ QuotaFileIOTest()
+ : weak_factory_(this) {}
+
+ virtual void SetUp() OVERRIDE {
+ PpapiUnittest::SetUp();
+ ASSERT_TRUE(dir_.CreateUniqueTempDir());
+ base::FilePath path;
+ ASSERT_TRUE(file_util::CreateTemporaryFileInDir(dir_.path(), &path));
+ int file_flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_WRITE_ATTRIBUTES;
+ bool created = false;
+ file_ = base::kInvalidPlatformFileValue;
+ PlatformFileError error = base::PLATFORM_FILE_OK;
+ file_ = base::CreatePlatformFile(path, file_flags, &created, &error);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error);
+ ASSERT_NE(base::kInvalidPlatformFileValue, file_);
+ ASSERT_FALSE(created);
+ quota_file_io_.reset(new QuotaFileIO(
+ instance()->pp_instance(), file_, GURL(),
+ PP_FILESYSTEMTYPE_LOCALTEMPORARY));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ quota_file_io_.reset();
+ if (file_ != base::kInvalidPlatformFileValue)
+ base::ClosePlatformFile(file_);
+ PpapiUnittest::TearDown();
+ }
+
+ protected:
+ virtual MockPluginDelegate* NewPluginDelegate() OVERRIDE {
+ return static_cast<MockPluginDelegate*>(new QuotaMockPluginDelegate);
+ }
+
+ void WriteTestBody(bool will_operation) {
+ // Attempt to write zero bytes.
+ EXPECT_FALSE(quota_file_io_->Write(
+ 0, "data", 0,
+ base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr())));
+ // Attempt to write negative number of bytes.
+ EXPECT_FALSE(quota_file_io_->Write(
+ 0, "data", std::numeric_limits<int32_t>::min(),
+ base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr())));
+
+ quota_plugin_delegate()->set_available_space(100);
+ std::string read_buffer;
+
+ // Write 8 bytes at offset 0 (-> length=8).
+ std::string data("12345678");
+ Write(0, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 8, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ // WillWrite doesn't actually write.
+ EXPECT_EQ(0, GetPlatformFileSize());
+ // Adjust the actual file size to 'fake' write to proceed testing.
+ SetPlatformFileSize(8);
+ } else {
+ EXPECT_EQ(8, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ(data, read_buffer);
+ }
+
+ // Write 5 bytes at offset 5 (-> length=10).
+ data = "55555";
+ Write(5, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 10, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(8, GetPlatformFileSize());
+ SetPlatformFileSize(10);
+ } else {
+ EXPECT_EQ(10, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ("1234555555", read_buffer);
+ }
+
+ // Write 7 bytes at offset 8 (-> length=15).
+ data = "9012345";
+ Write(8, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 15, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(10, GetPlatformFileSize());
+ SetPlatformFileSize(15);
+ } else {
+ EXPECT_EQ(15, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ("123455559012345", read_buffer);
+ }
+
+ // Write 2 bytes at offset 2 (-> length=15).
+ data = "33";
+ Write(2, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 15, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(15, GetPlatformFileSize());
+ } else {
+ EXPECT_EQ(15, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ("123355559012345", read_buffer);
+ }
+
+ // Write 4 bytes at offset 20 (-> length=24).
+ data = "XXXX";
+ Write(20, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 24, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(15, GetPlatformFileSize());
+ SetPlatformFileSize(24);
+ } else {
+ EXPECT_EQ(24, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ(std::string("123355559012345\0\0\0\0\0XXXX", 24), read_buffer);
+ }
+
+ quota_plugin_delegate()->set_available_space(5);
+
+ // Quota error case. Write 7 bytes at offset 23 (-> length is unchanged)
+ data = "ABCDEFG";
+ Write(23, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status().front());
+ EXPECT_EQ(5, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ // Overlapping write. Write 6 bytes at offset 2 (-> length is unchanged)
+ data = "ABCDEF";
+ Write(2, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(5, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ // Overlapping + extending the file size, but within the quota.
+ // Write 6 bytes at offset 23 (-> length=29).
+ Write(23, data, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(0, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (!will_operation) {
+ EXPECT_EQ(29, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ(std::string("12ABCDEF9012345\0\0\0\0\0XXXABCDEF", 29),
+ read_buffer);
+ }
+ }
+
+ void SetLengthTestBody(bool will_operation) {
+ quota_plugin_delegate()->set_available_space(100);
+
+ SetLength(0, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(0, GetPlatformFileSize());
+ EXPECT_EQ(100, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ SetLength(8, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 8, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(0, GetPlatformFileSize());
+ SetPlatformFileSize(8);
+ } else {
+ EXPECT_EQ(8, GetPlatformFileSize());
+ }
+
+ SetLength(16, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 16, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(8, GetPlatformFileSize());
+ SetPlatformFileSize(16);
+ } else {
+ EXPECT_EQ(16, GetPlatformFileSize());
+ }
+
+ SetLength(4, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100 - 4, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(16, GetPlatformFileSize());
+ SetPlatformFileSize(4);
+ } else {
+ EXPECT_EQ(4, GetPlatformFileSize());
+ }
+
+ SetLength(0, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ EXPECT_EQ(100, quota_plugin_delegate()->available_space());
+ reset_results();
+
+ if (will_operation) {
+ EXPECT_EQ(4, GetPlatformFileSize());
+ SetPlatformFileSize(0);
+ } else {
+ EXPECT_EQ(0, GetPlatformFileSize());
+ }
+
+ quota_plugin_delegate()->set_available_space(5);
+
+ // Quota error case.
+ SetLength(7, will_operation);
+ base::MessageLoop::current()->RunUntilIdle();
+ ASSERT_EQ(1U, num_results());
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status().front());
+ EXPECT_EQ(5, quota_plugin_delegate()->available_space());
+ reset_results();
+ }
+
+ QuotaMockPluginDelegate* quota_plugin_delegate() {
+ return static_cast<QuotaMockPluginDelegate*>(delegate());
+ }
+
+ void Write(int64_t offset, const std::string& data, bool will_operation) {
+ if (will_operation) {
+ ASSERT_TRUE(quota_file_io_->WillWrite(
+ offset, data.size(),
+ base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr())));
+ } else {
+ ASSERT_TRUE(quota_file_io_->Write(
+ offset, data.c_str(), data.size(),
+ base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr())));
+ }
+ }
+
+ void SetLength(int64_t length, bool will_operation) {
+ if (will_operation) {
+ ASSERT_TRUE(quota_file_io_->WillSetLength(
+ length,
+ base::Bind(&QuotaFileIOTest::DidSetLength,
+ weak_factory_.GetWeakPtr())));
+ } else {
+ ASSERT_TRUE(quota_file_io_->SetLength(
+ length,
+ base::Bind(&QuotaFileIOTest::DidSetLength,
+ weak_factory_.GetWeakPtr())));
+ }
+ }
+
+ void DidWrite(PlatformFileError status, int bytes_written) {
+ status_.push_back(status);
+ bytes_written_.push_back(bytes_written);
+ }
+
+ void DidSetLength(PlatformFileError status) {
+ status_.push_back(status);
+ }
+
+ size_t num_results() const { return status_.size(); }
+ const std::deque<int>& bytes_written() const { return bytes_written_; }
+ const std::deque<PlatformFileError>& status() const { return status_; }
+
+ void reset_results() {
+ bytes_written_.clear();
+ status_.clear();
+ }
+
+ void pop_result() {
+ bytes_written_.pop_front();
+ status_.pop_front();
+ }
+
+ void ReadPlatformFile(std::string* data) {
+ data->clear();
+ char buf[256];
+ int32_t read_offset = 0;
+ for (;;) {
+ int rv = base::ReadPlatformFile(file_, read_offset, buf, sizeof(buf));
+ ASSERT_GE(rv, 0);
+ if (rv == 0)
+ break;
+ read_offset += rv;
+ data->append(buf, rv);
+ }
+ }
+
+ int64_t GetPlatformFileSize() {
+ base::PlatformFileInfo info;
+ EXPECT_TRUE(base::GetPlatformFileInfo(file_, &info));
+ return info.size;
+ }
+
+ void SetPlatformFileSize(int64_t length) {
+ EXPECT_TRUE(base::TruncatePlatformFile(file_, length));
+ }
+
+ private:
+ base::ScopedTempDir dir_;
+ PlatformFile file_;
+ scoped_ptr<QuotaFileIO> quota_file_io_;
+ std::deque<int> bytes_written_;
+ std::deque<PlatformFileError> status_;
+ base::WeakPtrFactory<QuotaFileIOTest> weak_factory_;
+};
+
+TEST_F(QuotaFileIOTest, Write) {
+ WriteTestBody(false);
+}
+
+TEST_F(QuotaFileIOTest, WillWrite) {
+ WriteTestBody(true);
+}
+
+TEST_F(QuotaFileIOTest, SetLength) {
+ SetLengthTestBody(false);
+}
+
+TEST_F(QuotaFileIOTest, WillSetLength) {
+ SetLengthTestBody(true);
+}
+
+TEST_F(QuotaFileIOTest, ParallelWrites) {
+ quota_plugin_delegate()->set_available_space(22);
+ std::string read_buffer;
+
+ const std::string data1[] = {
+ std::string("12345678"),
+ std::string("55555"),
+ std::string("9012345"),
+ };
+ Write(0, data1[0], false);
+ Write(5, data1[1], false);
+ Write(8, data1[2], false);
+ base::MessageLoop::current()->RunUntilIdle();
+
+ ASSERT_EQ(ARRAYSIZE_UNSAFE(data1), num_results());
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data1); ++i) {
+ EXPECT_EQ(static_cast<int>(data1[i].size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ pop_result();
+ }
+
+ EXPECT_EQ(22 - 15, quota_plugin_delegate()->available_space());
+ EXPECT_EQ(15, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ("123455559012345", read_buffer);
+
+ // The second write will fail for quota error.
+ const std::string data2[] = {
+ std::string("33"),
+ std::string("XXXX"),
+ };
+ Write(2, data2[0], false);
+ Write(20, data2[1], false);
+ base::MessageLoop::current()->RunUntilIdle();
+
+ ASSERT_EQ(ARRAYSIZE_UNSAFE(data2), num_results());
+ EXPECT_EQ(static_cast<int>(data2[0].size()), bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_OK, status().front());
+ pop_result();
+ EXPECT_EQ(0, bytes_written().front());
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status().front());
+ pop_result();
+
+ EXPECT_EQ(22 - 15, quota_plugin_delegate()->available_space());
+ EXPECT_EQ(15, GetPlatformFileSize());
+ ReadPlatformFile(&read_buffer);
+ EXPECT_EQ("123355559012345", read_buffer);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc
index 18b5859..0d6768f 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -8,11 +8,16 @@
#include "base/logging.h"
#include "base/process/process_handle.h"
#include "content/common/sandbox_util.h"
+#include "content/renderer/pepper/fullscreen_container.h"
+#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/pepper_browser_connection.h"
#include "content/renderer/pepper/pepper_graphics_2d_host.h"
#include "content/renderer/pepper/pepper_in_process_resource_creation.h"
#include "content/renderer/pepper/pepper_in_process_router.h"
#include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/render_view_impl.h"
#include "content/renderer/render_widget_fullscreen_pepper.h"
#include "ipc/ipc_message.h"
@@ -23,11 +28,6 @@
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "ui/gfx/point.h"
-#include "webkit/plugins/ppapi/fullscreen_container.h"
-#include "webkit/plugins/ppapi/host_globals.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
-#include "webkit/plugins/ppapi/plugin_module.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
using webkit::ppapi::HostGlobals;
using webkit::ppapi::PluginInstance;
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.h b/content/renderer/pepper/renderer_ppapi_host_impl.h
index 6d0332f..6d576f7 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.h
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.h
@@ -9,9 +9,9 @@
#include "base/memory/scoped_ptr.h"
#include "content/public/renderer/renderer_ppapi_host.h"
#include "content/renderer/pepper/content_renderer_pepper_host_factory.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/plugin_module.h"
#include "ppapi/host/ppapi_host.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
-#include "webkit/plugins/ppapi/plugin_module.h"
namespace IPC {
class Sender;
diff --git a/content/renderer/pepper/resource_creation_impl.cc b/content/renderer/pepper/resource_creation_impl.cc
new file mode 100644
index 0000000..63fbe35
--- /dev/null
+++ b/content/renderer/pepper/resource_creation_impl.cc
@@ -0,0 +1,317 @@
+// 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/resource_creation_impl.h"
+
+#include "content/renderer/pepper/common.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"
+#include "content/renderer/pepper/ppb_file_ref_impl.h"
+#include "content/renderer/pepper/ppb_flash_message_loop_impl.h"
+#include "content/renderer/pepper/ppb_graphics_3d_impl.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/pepper/ppb_network_monitor_private_impl.h"
+#include "content/renderer/pepper/ppb_scrollbar_impl.h"
+#include "content/renderer/pepper/ppb_tcp_server_socket_private_impl.h"
+#include "content/renderer/pepper/ppb_tcp_socket_private_impl.h"
+#include "content/renderer/pepper/ppb_video_decoder_impl.h"
+#include "content/renderer/pepper/ppb_x509_certificate_private_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "ppapi/c/pp_size.h"
+#include "ppapi/shared_impl/ppb_audio_config_shared.h"
+#include "ppapi/shared_impl/ppb_image_data_shared.h"
+#include "ppapi/shared_impl/ppb_input_event_shared.h"
+#include "ppapi/shared_impl/ppb_resource_array_shared.h"
+#include "ppapi/shared_impl/var.h"
+
+using ppapi::InputEventData;
+using ppapi::PPB_InputEvent_Shared;
+using ppapi::PPB_ResourceArray_Shared;
+using ppapi::StringVar;
+
+namespace webkit {
+namespace ppapi {
+
+ResourceCreationImpl::ResourceCreationImpl(PluginInstanceImpl* instance) {
+}
+
+ResourceCreationImpl::~ResourceCreationImpl() {
+}
+
+PP_Resource ResourceCreationImpl::CreateAudio(
+ PP_Instance instance,
+ PP_Resource config_id,
+ PPB_Audio_Callback audio_callback,
+ void* user_data) {
+ return PPB_Audio_Impl::Create(instance, config_id, audio_callback,
+ user_data);
+}
+
+PP_Resource ResourceCreationImpl::CreateAudioConfig(
+ PP_Instance instance,
+ PP_AudioSampleRate sample_rate,
+ uint32_t sample_frame_count) {
+ return ::ppapi::PPB_AudioConfig_Shared::Create(
+ ::ppapi::OBJECT_IS_IMPL, instance, sample_rate, sample_frame_count);
+}
+
+PP_Resource ResourceCreationImpl::CreateAudioTrusted(
+ PP_Instance instance) {
+ return (new PPB_Audio_Impl(instance))->GetReference();
+}
+
+PP_Resource ResourceCreationImpl::CreateAudioInput(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateBroker(PP_Instance instance) {
+ return (new PPB_Broker_Impl(instance))->GetReference();
+}
+
+PP_Resource ResourceCreationImpl::CreateBuffer(PP_Instance instance,
+ uint32_t size) {
+ return PPB_Buffer_Impl::Create(instance, size);
+}
+
+PP_Resource ResourceCreationImpl::CreateFileRef(
+ PP_Instance instance,
+ PP_Resource file_system,
+ const char* path) {
+ PPB_FileRef_Impl* res = PPB_FileRef_Impl::CreateInternal(
+ instance, file_system, path);
+ return res ? res->GetReference() : 0;
+}
+
+PP_Resource ResourceCreationImpl::CreateFileRef(
+ const ::ppapi::PPB_FileRef_CreateInfo& serialized) {
+ // When we're in-process, the host resource in the create info *is* the
+ // resource, so we don't need to do anything.
+ return serialized.resource.host_resource();
+}
+
+PP_Resource ResourceCreationImpl::CreateFlashDRM(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateFlashFontFile(
+ PP_Instance instance,
+ const PP_BrowserFont_Trusted_Description* description,
+ PP_PrivateFontCharset charset) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateFlashMenu(
+ PP_Instance instance,
+ const PP_Flash_Menu* menu_data) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateFlashMessageLoop(PP_Instance instance) {
+ return PPB_Flash_MessageLoop_Impl::Create(instance);
+}
+
+PP_Resource ResourceCreationImpl::CreateGraphics3D(
+ PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list) {
+ return PPB_Graphics3D_Impl::Create(instance, share_context, attrib_list);
+}
+
+PP_Resource ResourceCreationImpl::CreateGraphics3DRaw(
+ PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list) {
+ return PPB_Graphics3D_Impl::CreateRaw(instance, share_context, attrib_list);
+}
+
+PP_Resource ResourceCreationImpl::CreateHostResolver(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateHostResolverPrivate(
+ PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateImageData(
+ PP_Instance instance,
+ PP_ImageDataFormat format,
+ const PP_Size* size,
+ PP_Bool init_to_zero) {
+ return PPB_ImageData_Impl::Create(instance,
+ ::ppapi::PPB_ImageData_Shared::PLATFORM,
+ format, *size, init_to_zero);
+}
+
+PP_Resource ResourceCreationImpl::CreateImageDataSimple(
+ PP_Instance instance,
+ PP_ImageDataFormat format,
+ const PP_Size* size,
+ PP_Bool init_to_zero) {
+ return PPB_ImageData_Impl::Create(instance,
+ ::ppapi::PPB_ImageData_Shared::SIMPLE,
+ format, *size, init_to_zero);
+}
+
+PP_Resource ResourceCreationImpl::CreateIMEInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ struct PP_Var text,
+ uint32_t segment_number,
+ const uint32_t* segment_offsets,
+ int32_t target_segment,
+ uint32_t selection_start,
+ uint32_t selection_end) {
+ return PPB_InputEvent_Shared::CreateIMEInputEvent(
+ ::ppapi::OBJECT_IS_IMPL, instance, type, time_stamp, text, segment_number,
+ segment_offsets, target_segment, selection_start, selection_end);
+}
+
+PP_Resource ResourceCreationImpl::CreateIsolatedFileSystem(PP_Instance instance,
+ const char* fsid) {
+ NOTIMPLEMENTED(); // no need to support in-process
+ return 0;
+}
+
+PP_Resource ResourceCreationImpl::CreateKeyboardInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers,
+ uint32_t key_code,
+ struct PP_Var character_text) {
+ return PPB_InputEvent_Shared::CreateKeyboardInputEvent(
+ ::ppapi::OBJECT_IS_IMPL, instance, type, time_stamp, modifiers, key_code,
+ character_text);
+}
+
+PP_Resource ResourceCreationImpl::CreateMouseInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers,
+ PP_InputEvent_MouseButton mouse_button,
+ const PP_Point* mouse_position,
+ int32_t click_count,
+ const PP_Point* mouse_movement) {
+ return PPB_InputEvent_Shared::CreateMouseInputEvent(
+ ::ppapi::OBJECT_IS_IMPL, instance, type, time_stamp, modifiers,
+ mouse_button, mouse_position, click_count, mouse_movement);
+}
+
+PP_Resource ResourceCreationImpl::CreateNetAddressFromIPv4Address(
+ PP_Instance instance,
+ const PP_NetAddress_IPv4* ipv4_addr) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateNetAddressFromIPv6Address(
+ PP_Instance instance,
+ const PP_NetAddress_IPv6* ipv6_addr) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateNetAddressFromNetAddressPrivate(
+ PP_Instance instance,
+ const PP_NetAddress_Private& private_addr) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateTouchInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers) {
+ return PPB_InputEvent_Shared::CreateTouchInputEvent(
+ ::ppapi::OBJECT_IS_IMPL, instance, type, time_stamp, modifiers);
+}
+
+PP_Resource ResourceCreationImpl::CreateNetworkMonitor(
+ PP_Instance instance,
+ PPB_NetworkMonitor_Callback callback,
+ void* user_data) {
+ return PPB_NetworkMonitor_Private_Impl::Create(instance, callback, user_data);
+}
+
+PP_Resource ResourceCreationImpl::CreateScrollbar(PP_Instance instance,
+ PP_Bool vertical) {
+ 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::CreateResourceArray(
+ PP_Instance instance,
+ const PP_Resource elements[],
+ uint32_t size) {
+ PPB_ResourceArray_Shared* object = new PPB_ResourceArray_Shared(
+ ::ppapi::OBJECT_IS_IMPL, instance, elements, size);
+ return object->GetReference();
+}
+
+PP_Resource ResourceCreationImpl::CreateTCPServerSocketPrivate(
+ PP_Instance instance) {
+ return PPB_TCPServerSocket_Private_Impl::CreateResource(instance);
+}
+
+PP_Resource ResourceCreationImpl::CreateTCPSocket(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateTCPSocketPrivate(PP_Instance instance) {
+ return PPB_TCPSocket_Private_Impl::CreateResource(instance);
+}
+
+PP_Resource ResourceCreationImpl::CreateUDPSocket(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateUDPSocketPrivate(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateVideoCapture(PP_Instance instance) {
+ return 0; // VideoCapture is not supported in process now.
+}
+
+PP_Resource ResourceCreationImpl::CreateVideoDecoder(
+ PP_Instance instance,
+ PP_Resource graphics3d_id,
+ PP_VideoDecoder_Profile profile) {
+ return PPB_VideoDecoder_Impl::Create(instance, graphics3d_id, profile);
+}
+
+PP_Resource ResourceCreationImpl::CreateVideoDestination(
+ PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateVideoSource(
+ PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
+PP_Resource ResourceCreationImpl::CreateWheelInputEvent(
+ PP_Instance instance,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers,
+ const PP_FloatPoint* wheel_delta,
+ const PP_FloatPoint* wheel_ticks,
+ PP_Bool scroll_by_page) {
+ return PPB_InputEvent_Shared::CreateWheelInputEvent(
+ ::ppapi::OBJECT_IS_IMPL, instance, time_stamp, modifiers,
+ wheel_delta, wheel_ticks, scroll_by_page);
+}
+
+PP_Resource ResourceCreationImpl::CreateX509CertificatePrivate(
+ PP_Instance instance) {
+ return PPB_X509Certificate_Private_Impl::CreateResource(instance);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/resource_creation_impl.h b/content/renderer/pepper/resource_creation_impl.h
new file mode 100644
index 0000000..8ed7ac4
--- /dev/null
+++ b/content/renderer/pepper/resource_creation_impl.h
@@ -0,0 +1,151 @@
+// 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_RESOURCE_CREATION_IMPL_H_
+#define CONTENT_RENDERER_PEPPER_RESOURCE_CREATION_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ppapi/thunk/resource_creation_api.h"
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstanceImpl;
+
+// This is an abstract class. ResourceCreationAPI functions that implement
+// "old-style" resources are handled here. See
+// content/renderer/pepper/pepper_in_process_resource_creation.h for functions
+// that implement "new-style" resources.
+class ResourceCreationImpl : public ::ppapi::thunk::ResourceCreationAPI {
+ public:
+ explicit ResourceCreationImpl(PluginInstanceImpl* instance);
+ virtual ~ResourceCreationImpl();
+
+ // ResourceCreationAPI implementation.
+ virtual PP_Resource CreateAudio(PP_Instance instance,
+ PP_Resource config_id,
+ PPB_Audio_Callback audio_callback,
+ void* user_data) OVERRIDE;
+ virtual PP_Resource CreateAudioTrusted(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateAudioConfig(PP_Instance instance,
+ PP_AudioSampleRate sample_rate,
+ uint32_t sample_frame_count) OVERRIDE;
+ virtual PP_Resource CreateAudioInput(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateBroker(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateBuffer(PP_Instance instance,
+ uint32_t size) OVERRIDE;
+ virtual PP_Resource CreateFileRef(PP_Instance instance,
+ PP_Resource file_system,
+ const char* path) OVERRIDE;
+ virtual PP_Resource CreateFileRef(
+ const ::ppapi::PPB_FileRef_CreateInfo& serialized) OVERRIDE;
+ virtual PP_Resource CreateFlashDRM(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateFlashFontFile(
+ PP_Instance instance,
+ const PP_BrowserFont_Trusted_Description* description,
+ PP_PrivateFontCharset charset) OVERRIDE;
+ virtual PP_Resource CreateFlashMenu(PP_Instance instance,
+ const PP_Flash_Menu* menu_data) OVERRIDE;
+ virtual PP_Resource CreateFlashMessageLoop(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateGraphics3D(PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list) OVERRIDE;
+ virtual PP_Resource CreateGraphics3DRaw(PP_Instance instance,
+ PP_Resource share_context,
+ const int32_t* attrib_list) OVERRIDE;
+ virtual PP_Resource CreateHostResolver(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateHostResolverPrivate(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateImageData(PP_Instance instance,
+ PP_ImageDataFormat format,
+ const PP_Size* size,
+ PP_Bool init_to_zero) OVERRIDE;
+ virtual PP_Resource CreateImageDataSimple(PP_Instance instance,
+ PP_ImageDataFormat format,
+ const PP_Size* size,
+ PP_Bool init_to_zero) OVERRIDE;
+ virtual PP_Resource CreateIMEInputEvent(PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ struct PP_Var text,
+ uint32_t segment_number,
+ const uint32_t* segment_offsets,
+ int32_t target_segment,
+ uint32_t selection_start,
+ uint32_t selection_end) OVERRIDE;
+ virtual PP_Resource CreateIsolatedFileSystem(PP_Instance instance,
+ const char* fsid) OVERRIDE;
+ virtual PP_Resource CreateKeyboardInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers,
+ uint32_t key_code,
+ PP_Var character_text) OVERRIDE;
+ virtual PP_Resource CreateMouseInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers,
+ PP_InputEvent_MouseButton mouse_button,
+ const PP_Point* mouse_position,
+ int32_t click_count,
+ const PP_Point* mouse_movement) OVERRIDE;
+ virtual PP_Resource CreateNetAddressFromIPv4Address(
+ PP_Instance instance,
+ const PP_NetAddress_IPv4* ipv4_addr) OVERRIDE;
+ virtual PP_Resource CreateNetAddressFromIPv6Address(
+ PP_Instance instance,
+ const PP_NetAddress_IPv6* ipv6_addr) OVERRIDE;
+ virtual PP_Resource CreateNetAddressFromNetAddressPrivate(
+ PP_Instance instance,
+ const PP_NetAddress_Private& private_addr) OVERRIDE;
+ virtual PP_Resource CreateTouchInputEvent(
+ PP_Instance instance,
+ PP_InputEvent_Type type,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers) OVERRIDE;
+ virtual PP_Resource CreateNetworkMonitor(
+ PP_Instance instance,
+ PPB_NetworkMonitor_Callback callback,
+ void* user_data) OVERRIDE;
+ virtual PP_Resource CreateResourceArray(PP_Instance instance,
+ const PP_Resource elements[],
+ uint32_t size) OVERRIDE;
+ virtual PP_Resource CreateScrollbar(PP_Instance instance,
+ PP_Bool vertical) OVERRIDE;
+ virtual PP_Resource CreateTalk(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateTCPServerSocketPrivate(
+ PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateTCPSocket(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateUDPSocket(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateVideoCapture(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateVideoDecoder(
+ PP_Instance instance,
+ PP_Resource graphics3d_id,
+ PP_VideoDecoder_Profile profile) OVERRIDE;
+ virtual PP_Resource CreateVideoDestination(
+ PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateVideoSource(
+ PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateWheelInputEvent(
+ PP_Instance instance,
+ PP_TimeTicks time_stamp,
+ uint32_t modifiers,
+ const PP_FloatPoint* wheel_delta,
+ const PP_FloatPoint* wheel_ticks,
+ PP_Bool scroll_by_page) OVERRIDE;
+ virtual PP_Resource CreateX509CertificatePrivate(
+ PP_Instance instance) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceCreationImpl);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_RESOURCE_CREATION_IMPL_H_
diff --git a/content/renderer/pepper/resource_helper.cc b/content/renderer/pepper/resource_helper.cc
new file mode 100644
index 0000000..c665223
--- /dev/null
+++ b/content/renderer/pepper/resource_helper.cc
@@ -0,0 +1,41 @@
+// 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/pepper/resource_helper.h"
+
+#include "base/logging.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
+#include "ppapi/shared_impl/resource.h"
+
+namespace webkit {
+namespace ppapi {
+
+// static
+PluginInstanceImpl* ResourceHelper::GetPluginInstance(
+ const ::ppapi::Resource* resource) {
+ return PPInstanceToPluginInstance(resource->pp_instance());
+}
+
+PluginInstanceImpl* ResourceHelper::PPInstanceToPluginInstance(
+ PP_Instance instance) {
+ return HostGlobals::Get()->GetInstance(instance);
+}
+
+PluginModule* ResourceHelper::GetPluginModule(
+ const ::ppapi::Resource* resource) {
+ PluginInstanceImpl* instance = GetPluginInstance(resource);
+ return instance ? instance->module() : NULL;
+}
+
+PluginDelegate* ResourceHelper::GetPluginDelegate(
+ const ::ppapi::Resource* resource) {
+ PluginInstanceImpl* instance = GetPluginInstance(resource);
+ return instance ? instance->delegate() : NULL;
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/content/renderer/pepper/resource_helper.h b/content/renderer/pepper/resource_helper.h
new file mode 100644
index 0000000..fa8483f
--- /dev/null
+++ b/content/renderer/pepper/resource_helper.h
@@ -0,0 +1,53 @@
+// 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_PEPPER_RESOURCE_HELPER_H_
+#define CONTENT_RENDERER_PEPPER_RESOURCE_HELPER_H_
+
+#include "base/basictypes.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+
+namespace ppapi {
+class Resource;
+}
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstanceImpl;
+class PluginModule;
+class PluginDelegate;
+
+// Helper functions for Resoruce implementations.
+//
+// This is specifically not designed to be a base class that derives from
+// ppapi::Resource to avoid diamond inheritance if most of a resource class
+// is implemented in the shared_impl (to share code with the proxy).
+class ResourceHelper {
+ public:
+ // Returns the instance implementation object for the given resource, or NULL
+ // if the resource has outlived its instance.
+ static PluginInstanceImpl* GetPluginInstance(
+ const ::ppapi::Resource* resource);
+
+ // Returns the module for the given resource, or NULL if the resource has
+ // outlived its instance.
+ static PluginModule* GetPluginModule(const ::ppapi::Resource* resource);
+
+ // Returns the plugin delegate for the given resource, or NULL if the
+ // resource has outlived its instance.
+ static PluginDelegate* GetPluginDelegate(const ::ppapi::Resource* resource);
+
+ // Returns the instance implementation object for the pp_instance.
+ static PluginInstanceImpl* PPInstanceToPluginInstance(PP_Instance instance);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceHelper);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_RESOURCE_IMPL_HELPER_H_
diff --git a/content/renderer/pepper/url_request_info_util.cc b/content/renderer/pepper/url_request_info_util.cc
new file mode 100644
index 0000000..08fc076
--- /dev/null
+++ b/content/renderer/pepper/url_request_info_util.cc
@@ -0,0 +1,205 @@
+// 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/url_request_info_util.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "content/renderer/pepper/common.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/ppb_file_ref_impl.h"
+#include "content/renderer/pepper/resource_helper.h"
+#include "net/http/http_util.h"
+#include "ppapi/shared_impl/url_request_info_data.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/thunk/enter.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebHTTPBody.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "url/gurl.h"
+#include "url/url_util.h"
+#include "webkit/child/weburlrequest_extradata_impl.h"
+
+using ppapi::URLRequestInfoData;
+using ppapi::Resource;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_FileRef_API;
+using WebKit::WebData;
+using WebKit::WebHTTPBody;
+using WebKit::WebString;
+using WebKit::WebFrame;
+using WebKit::WebURL;
+using WebKit::WebURLRequest;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+// Appends the file ref given the Resource pointer associated with it to the
+// given HTTP body, returning true on success.
+bool AppendFileRefToBody(
+ Resource* file_ref_resource,
+ int64_t start_offset,
+ int64_t number_of_bytes,
+ PP_Time expected_last_modified_time,
+ WebHTTPBody *http_body) {
+ // Get the underlying file ref impl.
+ if (!file_ref_resource)
+ return false;
+ PPB_FileRef_API* file_ref_api = file_ref_resource->AsPPB_FileRef_API();
+ if (!file_ref_api)
+ return false;
+ const PPB_FileRef_Impl* file_ref =
+ static_cast<PPB_FileRef_Impl*>(file_ref_api);
+
+ PluginDelegate* plugin_delegate =
+ ResourceHelper::GetPluginDelegate(file_ref_resource);
+ if (!plugin_delegate)
+ return false;
+
+ base::FilePath platform_path;
+ switch (file_ref->GetFileSystemType()) {
+ case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
+ case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
+ // TODO(kinuko): remove this sync IPC when we fully support
+ // AppendURLRange for FileSystem URL.
+ plugin_delegate->SyncGetFileSystemPlatformPath(
+ file_ref->GetFileSystemURL(), &platform_path);
+ break;
+ case PP_FILESYSTEMTYPE_EXTERNAL:
+ platform_path = file_ref->GetSystemPath();
+ break;
+ default:
+ NOTREACHED();
+ }
+ http_body->appendFileRange(
+ platform_path.AsUTF16Unsafe(),
+ start_offset,
+ number_of_bytes,
+ expected_last_modified_time);
+ return true;
+}
+
+// Checks that the request data is valid. Returns false on failure. Note that
+// method and header validation is done by the URL loader when the request is
+// opened, and any access errors are returned asynchronously.
+bool ValidateURLRequestData(const ::ppapi::URLRequestInfoData& data) {
+ if (data.prefetch_buffer_lower_threshold < 0 ||
+ data.prefetch_buffer_upper_threshold < 0 ||
+ data.prefetch_buffer_upper_threshold <=
+ data.prefetch_buffer_lower_threshold) {
+ return false;
+ }
+ return true;
+}
+
+// Ensures that the file_ref members of the given request info data are
+// populated from the resource IDs. Returns true on success.
+bool EnsureFileRefObjectsPopulated(::ppapi::URLRequestInfoData* data) {
+ // Get the Resource objects for any file refs with only host resource (this
+ // is the state of the request as it comes off IPC).
+ for (size_t i = 0; i < data->body.size(); ++i) {
+ URLRequestInfoData::BodyItem& item = data->body[i];
+ if (item.is_file && !item.file_ref.get()) {
+ EnterResourceNoLock<PPB_FileRef_API> enter(
+ item.file_ref_host_resource.host_resource(), false);
+ if (!enter.succeeded())
+ return false;
+ item.file_ref = enter.resource();
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+bool CreateWebURLRequest(::ppapi::URLRequestInfoData* data,
+ WebFrame* frame,
+ WebURLRequest* dest) {
+ // In the out-of-process case, we've received the URLRequestInfoData
+ // from the untrusted plugin and done no validation on it. We need to be
+ // sure it's not being malicious by checking everything for consistency.
+ if (!ValidateURLRequestData(*data) || !EnsureFileRefObjectsPopulated(data))
+ return false;
+
+ dest->initialize();
+ dest->setTargetType(WebURLRequest::TargetIsObject);
+ dest->setURL(frame->document().completeURL(WebString::fromUTF8(
+ data->url)));
+ dest->setDownloadToFile(data->stream_to_file);
+ dest->setReportUploadProgress(data->record_upload_progress);
+
+ if (!data->method.empty())
+ dest->setHTTPMethod(WebString::fromUTF8(data->method));
+
+ dest->setFirstPartyForCookies(frame->document().firstPartyForCookies());
+
+ const std::string& headers = data->headers;
+ if (!headers.empty()) {
+ net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n\r");
+ while (it.GetNext()) {
+ dest->addHTTPHeaderField(
+ WebString::fromUTF8(it.name()),
+ WebString::fromUTF8(it.values()));
+ }
+ }
+
+ // Append the upload data.
+ if (!data->body.empty()) {
+ WebHTTPBody http_body;
+ http_body.initialize();
+ for (size_t i = 0; i < data->body.size(); ++i) {
+ const URLRequestInfoData::BodyItem& item = data->body[i];
+ if (item.is_file) {
+ if (!AppendFileRefToBody(item.file_ref.get(),
+ item.start_offset,
+ item.number_of_bytes,
+ item.expected_last_modified_time,
+ &http_body))
+ return false;
+ } else {
+ DCHECK(!item.data.empty());
+ http_body.appendData(WebData(item.data));
+ }
+ }
+ dest->setHTTPBody(http_body);
+ }
+
+ // Add the "Referer" header if there is a custom referrer. Such requests
+ // require universal access. For all other requests, "Referer" will be set
+ // after header security checks are done in AssociatedURLLoader.
+ if (data->has_custom_referrer_url && !data->custom_referrer_url.empty())
+ frame->setReferrerForRequest(*dest, GURL(data->custom_referrer_url));
+
+ if (data->has_custom_content_transfer_encoding &&
+ !data->custom_content_transfer_encoding.empty()) {
+ dest->addHTTPHeaderField(
+ WebString::fromUTF8("Content-Transfer-Encoding"),
+ WebString::fromUTF8(data->custom_content_transfer_encoding));
+ }
+
+ if (data->has_custom_user_agent) {
+ dest->setExtraData(new webkit_glue::WebURLRequestExtraDataImpl(
+ WebKit::WebReferrerPolicyDefault, // Ignored.
+ WebString::fromUTF8(data->custom_user_agent)));
+ }
+
+ return true;
+}
+
+bool URLRequestRequiresUniversalAccess(
+ const ::ppapi::URLRequestInfoData& data) {
+ return
+ data.has_custom_referrer_url ||
+ data.has_custom_content_transfer_encoding ||
+ data.has_custom_user_agent ||
+ url_util::FindAndCompareScheme(data.url, "javascript", NULL);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/url_request_info_util.h b/content/renderer/pepper/url_request_info_util.h
new file mode 100644
index 0000000..88cabc8
--- /dev/null
+++ b/content/renderer/pepper/url_request_info_util.h
@@ -0,0 +1,38 @@
+// 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_PEPPER_URL_REQUEST_INFO_UTIL_H_
+#define CONTENT_RENDERER_PEPPER_URL_REQUEST_INFO_UTIL_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+
+namespace ppapi {
+struct URLRequestInfoData;
+}
+
+namespace WebKit {
+class WebFrame;
+class WebURLRequest;
+}
+
+namespace webkit {
+namespace ppapi {
+
+// Creates the WebKit URL request from the current request info. Returns true
+// on success, false if the request is invalid (in which case *dest may be
+// partially initialized). Any upload files with only resource IDs (no file ref
+// pointers) will be populated by this function on success.
+CONTENT_EXPORT bool CreateWebURLRequest(::ppapi::URLRequestInfoData* data,
+ WebKit::WebFrame* frame,
+ WebKit::WebURLRequest* dest);
+
+// Returns true if universal access is required to use the given request.
+CONTENT_EXPORT bool URLRequestRequiresUniversalAccess(
+ const ::ppapi::URLRequestInfoData& data);
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_PPB_URL_REQUEST_INFO_UTIL_H_
diff --git a/content/renderer/pepper/url_response_info_util.cc b/content/renderer/pepper/url_response_info_util.cc
index ddfa0f2..f07a9b9 100644
--- a/content/renderer/pepper/url_response_info_util.cc
+++ b/content/renderer/pepper/url_response_info_util.cc
@@ -5,13 +5,13 @@
#include "content/renderer/pepper/url_response_info_util.h"
#include "base/files/file_path.h"
+#include "content/renderer/pepper/ppb_file_ref_impl.h"
#include "ppapi/shared_impl/url_response_info_data.h"
#include "third_party/WebKit/public/platform/WebCString.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/WebURLResponse.h"
-#include "webkit/plugins/ppapi/ppb_file_ref_impl.h"
using webkit::ppapi::PPB_FileRef_Impl;
using WebKit::WebHTTPHeaderVisitor;
diff --git a/content/renderer/pepper/usb_key_code_conversion.cc b/content/renderer/pepper/usb_key_code_conversion.cc
new file mode 100644
index 0000000..2640417
--- /dev/null
+++ b/content/renderer/pepper/usb_key_code_conversion.cc
@@ -0,0 +1,23 @@
+// 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 WebKit::WebKeyboardEvent;
+
+namespace webkit {
+namespace ppapi {
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN)
+
+uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
+ return 0;
+}
+
+#endif
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/usb_key_code_conversion.h b/content/renderer/pepper/usb_key_code_conversion.h
new file mode 100644
index 0000000..459e662
--- /dev/null
+++ b/content/renderer/pepper/usb_key_code_conversion.h
@@ -0,0 +1,27 @@
+// 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 WebKit {
+class WebKeyboardEvent;
+} // namespace WebKit
+
+namespace webkit {
+namespace ppapi {
+
+// 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 WebKit::WebKeyboardEvent& key_event);
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_USB_KEY_CODE_CONVERSION_H_
diff --git a/content/renderer/pepper/usb_key_code_conversion_linux.cc b/content/renderer/pepper/usb_key_code_conversion_linux.cc
new file mode 100644
index 0000000..fd5e2b1
--- /dev/null
+++ b/content/renderer/pepper/usb_key_code_conversion_linux.cc
@@ -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.
+
+#include "content/renderer/pepper/usb_key_code_conversion.h"
+
+#include "base/basictypes.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+using WebKit::WebKeyboardEvent;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+#define USB_KEYMAP(usb, xkb, win, mac) {usb, xkb}
+#include "ui/base/keycodes/usb_keycode_map.h"
+#undef USB_KEYMAP
+
+} // anonymous namespace
+
+uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
+ // TODO(garykac): This code assumes that on Linux we're receiving events via
+ // the XKB driver. We should detect between "XKB", "kbd" and "evdev" at
+ // run-time and re-map accordingly, but that's not possible here, inside the
+ // sandbox.
+ return NativeKeycodeToUsbKeycode(key_event.nativeKeyCode);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/usb_key_code_conversion_mac.cc b/content/renderer/pepper/usb_key_code_conversion_mac.cc
new file mode 100644
index 0000000..4f55366
--- /dev/null
+++ b/content/renderer/pepper/usb_key_code_conversion_mac.cc
@@ -0,0 +1,28 @@
+// 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 "base/basictypes.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+using WebKit::WebKeyboardEvent;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+#define USB_KEYMAP(usb, xkb, win, mac) {usb, mac}
+#include "ui/base/keycodes/usb_keycode_map.h"
+#undef USB_KEYMAP
+
+} // anonymous namespace
+
+uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
+ return NativeKeycodeToUsbKeycode(key_event.nativeKeyCode);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/usb_key_code_conversion_win.cc b/content/renderer/pepper/usb_key_code_conversion_win.cc
new file mode 100644
index 0000000..5ef1d81
--- /dev/null
+++ b/content/renderer/pepper/usb_key_code_conversion_win.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.
+
+#include "content/renderer/pepper/usb_key_code_conversion.h"
+
+#include "base/basictypes.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+using WebKit::WebKeyboardEvent;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+#define USB_KEYMAP(usb, xkb, win, mac) {usb, win}
+#include "ui/base/keycodes/usb_keycode_map.h"
+#undef USB_KEYMAP
+
+} // anonymous namespace
+
+uint32_t UsbKeyCodeForKeyboardEvent(const WebKeyboardEvent& key_event) {
+ // Extract the scancode and extended bit from the native key event's lParam.
+ int scancode = (key_event.nativeKeyCode >> 16) & 0x000000FF;
+ if ((key_event.nativeKeyCode & (1 << 24)) != 0)
+ scancode |= 0xe000;
+
+ return NativeKeycodeToUsbKeycode(scancode);
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc
new file mode 100644
index 0000000..202a7cc
--- /dev/null
+++ b/content/renderer/pepper/v8_var_converter.cc
@@ -0,0 +1,470 @@
+// 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/pepper/v8_var_converter.h"
+
+#include <map>
+#include <stack>
+#include <string>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/renderer/pepper/host_array_buffer_var.h"
+#include "ppapi/shared_impl/array_var.h"
+#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"
+
+using ppapi::ArrayBufferVar;
+using ppapi::ArrayVar;
+using ppapi::DictionaryVar;
+using ppapi::ScopedPPVar;
+using ppapi::StringVar;
+using std::make_pair;
+
+namespace {
+
+template <class T>
+struct StackEntry {
+ StackEntry(T v) : val(v), sentinel(false) {}
+ T val;
+ // Used to track parent nodes on the stack while traversing the graph.
+ bool sentinel;
+};
+
+struct HashedHandle {
+ HashedHandle(v8::Handle<v8::Object> h) : handle(h) {}
+ size_t hash() const { return handle->GetIdentityHash(); }
+ bool operator==(const HashedHandle& h) const { return handle == h.handle; }
+ bool operator<(const HashedHandle& h) const { return hash() < h.hash(); }
+ v8::Handle<v8::Object> handle;
+};
+
+} // namespace
+
+namespace BASE_HASH_NAMESPACE {
+#if defined(COMPILER_GCC)
+template <>
+struct hash<HashedHandle> {
+ size_t operator()(const HashedHandle& handle) const {
+ return handle.hash();
+ }
+};
+#elif defined(COMPILER_MSVC)
+inline size_t hash_value(const HashedHandle& handle) {
+ return handle.hash();
+}
+#endif
+} // namespace BASE_HASH_NAMESPACE
+
+namespace webkit {
+namespace ppapi {
+namespace V8VarConverter {
+
+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_set<int64_t> ParentVarSet;
+
+// Maps V8 value handles to the PP_Var they correspond to.
+typedef base::hash_map<HashedHandle, ScopedPPVar> HandleVarMap;
+typedef base::hash_set<HashedHandle> ParentHandleSet;
+
+// Returns a V8 value which corresponds to a given PP_Var. If |var| is a
+// reference counted PP_Var type, and it exists in |visited_ids|, the V8 value
+// 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(const PP_Var& var,
+ v8::Handle<v8::Value>* result,
+ bool* did_create,
+ VarHandleMap* visited_ids,
+ ParentVarSet* parent_ids) {
+ *did_create = false;
+
+ if (::ppapi::VarTracker::IsVarTypeRefcounted(var.type)) {
+ if (parent_ids->count(var.value.as_id) != 0)
+ return false;
+ VarHandleMap::iterator it = visited_ids->find(var.value.as_id);
+ if (it != visited_ids->end()) {
+ *result = it->second;
+ return true;
+ }
+ }
+
+ switch (var.type) {
+ case PP_VARTYPE_UNDEFINED:
+ *result = v8::Undefined();
+ break;
+ case PP_VARTYPE_NULL:
+ *result = v8::Null();
+ break;
+ case PP_VARTYPE_BOOL:
+ *result = (var.value.as_bool == PP_TRUE) ? v8::True() : v8::False();
+ break;
+ case PP_VARTYPE_INT32:
+ *result = v8::Integer::New(var.value.as_int);
+ break;
+ case PP_VARTYPE_DOUBLE:
+ *result = v8::Number::New(var.value.as_double);
+ break;
+ case PP_VARTYPE_STRING: {
+ StringVar* string = StringVar::FromPPVar(var);
+ if (!string) {
+ NOTREACHED();
+ result->Clear();
+ return false;
+ }
+ const std::string& value = string->value();
+ // Create a string object rather than a string primitive. This allows us
+ // to have multiple references to the same string in javascript, which
+ // matches the reference behavior of PP_Vars.
+ *result = v8::String::New(value.c_str(), value.size())->ToObject();
+ break;
+ }
+ case PP_VARTYPE_ARRAY_BUFFER: {
+ ArrayBufferVar* buffer = ArrayBufferVar::FromPPVar(var);
+ if (!buffer) {
+ NOTREACHED();
+ result->Clear();
+ return false;
+ }
+ HostArrayBufferVar* host_buffer =
+ static_cast<HostArrayBufferVar*>(buffer);
+ *result =
+ v8::Local<v8::Value>::New(host_buffer->webkit_buffer().toV8Value());
+ break;
+ }
+ case PP_VARTYPE_ARRAY:
+ *result = v8::Array::New();
+ break;
+ case PP_VARTYPE_DICTIONARY:
+ *result = v8::Object::New();
+ break;
+ case PP_VARTYPE_OBJECT:
+ NOTREACHED();
+ result->Clear();
+ return false;
+ }
+
+ *did_create = true;
+ if (::ppapi::VarTracker::IsVarTypeRefcounted(var.type))
+ (*visited_ids)[var.value.as_id] = *result;
+ return true;
+}
+
+// For a given V8 value handle, this returns a PP_Var which corresponds to it.
+// If the handle already exists in |visited_handles|, the PP_Var associated with
+// 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,
+ PP_Var* result,
+ bool* did_create,
+ HandleVarMap* visited_handles,
+ ParentHandleSet* parent_handles) {
+ CHECK(!val.IsEmpty());
+ *did_create = false;
+
+ // 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)
+ return false;
+
+ HandleVarMap::const_iterator it = visited_handles->find(
+ HashedHandle(val->ToObject()));
+ if (it != visited_handles->end()) {
+ *result = it->second.get();
+ return true;
+ }
+ }
+
+ 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()));
+ } else if (val->IsInt32()) {
+ *result = PP_MakeInt32(val->ToInt32()->Value());
+ } else if (val->IsNumber() || val->IsNumberObject()) {
+ *result = PP_MakeDouble(val->ToNumber()->Value());
+ } else if (val->IsString() || val->IsStringObject()) {
+ v8::String::Utf8Value utf8(val->ToString());
+ *result = StringVar::StringToPPVar(std::string(*utf8, utf8.length()));
+ } else if (val->IsArray()) {
+ *result = (new ArrayVar())->GetPPVar();
+ } else if (val->IsObject()) {
+ scoped_ptr<WebKit::WebArrayBuffer> web_array_buffer(
+ WebKit::WebArrayBuffer::createFromV8Value(val));
+ if (web_array_buffer.get()) {
+ scoped_refptr<HostArrayBufferVar> buffer_var(new HostArrayBufferVar(
+ *web_array_buffer));
+ *result = buffer_var->GetPPVar();
+ } else {
+ *result = (new DictionaryVar())->GetPPVar();
+ }
+ } else {
+ // Silently ignore the case where we can't convert to a Var as we may
+ // be trying to convert a type that doesn't have a corresponding
+ // PP_Var type.
+ return true;
+ }
+
+ *did_create = true;
+ if (val->IsObject() || val->IsString()) {
+ visited_handles->insert(make_pair(
+ HashedHandle(val->ToObject()),
+ ScopedPPVar(ScopedPPVar::PassRef(), *result)));
+ }
+ return true;
+}
+
+bool CanHaveChildren(PP_Var var) {
+ return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
+}
+
+} // namespace
+
+// To/FromV8Value use a stack-based DFS search to traverse V8/Var graph. Each
+// iteration, the top node on the stack examined. If the node has not been
+// visited yet (i.e. sentinel == false) then it is added to the list of parents
+// which contains all of the nodes on the path from the start node to the
+// current node. Each of the current nodes children are examined. If they appear
+// in the list of parents it means we have a cycle and we return NULL.
+// Otherwise, if they can have children, we add them to the stack. If the
+// node at the top of the stack has already been visited, then we pop it off the
+// stack and erase it from the list of parents.
+// static
+bool ToV8Value(const PP_Var& var,
+ v8::Handle<v8::Context> context,
+ v8::Handle<v8::Value>* result) {
+ v8::Context::Scope context_scope(context);
+ v8::HandleScope handle_scope;
+
+ VarHandleMap visited_ids;
+ ParentVarSet parent_ids;
+
+ std::stack<StackEntry<PP_Var> > stack;
+ stack.push(StackEntry<PP_Var>(var));
+ v8::Handle<v8::Value> root;
+ bool is_root = true;
+
+ while (!stack.empty()) {
+ const PP_Var& current_var = stack.top().val;
+ v8::Handle<v8::Value> current_v8;
+
+ if (stack.top().sentinel) {
+ stack.pop();
+ if (CanHaveChildren(current_var))
+ parent_ids.erase(current_var.value.as_id);
+ continue;
+ } else {
+ stack.top().sentinel = true;
+ }
+
+ bool did_create = false;
+ if (!GetOrCreateV8Value(current_var, &current_v8, &did_create,
+ &visited_ids, &parent_ids)) {
+ return false;
+ }
+
+ if (is_root) {
+ is_root = false;
+ root = current_v8;
+ }
+
+ // Add child nodes to the stack.
+ if (current_var.type == PP_VARTYPE_ARRAY) {
+ parent_ids.insert(current_var.value.as_id);
+ ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
+ if (!array_var) {
+ NOTREACHED();
+ return false;
+ }
+ DCHECK(current_v8->IsArray());
+ v8::Handle<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;
+ if (!GetOrCreateV8Value(child_var, &child_v8, &did_create,
+ &visited_ids, &parent_ids)) {
+ return false;
+ }
+ if (did_create && CanHaveChildren(child_var))
+ stack.push(child_var);
+ v8::TryCatch try_catch;
+ v8_array->Set(static_cast<uint32>(i), child_v8);
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Setter for index " << i << " threw an exception.";
+ return false;
+ }
+ }
+ } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
+ parent_ids.insert(current_var.value.as_id);
+ DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
+ if (!dict_var) {
+ NOTREACHED();
+ return false;
+ }
+ DCHECK(current_v8->IsObject());
+ v8::Handle<v8::Object> v8_object = current_v8->ToObject();
+
+ for (DictionaryVar::KeyValueMap::const_iterator iter =
+ dict_var->key_value_map().begin();
+ iter != dict_var->key_value_map().end();
+ ++iter) {
+ const std::string& key = iter->first;
+ const PP_Var& child_var = iter->second.get();
+ v8::Handle<v8::Value> child_v8;
+ if (!GetOrCreateV8Value(child_var, &child_v8, &did_create,
+ &visited_ids, &parent_ids)) {
+ return false;
+ }
+ if (did_create && CanHaveChildren(child_var))
+ stack.push(child_var);
+ v8::TryCatch try_catch;
+ v8_object->Set(v8::String::New(key.c_str(), key.length()), child_v8);
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Setter for property " << key.c_str() << " threw an "
+ << "exception.";
+ return false;
+ }
+ }
+ }
+ }
+
+ *result = handle_scope.Close(root);
+ return true;
+}
+
+bool FromV8Value(v8::Handle<v8::Value> val,
+ v8::Handle<v8::Context> context,
+ PP_Var* result) {
+ v8::Context::Scope context_scope(context);
+ v8::HandleScope handle_scope;
+
+ HandleVarMap visited_handles;
+ ParentHandleSet parent_handles;
+
+ std::stack<StackEntry<v8::Handle<v8::Value> > > stack;
+ stack.push(StackEntry<v8::Handle<v8::Value> >(val));
+ ScopedPPVar root;
+ bool is_root = true;
+
+ while (!stack.empty()) {
+ v8::Handle<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()));
+ continue;
+ } else {
+ stack.top().sentinel = true;
+ }
+
+ bool did_create = false;
+ if (!GetOrCreateVar(current_v8, &current_var, &did_create,
+ &visited_handles, &parent_handles)) {
+ return false;
+ }
+
+ if (is_root) {
+ is_root = false;
+ root = current_var;
+ }
+
+ // 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>();
+ parent_handles.insert(HashedHandle(v8_array));
+
+ ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
+ if (!array_var) {
+ NOTREACHED();
+ return false;
+ }
+
+ for (uint32 i = 0; i < v8_array->Length(); ++i) {
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Value> child_v8 = v8_array->Get(i);
+ if (try_catch.HasCaught())
+ return false;
+
+ if (!v8_array->HasRealIndexedProperty(i))
+ continue;
+
+ PP_Var child_var;
+ if (!GetOrCreateVar(child_v8, &child_var, &did_create,
+ &visited_handles, &parent_handles)) {
+ return false;
+ }
+ if (did_create && child_v8->IsObject())
+ stack.push(child_v8);
+
+ array_var->Set(i, child_var);
+ }
+ } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
+ DCHECK(current_v8->IsObject());
+ v8::Handle<v8::Object> v8_object = current_v8->ToObject();
+ parent_handles.insert(HashedHandle(v8_object));
+
+ DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
+ if (!dict_var) {
+ NOTREACHED();
+ return false;
+ }
+
+ v8::Handle<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));
+
+ // Extend this test to cover more types as necessary and if sensible.
+ if (!key->IsString() && !key->IsNumber()) {
+ NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" "
+ "is neither a string nor a number";
+ return false;
+ }
+
+ // Skip all callbacks: crbug.com/139933
+ if (v8_object->HasRealNamedCallbackProperty(key->ToString()))
+ continue;
+
+ v8::String::Utf8Value name_utf8(key->ToString());
+
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Value> child_v8 = v8_object->Get(key);
+ if (try_catch.HasCaught())
+ return false;
+
+ PP_Var child_var;
+ if (!GetOrCreateVar(child_v8, &child_var, &did_create,
+ &visited_handles, &parent_handles)) {
+ return false;
+ }
+ if (did_create && child_v8->IsObject())
+ stack.push(child_v8);
+
+ bool success = dict_var->SetWithStringKey(
+ std::string(*name_utf8, name_utf8.length()), child_var);
+ DCHECK(success);
+ }
+ }
+ }
+ *result = root.Release();
+ return true;
+}
+
+} // namespace V8VarConverter
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/pepper/v8_var_converter.h b/content/renderer/pepper/v8_var_converter.h
new file mode 100644
index 0000000..2a07bfb
--- /dev/null
+++ b/content/renderer/pepper/v8_var_converter.h
@@ -0,0 +1,35 @@
+// 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_PEPPER_V8_VAR_CONVERTER_H
+#define CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H
+
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ppapi/c/pp_var.h"
+#include "v8/include/v8.h"
+#include "content/common/content_export.h"
+
+namespace webkit {
+namespace ppapi {
+namespace V8VarConverter {
+
+// Converts the given PP_Var to a v8::Value. True is returned upon success.
+bool CONTENT_EXPORT ToV8Value(const PP_Var& var,
+ v8::Handle<v8::Context> context,
+ v8::Handle<v8::Value>* result);
+// Converts the given v8::Value to a PP_Var. True is returned upon success.
+// Every PP_Var in the reference graph of which |result| is apart will have
+// a refcount equal to the number of references to it in the graph. |result|
+// will have one additional reference.
+bool CONTENT_EXPORT FromV8Value(v8::Handle<v8::Value> val,
+ v8::Handle<v8::Context> context,
+ PP_Var* result);
+
+} // namespace V8VarConverter
+} // namespace ppapi
+} // namespace webkit
+
+#endif // CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H
diff --git a/content/renderer/pepper/v8_var_converter_unittest.cc b/content/renderer/pepper/v8_var_converter_unittest.cc
new file mode 100644
index 0000000..794c665
--- /dev/null
+++ b/content/renderer/pepper/v8_var_converter_unittest.cc
@@ -0,0 +1,387 @@
+// 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/v8_var_converter.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/shared_impl/array_var.h"
+#include "ppapi/shared_impl/dictionary_var.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#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/var.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+using ppapi::ArrayBufferVar;
+using ppapi::ArrayVar;
+using ppapi::DictionaryVar;
+using ppapi::PpapiGlobals;
+using ppapi::ProxyLock;
+using ppapi::ScopedPPVar;
+using ppapi::StringVar;
+using ppapi::TestGlobals;
+using ppapi::TestEqual;
+using ppapi::VarTracker;
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+// Maps PP_Var IDs to the V8 value handle they correspond to.
+typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap;
+
+bool Equals(const PP_Var& var,
+ v8::Handle<v8::Value> val,
+ VarHandleMap* visited_ids) {
+ if (::ppapi::VarTracker::IsVarTypeRefcounted(var.type)) {
+ VarHandleMap::iterator it = visited_ids->find(var.value.as_id);
+ if (it != visited_ids->end())
+ return it->second == val;
+ (*visited_ids)[var.value.as_id] = val;
+ }
+
+ 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;
+ } else if (val->IsInt32()) {
+ return var.type == PP_VARTYPE_INT32 &&
+ val->ToInt32()->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;
+ } 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());
+ 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>();
+ 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);
+ if (!Equals(array_var->elements()[i].get(), child_v8, visited_ids))
+ return false;
+ }
+ return true;
+ } else if (val->IsObject()) {
+ if (var.type == PP_VARTYPE_ARRAY_BUFFER) {
+ // TODO(raymes): Implement this when we have tests for array buffers.
+ NOTIMPLEMENTED();
+ return false;
+ } else {
+ v8::Handle<v8::Object> v8_object = val->ToObject();
+ 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());
+ 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));
+
+ if (!key->IsString() && !key->IsNumber())
+ return false;
+ v8::Handle<v8::Value> child_v8 = v8_object->Get(key);
+
+ v8::String::Utf8Value name_utf8(key->ToString());
+ ScopedPPVar release_key(ScopedPPVar::PassRef(),
+ StringVar::StringToPPVar(
+ std::string(*name_utf8, name_utf8.length())));
+ if (!dict_var->HasKey(release_key.get()))
+ return false;
+ ScopedPPVar release_value(ScopedPPVar::PassRef(),
+ dict_var->Get(release_key.get()));
+ if (!Equals(release_value.get(), child_v8, visited_ids))
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Equals(const PP_Var& var,
+ v8::Handle<v8::Value> val) {
+ VarHandleMap var_handle_map;
+ return Equals(var, val, &var_handle_map);
+}
+
+class V8VarConverterTest : public testing::Test {
+ public:
+ V8VarConverterTest()
+ : isolate_(v8::Isolate::GetCurrent()) {}
+ virtual ~V8VarConverterTest() {}
+
+ // testing::Test implementation.
+ virtual void SetUp() {
+ ProxyLock::Acquire();
+ v8::HandleScope handle_scope(isolate_);
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
+ }
+ virtual void TearDown() {
+ context_.Dispose();
+ ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
+ ProxyLock::Release();
+ }
+
+ protected:
+ bool RoundTrip(const PP_Var& var, PP_Var* result) {
+ v8::HandleScope handle_scope(isolate_);
+ v8::Context::Scope context_scope(isolate_, context_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+ v8::Handle<v8::Value> v8_result;
+ if (!V8VarConverter::ToV8Value(var, context, &v8_result))
+ return false;
+ if (!Equals(var, v8_result))
+ return false;
+ if (!V8VarConverter::FromV8Value(v8_result, context, result))
+ return false;
+ return true;
+ }
+
+ // Assumes a ref for var.
+ bool RoundTripAndCompare(const PP_Var& var) {
+ ScopedPPVar expected(ScopedPPVar::PassRef(), var);
+ PP_Var actual_var;
+ if (!RoundTrip(expected.get(), &actual_var))
+ return false;
+ ScopedPPVar actual(ScopedPPVar::PassRef(), actual_var);
+ return TestEqual(expected.get(), actual.get());
+ }
+
+ v8::Isolate* isolate_;
+
+ // Context for the JavaScript in the test.
+ v8::Persistent<v8::Context> context_;
+
+ private:
+ TestGlobals globals_;
+};
+
+} // namespace
+
+TEST_F(V8VarConverterTest, SimpleRoundTripTest) {
+ EXPECT_TRUE(RoundTripAndCompare(PP_MakeUndefined()));
+ EXPECT_TRUE(RoundTripAndCompare(PP_MakeNull()));
+ EXPECT_TRUE(RoundTripAndCompare(PP_MakeInt32(100)));
+ EXPECT_TRUE(RoundTripAndCompare(PP_MakeBool(PP_TRUE)));
+ EXPECT_TRUE(RoundTripAndCompare(PP_MakeDouble(53.75)));
+}
+
+TEST_F(V8VarConverterTest, StringRoundTripTest) {
+ EXPECT_TRUE(RoundTripAndCompare(StringVar::StringToPPVar("")));
+ EXPECT_TRUE(RoundTripAndCompare(StringVar::StringToPPVar("hello world!")));
+}
+
+TEST_F(V8VarConverterTest, ArrayBufferRoundTripTest) {
+ // TODO(raymes): Testing this here requires spinning up some of WebKit.
+ // Work out how to do this.
+}
+
+TEST_F(V8VarConverterTest, DictionaryArrayRoundTripTest) {
+ // Empty array.
+ scoped_refptr<ArrayVar> array(new ArrayVar);
+ ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
+ EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
+
+ size_t index = 0;
+
+ // Array with primitives.
+ array->Set(index++, PP_MakeUndefined());
+ array->Set(index++, PP_MakeNull());
+ array->Set(index++, PP_MakeInt32(100));
+ array->Set(index++, PP_MakeBool(PP_FALSE));
+ array->Set(index++, PP_MakeDouble(0.123));
+ EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
+
+ // Array with 2 references to the same string.
+ ScopedPPVar release_string(
+ ScopedPPVar::PassRef(), StringVar::StringToPPVar("abc"));
+ array->Set(index++, release_string.get());
+ array->Set(index++, release_string.get());
+ EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
+
+ // Array with nested array that references the same string.
+ scoped_refptr<ArrayVar> array2(new ArrayVar);
+ ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar());
+ array2->Set(0, release_string.get());
+ array->Set(index++, release_array2.get());
+ EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
+
+ // Empty dictionary.
+ scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
+ ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
+ dictionary->GetPPVar());
+ EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
+
+ // Dictionary with primitives.
+ dictionary->SetWithStringKey("1", PP_MakeUndefined());
+ dictionary->SetWithStringKey("2", PP_MakeNull());
+ dictionary->SetWithStringKey("3", PP_MakeInt32(-100));
+ dictionary->SetWithStringKey("4", PP_MakeBool(PP_TRUE));
+ dictionary->SetWithStringKey("5", PP_MakeDouble(-103.52));
+ EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
+
+ // Dictionary with 2 references to the same string.
+ dictionary->SetWithStringKey("6", release_string.get());
+ dictionary->SetWithStringKey("7", release_string.get());
+ EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
+
+ // Dictionary with nested dictionary that references the same string.
+ scoped_refptr<DictionaryVar> dictionary2(new DictionaryVar);
+ ScopedPPVar release_dictionary2(ScopedPPVar::PassRef(),
+ dictionary2->GetPPVar());
+ dictionary2->SetWithStringKey("abc", release_string.get());
+ dictionary->SetWithStringKey("8", release_dictionary2.get());
+ EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
+
+ // Array with dictionary.
+ array->Set(index++, release_dictionary.get());
+ EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
+
+ // Array with dictionary with array.
+ array2->Set(0, PP_MakeInt32(100));
+ dictionary->SetWithStringKey("9", release_array2.get());
+ EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
+}
+
+TEST_F(V8VarConverterTest, Cycles) {
+ // Check that cycles aren't converted.
+ v8::HandleScope handle_scope(isolate_);
+ v8::Context::Scope context_scope(isolate_, context_);
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Context>::New(isolate_, context_);
+
+ // Var->V8 conversion.
+ {
+ scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
+ ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
+ dictionary->GetPPVar());
+ scoped_refptr<ArrayVar> array(new ArrayVar);
+ ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
+
+ dictionary->SetWithStringKey("1", release_array.get());
+ array->Set(0, release_dictionary.get());
+
+ v8::Handle<v8::Value> v8_result;
+
+ // Array <-> dictionary cycle.
+ dictionary->SetWithStringKey("1", release_array.get());
+ ASSERT_FALSE(V8VarConverter::ToV8Value(release_dictionary.get(),
+ context, &v8_result));
+ // Break the cycle.
+ // TODO(raymes): We need some better machinery for releasing vars with
+ // cycles. Remove the code below once we have that.
+ dictionary->DeleteWithStringKey("1");
+
+ // Array with self reference.
+ array->Set(0, release_array.get());
+ ASSERT_FALSE(V8VarConverter::ToV8Value(release_array.get(),
+ context, &v8_result));
+ // Break the self reference.
+ array->Set(0, PP_MakeUndefined());
+ }
+
+ // V8->Var conversion.
+ {
+ v8::Handle<v8::Object> object = v8::Object::New();
+ v8::Handle<v8::Array> array = v8::Array::New();
+
+ PP_Var var_result;
+
+ // Array <-> dictionary cycle.
+ std::string key = "1";
+ object->Set(v8::String::New(key.c_str(), key.length()), array);
+ array->Set(0, object);
+
+ ASSERT_FALSE(V8VarConverter::FromV8Value(object, context, &var_result));
+
+ // Array with self reference.
+ array->Set(0, array);
+ ASSERT_FALSE(V8VarConverter::FromV8Value(array, context, &var_result));
+ }
+}
+
+TEST_F(V8VarConverterTest, StrangeDictionaryKeyTest) {
+ {
+ // Test keys with '.'.
+ scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
+ dictionary->SetWithStringKey(".", PP_MakeUndefined());
+ dictionary->SetWithStringKey("x.y", PP_MakeUndefined());
+ EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
+ }
+
+ {
+ // Test non-string key types. They should be cast to strings.
+ v8::HandleScope handle_scope(isolate_);
+ v8::Context::Scope context_scope(isolate_, 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::New(v8::String::New(source)));
+ v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+
+ PP_Var actual;
+ ASSERT_TRUE(V8VarConverter::FromV8Value(object,
+ v8::Local<v8::Context>::New(isolate_, context_), &actual));
+ ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual);
+
+ scoped_refptr<DictionaryVar> expected(new DictionaryVar);
+ ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo"));
+ expected->SetWithStringKey("1", foo.get());
+ ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar"));
+ expected->SetWithStringKey("2", bar.get());
+ ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz"));
+ expected->SetWithStringKey("true", baz.get());
+ ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux"));
+ expected->SetWithStringKey("false", qux.get());
+ ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux"));
+ expected->SetWithStringKey("null", quux.get());
+ ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops"));
+ expected->SetWithStringKey("undefined", oops.get());
+ ScopedPPVar release_expected(
+ ScopedPPVar::PassRef(), expected->GetPPVar());
+
+ ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get()));
+ }
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index e3976f6..fa49316 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -31,6 +31,7 @@
#include "content/renderer/gpu/mailbox_output_surface.h"
#include "content/renderer/gpu/render_widget_compositor.h"
#include "content/renderer/ime_event_guard.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/render_process.h"
#include "content/renderer/render_process_visibility_manager.h"
#include "content/renderer/render_thread_impl.h"
@@ -57,7 +58,6 @@
#include "ui/gfx/skia_util.h"
#include "ui/gl/gl_switches.h"
#include "ui/surface/transport_dib.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
#include "webkit/renderer/compositor_bindings/web_rendering_stats_impl.h"
#include "webkit/renderer/cursor_utils.h"
@@ -971,6 +971,7 @@ void RenderWidget::PaintRect(const gfx::Rect& rect,
&optimized_copy_rect,
&dib_scale_factor);
if (optimized_instance) {
+#if defined(ENABLE_PLUGINS)
// This plugin can be optimize-painted and we can just ask it to paint
// itself. We don't actually need the TransportDIB in this case.
//
@@ -1005,6 +1006,7 @@ void RenderWidget::PaintRect(const gfx::Rect& rect,
if (!is_accelerated_compositing_active_)
software_stats_.total_paint_time += paint_time;
}
+#endif
} else {
// Normal painting case.
base::TimeTicks paint_begin_ticks;
diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc
index 80a6128..1eb0ff9 100644
--- a/content/renderer/render_widget_fullscreen_pepper.cc
+++ b/content/renderer/render_widget_fullscreen_pepper.cc
@@ -14,6 +14,8 @@
#include "content/public/common/content_switches.h"
#include "content/renderer/gpu/render_widget_compositor.h"
#include "content/renderer/pepper/pepper_platform_context_3d_impl.h"
+#include "content/renderer/pepper/plugin_delegate.h"
+#include "content/renderer/pepper/ppapi_plugin_instance_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "skia/ext/platform_canvas.h"
@@ -25,8 +27,6 @@
#include "third_party/WebKit/public/web/WebWidget.h"
#include "ui/gfx/size_conversions.h"
#include "ui/gl/gpu_preference.h"
-#include "webkit/plugins/ppapi/plugin_delegate.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h"
using WebKit::WebCanvas;
using WebKit::WebCompositionUnderline;
diff --git a/content/renderer/render_widget_fullscreen_pepper.h b/content/renderer/render_widget_fullscreen_pepper.h
index 9e54548..840a979 100644
--- a/content/renderer/render_widget_fullscreen_pepper.h
+++ b/content/renderer/render_widget_fullscreen_pepper.h
@@ -7,9 +7,9 @@
#include "base/memory/scoped_ptr.h"
#include "content/renderer/mouse_lock_dispatcher.h"
+#include "content/renderer/pepper/fullscreen_container.h"
#include "content/renderer/render_widget_fullscreen.h"
#include "third_party/WebKit/public/web/WebWidget.h"
-#include "webkit/plugins/ppapi/fullscreen_container.h"
namespace webkit {
namespace ppapi {
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index 5c59ad1..5d34342 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -28,13 +28,13 @@
#include "content/public/common/main_function_params.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/browser_plugin/browser_plugin_manager_impl.h"
+#include "content/renderer/pepper/ppapi_interface_factory.h"
#include "content/renderer/render_process_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/renderer_main_platform_delegate.h"
#include "ui/base/ui_base_switches.h"
#include "webkit/child/webkit_child_helpers.h"
#include "webkit/glue/webkit_glue.h"
-#include "webkit/plugins/ppapi/ppapi_interface_factory.h"
#if defined(OS_MACOSX)
#include <Carbon/Carbon.h>
@@ -148,9 +148,6 @@ int RendererMain(const MainFunctionParams& parameters) {
RendererMainPlatformDelegate platform(parameters);
- webkit::ppapi::PpapiInterfaceFactoryManager* factory_manager =
- webkit::ppapi::PpapiInterfaceFactoryManager::GetInstance();
- factory_manager->RegisterFactory(ContentPPAPIInterfaceFactory);
base::StatsCounterTimer stats_counter_timer("Content.RendererInit");
base::StatsScope<base::StatsCounterTimer> startup_timer(stats_counter_timer);
@@ -205,6 +202,10 @@ int RendererMain(const MainFunctionParams& parameters) {
}
#if defined(ENABLE_PLUGINS)
+ webkit::ppapi::PpapiInterfaceFactoryManager* factory_manager =
+ webkit::ppapi::PpapiInterfaceFactoryManager::GetInstance();
+ factory_manager->RegisterFactory(ContentPPAPIInterfaceFactory);
+
// Load pepper plugins before engaging the sandbox.
PepperPluginRegistry::GetInstance();
#endif