diff options
author | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
---|---|---|
committer | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
commit | 679147eead574d186ebf3069647b4c23e8ccace6 (patch) | |
tree | fc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/ppapi/proxy | |
download | qtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz |
Initial import.
Diffstat (limited to 'chromium/ppapi/proxy')
233 files changed, 37522 insertions, 0 deletions
diff --git a/chromium/ppapi/proxy/DEPS b/chromium/ppapi/proxy/DEPS new file mode 100644 index 00000000000..e56cd3def11 --- /dev/null +++ b/chromium/ppapi/proxy/DEPS @@ -0,0 +1,22 @@ +include_rules = [ + "+base", + "+components/tracing", + "+gpu", + "+ipc", + "+media/audio", + "+skia", + "+ui/surface", + + # We don't want the proxy to depend on the C++ layer, which is appropriate + # for plugins only. However, the completion callback factory is a very useful + # tool that we would otherwise have to duplicate, and has no other + # dependencies, so we allow that (and the output traits it depends on). + "-ppapi/cpp", + "+ppapi/cpp/completion_callback.h", + "+ppapi/cpp/output_traits.h", + + # The untrusted build references the NaCl integrated runtime (IRT). + "+native_client/src/shared", + "+native_client/src/untrusted" +] + diff --git a/chromium/ppapi/proxy/OWNERS b/chromium/ppapi/proxy/OWNERS new file mode 100644 index 00000000000..7d2c40a5e8b --- /dev/null +++ b/chromium/ppapi/proxy/OWNERS @@ -0,0 +1,11 @@ +piman@chromium.org + +# Changes to IPC messages require a security review to avoid introducing +# new sandbox escapes. +per-file *_messages*.h=set noparent +per-file *_messages*.h=cdn@chromium.org +per-file *_messages*.h=cevans@chromium.org +per-file *_messages*.h=jln@chromium.org +per-file *_messages*.h=jschuh@chromium.org +per-file *_messages*.h=palmer@chromium.org +per-file *_messages*.h=tsepez@chromium.org diff --git a/chromium/ppapi/proxy/audio_input_resource.cc b/chromium/ppapi/proxy/audio_input_resource.cc new file mode 100644 index 00000000000..4a7afff1a2c --- /dev/null +++ b/chromium/ppapi/proxy/audio_input_resource.cc @@ -0,0 +1,314 @@ +// 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 "ppapi/proxy/audio_input_resource.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "ipc/ipc_platform_file.h" +#include "media/audio/audio_parameters.h" +#include "media/audio/shared_memory_util.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/serialized_handle.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/ppb_audio_config_shared.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_audio_config_api.h" + +namespace ppapi { +namespace proxy { + +AudioInputResource::AudioInputResource( + Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + open_state_(BEFORE_OPEN), + capturing_(false), + shared_memory_size_(0), + audio_input_callback_0_2_(NULL), + audio_input_callback_(NULL), + user_data_(NULL), + enumeration_helper_(this), + bytes_per_second_(0) { + SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create()); +} + +AudioInputResource::~AudioInputResource() { + Close(); +} + +thunk::PPB_AudioInput_API* AudioInputResource::AsPPB_AudioInput_API() { + return this; +} + +void AudioInputResource::OnReplyReceived( + const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + if (!enumeration_helper_.HandleReply(params, msg)) + PluginResource::OnReplyReceived(params, msg); +} + +int32_t AudioInputResource::EnumerateDevices0_2( + PP_Resource* devices, + scoped_refptr<TrackedCallback> callback) { + return enumeration_helper_.EnumerateDevices0_2(devices, callback); +} + +int32_t AudioInputResource::EnumerateDevices( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + return enumeration_helper_.EnumerateDevices(output, callback); +} + +int32_t AudioInputResource::MonitorDeviceChange( + PP_MonitorDeviceChangeCallback callback, + void* user_data) { + return enumeration_helper_.MonitorDeviceChange(callback, user_data); +} + +int32_t AudioInputResource::Open0_2( + PP_Resource device_ref, + PP_Resource config, + PPB_AudioInput_Callback_0_2 audio_input_callback_0_2, + void* user_data, + scoped_refptr<TrackedCallback> callback) { + return CommonOpen(device_ref, config, audio_input_callback_0_2, NULL, + user_data, callback); +} + +int32_t AudioInputResource::Open(PP_Resource device_ref, + PP_Resource config, + PPB_AudioInput_Callback audio_input_callback, + void* user_data, + scoped_refptr<TrackedCallback> callback) { + return CommonOpen(device_ref, config, NULL, audio_input_callback, user_data, + callback); +} + +PP_Resource AudioInputResource::GetCurrentConfig() { + // AddRef for the caller. + if (config_.get()) + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_); + return config_; +} + +PP_Bool AudioInputResource::StartCapture() { + if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN && + !TrackedCallback::IsPending(open_callback_))) { + return PP_FALSE; + } + if (capturing_) + return PP_TRUE; + + capturing_ = true; + // Return directly if the audio input device hasn't been opened. Capturing + // will be started once the open operation is completed. + if (open_state_ == BEFORE_OPEN) + return PP_TRUE; + + StartThread(); + + Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(true)); + return PP_TRUE; +} + +PP_Bool AudioInputResource::StopCapture() { + if (open_state_ == CLOSED) + return PP_FALSE; + if (!capturing_) + return PP_TRUE; + + // If the audio input device hasn't been opened, set |capturing_| to false and + // return directly. + if (open_state_ == BEFORE_OPEN) { + capturing_ = false; + return PP_TRUE; + } + + Post(RENDERER, PpapiHostMsg_AudioInput_StartOrStop(false)); + + StopThread(); + capturing_ = false; + + return PP_TRUE; +} + +void AudioInputResource::Close() { + if (open_state_ == CLOSED) + return; + + open_state_ = CLOSED; + Post(RENDERER, PpapiHostMsg_AudioInput_Close()); + StopThread(); + + if (TrackedCallback::IsPending(open_callback_)) + open_callback_->PostAbort(); +} + +void AudioInputResource::LastPluginRefWasDeleted() { + enumeration_helper_.LastPluginRefWasDeleted(); +} + +void AudioInputResource::OnPluginMsgOpenReply( + const ResourceMessageReplyParams& params) { + if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) { + IPC::PlatformFileForTransit socket_handle_for_transit = + IPC::InvalidPlatformFileForTransit(); + params.TakeSocketHandleAtIndex(0, &socket_handle_for_transit); + base::SyncSocket::Handle socket_handle = + IPC::PlatformFileForTransitToPlatformFile(socket_handle_for_transit); + CHECK(socket_handle != base::SyncSocket::kInvalidHandle); + + SerializedHandle serialized_shared_memory_handle = + params.TakeHandleOfTypeAtIndex(1, SerializedHandle::SHARED_MEMORY); + CHECK(serialized_shared_memory_handle.IsHandleValid()); + + // See the comment in pepper_audio_input_host.cc about how we must call + // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here, + // we must call PacketSizeInBytes to get back the size of the audio buffer, + // excluding the bytes that audio uses for book-keeping. + size_t shared_memory_size = media::PacketSizeInBytes( + serialized_shared_memory_handle.size()); + + open_state_ = OPENED; + SetStreamInfo(serialized_shared_memory_handle.shmem(), shared_memory_size, + socket_handle); + } else { + capturing_ = false; + } + + // The callback may have been aborted by Close(). + if (TrackedCallback::IsPending(open_callback_)) + open_callback_->Run(params.result()); +} + +void AudioInputResource::SetStreamInfo( + base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket_handle) { + socket_.reset(new base::CancelableSyncSocket(socket_handle)); + shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); + shared_memory_size_ = shared_memory_size; + + if (!shared_memory_->Map(shared_memory_size_)) { + PpapiGlobals::Get()->LogWithSource( + pp_instance(), + PP_LOGLEVEL_WARNING, + std::string(), + "Failed to map shared memory for PPB_AudioInput_Shared."); + } + + // There is a pending capture request before SetStreamInfo(). + if (capturing_) { + // Set |capturing_| to false so that the state looks consistent to + // StartCapture(), which will reset it to true. + capturing_ = false; + StartCapture(); + } +} + +void AudioInputResource::StartThread() { + // Don't start the thread unless all our state is set up correctly. + if ((!audio_input_callback_0_2_ && !audio_input_callback_) || + !socket_.get() || !capturing_ || !shared_memory_->memory()) { + return; + } + DCHECK(!audio_input_thread_.get()); + audio_input_thread_.reset(new base::DelegateSimpleThread( + this, "plugin_audio_input_thread")); + audio_input_thread_->Start(); +} + +void AudioInputResource::StopThread() { + // Shut down the socket to escape any hanging |Receive|s. + if (socket_.get()) + socket_->Shutdown(); + if (audio_input_thread_.get()) { + audio_input_thread_->Join(); + audio_input_thread_.reset(); + } +} + +void AudioInputResource::Run() { + // The shared memory represents AudioInputBufferParameters and the actual data + // buffer. + media::AudioInputBuffer* buffer = + static_cast<media::AudioInputBuffer*>(shared_memory_->memory()); + uint32_t data_buffer_size = + shared_memory_size_ - sizeof(media::AudioInputBufferParameters); + int pending_data; + + while (sizeof(pending_data) == socket_->Receive(&pending_data, + sizeof(pending_data)) && + pending_data >= 0) { + // While closing the stream, we may receive buffers whose size is different + // from |data_buffer_size|. + CHECK_LE(buffer->params.size, data_buffer_size); + if (buffer->params.size > 0) { + if (audio_input_callback_) { + PP_TimeDelta latency = + static_cast<double>(pending_data) / bytes_per_second_; + audio_input_callback_(&buffer->audio[0], buffer->params.size, latency, + user_data_); + } else { + audio_input_callback_0_2_(&buffer->audio[0], buffer->params.size, + user_data_); + } + } + } +} + +int32_t AudioInputResource::CommonOpen( + PP_Resource device_ref, + PP_Resource config, + PPB_AudioInput_Callback_0_2 audio_input_callback_0_2, + PPB_AudioInput_Callback audio_input_callback, + void* user_data, + scoped_refptr<TrackedCallback> callback) { + std::string device_id; + // |device_id| remains empty if |device_ref| is 0, which means the default + // device. + if (device_ref != 0) { + thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter_device_ref( + device_ref, true); + if (enter_device_ref.failed()) + return PP_ERROR_BADRESOURCE; + device_id = enter_device_ref.object()->GetDeviceRefData().id; + } + + if (TrackedCallback::IsPending(open_callback_)) + return PP_ERROR_INPROGRESS; + if (open_state_ != BEFORE_OPEN) + return PP_ERROR_FAILED; + + if (!audio_input_callback_0_2 && !audio_input_callback) + return PP_ERROR_BADARGUMENT; + thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config, + true); + if (enter_config.failed()) + return PP_ERROR_BADARGUMENT; + + config_ = config; + audio_input_callback_0_2_ = audio_input_callback_0_2; + audio_input_callback_ = audio_input_callback; + user_data_ = user_data; + open_callback_ = callback; + bytes_per_second_ = kAudioInputChannels * (kBitsPerAudioInputSample / 8) * + enter_config.object()->GetSampleRate(); + + PpapiHostMsg_AudioInput_Open msg( + device_id, enter_config.object()->GetSampleRate(), + enter_config.object()->GetSampleFrameCount()); + Call<PpapiPluginMsg_AudioInput_OpenReply>( + RENDERER, msg, + base::Bind(&AudioInputResource::OnPluginMsgOpenReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/audio_input_resource.h b/chromium/ppapi/proxy/audio_input_resource.h new file mode 100644 index 00000000000..84785d08052 --- /dev/null +++ b/chromium/ppapi/proxy/audio_input_resource.h @@ -0,0 +1,145 @@ +// 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_PROXY_AUDIO_INPUT_RESOURCE_H_ +#define PPAPI_PROXY_AUDIO_INPUT_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "base/sync_socket.h" +#include "base/threading/simple_thread.h" +#include "ppapi/proxy/device_enumeration_resource_helper.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/thunk/ppb_audio_input_api.h" + +namespace ppapi { +namespace proxy { + +class ResourceMessageReplyParams; + +class AudioInputResource : public PluginResource, + public thunk::PPB_AudioInput_API, + public base::DelegateSimpleThread::Delegate { + public: + AudioInputResource(Connection connection, PP_Instance instance); + virtual ~AudioInputResource(); + + // Resource overrides. + virtual thunk::PPB_AudioInput_API* AsPPB_AudioInput_API() OVERRIDE; + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + // PPB_AudioInput_API implementation. + virtual int32_t EnumerateDevices0_2( + PP_Resource* devices, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t EnumerateDevices( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t MonitorDeviceChange( + PP_MonitorDeviceChangeCallback callback, + void* user_data) OVERRIDE; + virtual int32_t Open0_2(PP_Resource device_ref, + PP_Resource config, + PPB_AudioInput_Callback_0_2 audio_input_callback_0_2, + void* user_data, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Open(PP_Resource device_ref, + PP_Resource config, + PPB_AudioInput_Callback audio_input_callback, + void* user_data, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Resource GetCurrentConfig() OVERRIDE; + virtual PP_Bool StartCapture() OVERRIDE; + virtual PP_Bool StopCapture() OVERRIDE; + virtual void Close() OVERRIDE; + + protected: + // Resource override. + virtual void LastPluginRefWasDeleted() OVERRIDE; + + private: + enum OpenState { + BEFORE_OPEN, + OPENED, + CLOSED + }; + + void OnPluginMsgOpenReply(const ResourceMessageReplyParams& params); + + // Sets the shared memory and socket handles. This will automatically start + // capture if we're currently set to capture. + void SetStreamInfo(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket_handle); + + // Starts execution of the audio input thread. + void StartThread(); + + // Stops execution of the audio input thread. + void StopThread(); + + // DelegateSimpleThread::Delegate implementation. + // Run on the audio input thread. + virtual void Run() OVERRIDE; + + int32_t CommonOpen(PP_Resource device_ref, + PP_Resource config, + PPB_AudioInput_Callback_0_2 audio_input_callback_0_2, + PPB_AudioInput_Callback audio_input_callback, + void* user_data, + scoped_refptr<TrackedCallback> callback); + + OpenState open_state_; + + // True if capturing the stream. + bool capturing_; + + // Socket used to notify us when new samples are available. This pointer is + // created in SetStreamInfo(). + scoped_ptr<base::CancelableSyncSocket> socket_; + + // Sample buffer in shared memory. This pointer is created in + // SetStreamInfo(). The memory is only mapped when the audio thread is + // created. + scoped_ptr<base::SharedMemory> shared_memory_; + + // The size of the sample buffer in bytes. + size_t shared_memory_size_; + + // When the callback is set, this thread is spawned for calling it. + scoped_ptr<base::DelegateSimpleThread> audio_input_thread_; + + // Callback to call when new samples are available. + PPB_AudioInput_Callback_0_2 audio_input_callback_0_2_; + PPB_AudioInput_Callback audio_input_callback_; + + // User data pointer passed verbatim to the callback function. + void* user_data_; + + // The callback is not directly passed to OnPluginMsgOpenReply() because we + // would like to be able to cancel it early in Close(). + scoped_refptr<TrackedCallback> open_callback_; + + // Owning reference to the current config object. This isn't actually used, + // we just dish it out as requested by the plugin. + ScopedPPResource config_; + + DeviceEnumerationResourceHelper enumeration_helper_; + + // The data size (in bytes) of one second of audio input. Used to calculate + // latency. + size_t bytes_per_second_; + + DISALLOW_COPY_AND_ASSIGN(AudioInputResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_AUDIO_INPUT_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/broker_dispatcher.cc b/chromium/ppapi/proxy/broker_dispatcher.cc new file mode 100644 index 00000000000..7187852ba26 --- /dev/null +++ b/chromium/ppapi/proxy/broker_dispatcher.cc @@ -0,0 +1,99 @@ +// 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 "ppapi/proxy/broker_dispatcher.h" + +#include "base/sync_socket.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/platform_file.h" + +namespace ppapi { +namespace proxy { + +BrokerDispatcher::BrokerDispatcher(PP_ConnectInstance_Func connect_instance) + : connect_instance_(connect_instance) { +} + +BrokerDispatcher::~BrokerDispatcher() { +} + +bool BrokerDispatcher::InitBrokerWithChannel( + ProxyChannel::Delegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + return ProxyChannel::InitWithChannel(delegate, peer_pid, channel_handle, + is_client); +} + +bool BrokerDispatcher::OnMessageReceived(const IPC::Message& msg) { + // Control messages. + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(BrokerDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_ConnectToPlugin, OnMsgConnectToPlugin) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; + } + return false; +} + +// Transfers ownership of the handle to the broker module. +void BrokerDispatcher::OnMsgConnectToPlugin( + PP_Instance instance, + IPC::PlatformFileForTransit handle, + int32_t* result) { + if (handle == IPC::InvalidPlatformFileForTransit()) { + *result = PP_ERROR_FAILED; + } else { + base::SyncSocket::Handle socket_handle = + IPC::PlatformFileForTransitToPlatformFile(handle); + + if (connect_instance_) { + *result = connect_instance_(instance, + ppapi::PlatformFileToInt(socket_handle)); + } else { + *result = PP_ERROR_FAILED; + // Close the handle since there is no other owner. + // The easiest way to clean it up is to just put it in an object + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket(socket_handle); + } + } +} + +BrokerHostDispatcher::BrokerHostDispatcher() + : BrokerDispatcher(NULL) { +} + +void BrokerHostDispatcher::OnChannelError() { + DVLOG(1) << "BrokerHostDispatcher::OnChannelError()"; + BrokerDispatcher::OnChannelError(); // Stop using the channel. + + // Tell the host about the crash so it can clean up and display notification. + // TODO(ddorwin): Add BrokerCrashed() to PPB_Proxy_Private and call it. + // ppb_proxy_->BrokerCrashed(pp_module()); +} + +BrokerSideDispatcher::BrokerSideDispatcher( + PP_ConnectInstance_Func connect_instance) + : BrokerDispatcher(connect_instance) { +} + +void BrokerSideDispatcher::OnChannelError() { + DVLOG(1) << "BrokerSideDispatcher::OnChannelError()"; + BrokerDispatcher::OnChannelError(); + + // The renderer has crashed or exited. This channel and all instances + // associated with it are no longer valid. + // TODO(ddorwin): This causes the broker process to exit, which may not be + // desirable in some use cases. + delete this; +} + + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/broker_dispatcher.h b/chromium/ppapi/proxy/broker_dispatcher.h new file mode 100644 index 00000000000..2da4a472ced --- /dev/null +++ b/chromium/ppapi/proxy/broker_dispatcher.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 PPAPI_PROXY_BROKER_DISPATCHER_H_ +#define PPAPI_PROXY_BROKER_DISPATCHER_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/trusted/ppp_broker.h" +#include "ppapi/proxy/proxy_channel.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT BrokerDispatcher : public ProxyChannel { + public: + virtual ~BrokerDispatcher(); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitBrokerWithChannel(ProxyChannel::Delegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + // IPC::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + protected: + // You must call InitBrokerWithChannel after the constructor. + explicit BrokerDispatcher(PP_ConnectInstance_Func connect_instance); + + void OnMsgConnectToPlugin(PP_Instance instance, + IPC::PlatformFileForTransit handle, + int32_t* result); + + PP_ConnectInstance_Func connect_instance_; + + private: + DISALLOW_COPY_AND_ASSIGN(BrokerDispatcher); +}; + +// The dispatcher for the browser side of the broker channel. +class PPAPI_PROXY_EXPORT BrokerHostDispatcher : public BrokerDispatcher { + public: + BrokerHostDispatcher(); + + // IPC::Listener implementation. + virtual void OnChannelError() OVERRIDE; +}; + +// The dispatcher for the broker side of the broker channel. +class PPAPI_PROXY_EXPORT BrokerSideDispatcher : public BrokerDispatcher { + public: + explicit BrokerSideDispatcher(PP_ConnectInstance_Func connect_instance); + + // IPC::Listener implementation. + virtual void OnChannelError() OVERRIDE; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_BROKER_DISPATCHER_H_ diff --git a/chromium/ppapi/proxy/broker_resource.cc b/chromium/ppapi/proxy/broker_resource.cc new file mode 100644 index 00000000000..4fac07e54c3 --- /dev/null +++ b/chromium/ppapi/proxy/broker_resource.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 "ppapi/proxy/broker_resource.h" + +#include "ppapi/c/pp_bool.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +BrokerResource::BrokerResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_Broker_Create()); +} + +BrokerResource::~BrokerResource() { +} + +thunk::PPB_Broker_Instance_API* BrokerResource::AsPPB_Broker_Instance_API() { + return this; +} + +PP_Bool BrokerResource::IsAllowed() { + int32_t result = + SyncCall<IPC::Message>(BROWSER, PpapiHostMsg_Broker_IsAllowed()); + return PP_FromBool(result == PP_OK); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/broker_resource.h b/chromium/ppapi/proxy/broker_resource.h new file mode 100644 index 00000000000..48d804174e3 --- /dev/null +++ b/chromium/ppapi/proxy/broker_resource.h @@ -0,0 +1,35 @@ +// 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_PROXY_BROKER_RESOURCE_H_ +#define PPAPI_PROXY_BROKER_RESOURCE_H_ + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/ppb_broker_api.h" + +namespace ppapi { +namespace proxy { + +class BrokerResource + : public PluginResource, + public thunk::PPB_Broker_Instance_API { + public: + BrokerResource(Connection connection, PP_Instance instance); + virtual ~BrokerResource(); + + // Resource override. + virtual thunk::PPB_Broker_Instance_API* AsPPB_Broker_Instance_API() OVERRIDE; + + // thunk::PPB_Broker_Instance_API implementation. + virtual PP_Bool IsAllowed() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(BrokerResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_BROKER_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/browser_font_singleton_resource.cc b/chromium/ppapi/proxy/browser_font_singleton_resource.cc new file mode 100644 index 00000000000..0805126d2ca --- /dev/null +++ b/chromium/ppapi/proxy/browser_font_singleton_resource.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 "ppapi/proxy/browser_font_singleton_resource.h" + +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +BrowserFontSingletonResource::BrowserFontSingletonResource( + Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_BrowserFontSingleton_Create()); +} + +BrowserFontSingletonResource::~BrowserFontSingletonResource() { +} + +thunk::PPB_BrowserFont_Singleton_API* +BrowserFontSingletonResource::AsPPB_BrowserFont_Singleton_API() { + return this; +} + +PP_Var BrowserFontSingletonResource::GetFontFamilies(PP_Instance instance) { + if (families_.empty()) { + SyncCall<PpapiPluginMsg_BrowserFontSingleton_GetFontFamiliesReply>( + BROWSER, PpapiHostMsg_BrowserFontSingleton_GetFontFamilies(), + &families_); + } + return StringVar::StringToPPVar(families_); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/browser_font_singleton_resource.h b/chromium/ppapi/proxy/browser_font_singleton_resource.h new file mode 100644 index 00000000000..50b88dcbb29 --- /dev/null +++ b/chromium/ppapi/proxy/browser_font_singleton_resource.h @@ -0,0 +1,42 @@ +// 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_PROXY_BROWSER_FONT_SINGLETON_RESOURCE_H_ +#define PPAPI_PROXY_BROWSER_FONT_SINGLETON_RESOURCE_H_ + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/ppb_browser_font_singleton_api.h" + +namespace ppapi { +namespace proxy { + +// This handles the singleton calls (that don't take a PP_Resource parameter) +// on the browser font interface +class BrowserFontSingletonResource + : public PluginResource, + public thunk::PPB_BrowserFont_Singleton_API { + public: + BrowserFontSingletonResource(Connection connection, PP_Instance instance); + virtual ~BrowserFontSingletonResource(); + + // Resource override. + virtual thunk::PPB_BrowserFont_Singleton_API* + AsPPB_BrowserFont_Singleton_API() OVERRIDE; + + // thunk::PPB_BrowserFontSingleton_API implementation. + virtual PP_Var GetFontFamilies(PP_Instance instance) OVERRIDE; + + private: + // Lazily-filled-in list of font families. + std::string families_; + + DISALLOW_COPY_AND_ASSIGN(BrowserFontSingletonResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_BROWSER_FONT_SINGLETON_RESOURCE_H_ + diff --git a/chromium/ppapi/proxy/connection.h b/chromium/ppapi/proxy/connection.h new file mode 100644 index 00000000000..13cbbc6fcf4 --- /dev/null +++ b/chromium/ppapi/proxy/connection.h @@ -0,0 +1,52 @@ +// 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_PROXY_CONNECTION_H_ +#define PPAPI_PROXY_CONNECTION_H_ + +#include "ipc/ipc_message.h" + +namespace IPC { +class Sender; +} + +namespace ppapi { +namespace proxy { + +// This struct holds the channels that a resource uses to send message to the +// browser and renderer. +struct Connection { + Connection() : browser_sender(0), + renderer_sender(0), + in_process(false), + browser_sender_routing_id(MSG_ROUTING_NONE) { + } + Connection(IPC::Sender* browser, IPC::Sender* renderer) + : browser_sender(browser), + renderer_sender(renderer), + in_process(false), + browser_sender_routing_id(MSG_ROUTING_NONE) { + } + Connection(IPC::Sender* browser, IPC::Sender* renderer, int routing_id) + : browser_sender(browser), + renderer_sender(renderer), + in_process(true), + browser_sender_routing_id(routing_id) { + } + + IPC::Sender* browser_sender; + IPC::Sender* renderer_sender; + bool in_process; + // We need to use a routing ID when a plugin is in-process, and messages are + // sent back from the browser to the renderer. This is so that messages are + // routed to the proper RenderViewImpl. + int browser_sender_routing_id; +}; + +} // namespace proxy +} // namespace ppapi + + +#endif // PPAPI_PROXY_CONNECTION_H_ + diff --git a/chromium/ppapi/proxy/content_decryptor_private_serializer.h b/chromium/ppapi/proxy/content_decryptor_private_serializer.h new file mode 100644 index 00000000000..249b01cace3 --- /dev/null +++ b/chromium/ppapi/proxy/content_decryptor_private_serializer.h @@ -0,0 +1,57 @@ +// 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_PROXY_CONTENT_DECRYPTOR_PRIVATE_SERIALIZER_H_ +#define PPAPI_PROXY_CONTENT_DECRYPTOR_PRIVATE_SERIALIZER_H_ + +#include <cstring> +#include <string> + +#include "ppapi/c/private/pp_content_decryptor.h" + +namespace ppapi { +namespace proxy { + +// Serialization/deserialization utility functions for storing/extracting +// PP_DecryptedBlockInfo, PP_EncryptedBlockInfo, and PP_DecompressedFrameInfo +// structs within std::string's for passing through IPC. Both functions return +// true upon success, and false upon failure. +// +// Note, these functions check the size of |block_info| against the size of +// the "serialized" data stored within |serialized_block_info|, and will report +// failure if expectations are not met. Use of CHECK/DCHECK has been avoided +// because the functions are intended for use on both sides of the IPC proxy. + +template <typename T> +bool SerializeBlockInfo(const T& block_info, + std::string* serialized_block_info) { + if (!serialized_block_info) + return false; + + serialized_block_info->assign(reinterpret_cast<const char*>(&block_info), + sizeof(block_info)); + + if (serialized_block_info->size() != sizeof(block_info)) + return false; + + return true; +} + +template <typename T> +bool DeserializeBlockInfo(const std::string& serialized_block_info, + T* block_info) { + if (!block_info) + return false; + + if (serialized_block_info.size() != sizeof(*block_info)) + return false; + + std::memcpy(block_info, serialized_block_info.data(), sizeof(*block_info)); + return true; +} + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_CONTENT_DECRYPTOR_PRIVATE_SERIALIZER_H_ diff --git a/chromium/ppapi/proxy/device_enumeration_resource_helper.cc b/chromium/ppapi/proxy/device_enumeration_resource_helper.cc new file mode 100644 index 00000000000..e8d63e1dbdf --- /dev/null +++ b/chromium/ppapi/proxy/device_enumeration_resource_helper.cc @@ -0,0 +1,223 @@ +// 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 "ppapi/proxy/device_enumeration_resource_helper.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ppapi/c/pp_array_output.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/ppb_device_ref_shared.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace ppapi { +namespace proxy { + +DeviceEnumerationResourceHelper::DeviceEnumerationResourceHelper( + PluginResource* owner) + : owner_(owner), + pending_enumerate_devices_(false), + monitor_callback_id_(0), + monitor_user_data_(NULL) { +} + +DeviceEnumerationResourceHelper::~DeviceEnumerationResourceHelper() { +} + +int32_t DeviceEnumerationResourceHelper::EnumerateDevices0_2( + PP_Resource* devices, + scoped_refptr<TrackedCallback> callback) { + if (pending_enumerate_devices_) + return PP_ERROR_INPROGRESS; + if (!devices) + return PP_ERROR_BADARGUMENT; + + pending_enumerate_devices_ = true; + PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg; + owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>( + PluginResource::RENDERER, msg, + base::Bind( + &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2, + AsWeakPtr(), devices, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t DeviceEnumerationResourceHelper::EnumerateDevices( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + if (pending_enumerate_devices_) + return PP_ERROR_INPROGRESS; + + pending_enumerate_devices_ = true; + PpapiHostMsg_DeviceEnumeration_EnumerateDevices msg; + owner_->Call<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>( + PluginResource::RENDERER, msg, + base::Bind( + &DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply, + AsWeakPtr(), output, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t DeviceEnumerationResourceHelper::EnumerateDevicesSync( + const PP_ArrayOutput& output) { + std::vector<DeviceRefData> devices; + int32_t result = + owner_->SyncCall<PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply>( + PluginResource::RENDERER, + PpapiHostMsg_DeviceEnumeration_EnumerateDevices(), + &devices); + + if (result == PP_OK) + result = WriteToArrayOutput(devices, output); + + return result; +} + +int32_t DeviceEnumerationResourceHelper::MonitorDeviceChange( + PP_MonitorDeviceChangeCallback callback, + void* user_data) { + monitor_callback_id_++; + monitor_user_data_ = user_data; + if (callback) { + monitor_callback_.reset( + ThreadAwareCallback<PP_MonitorDeviceChangeCallback>::Create(callback)); + if (!monitor_callback_.get()) + return PP_ERROR_NO_MESSAGE_LOOP; + + owner_->Post(PluginResource::RENDERER, + PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange( + monitor_callback_id_)); + } else { + monitor_callback_.reset(NULL); + + owner_->Post(PluginResource::RENDERER, + PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange()); + } + return PP_OK; +} + +bool DeviceEnumerationResourceHelper::HandleReply( + const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(DeviceEnumerationResourceHelper, msg) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange, + OnPluginMsgNotifyDeviceChange) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(return false) + IPC_END_MESSAGE_MAP() + + return true; +} + +void DeviceEnumerationResourceHelper::LastPluginRefWasDeleted() { + // Make sure that no further notifications are sent to the plugin. + monitor_callback_id_++; + monitor_callback_.reset(NULL); + monitor_user_data_ = NULL; + + // There is no need to do anything with pending callback of + // EnumerateDevices(), because OnPluginMsgEnumerateDevicesReply*() will handle + // that properly. +} + +void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply0_2( + PP_Resource* devices_resource, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::vector<DeviceRefData>& devices) { + pending_enumerate_devices_ = false; + + // We shouldn't access |devices_resource| if the callback has been called, + // which is possible if the last plugin reference to the corresponding + // resource has gone away, and the callback has been aborted. + if (!TrackedCallback::IsPending(callback)) + return; + + if (params.result() == PP_OK) { + *devices_resource = PPB_DeviceRef_Shared::CreateResourceArray( + OBJECT_IS_PROXY, owner_->pp_instance(), devices); + } + + callback->Run(params.result()); +} + +void DeviceEnumerationResourceHelper::OnPluginMsgEnumerateDevicesReply( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::vector<DeviceRefData>& devices) { + pending_enumerate_devices_ = false; + + // We shouldn't access |output| if the callback has been called, which is + // possible if the last plugin reference to the corresponding resource has + // gone away, and the callback has been aborted. + if (!TrackedCallback::IsPending(callback)) + return; + + int32_t result = params.result(); + if (result == PP_OK) + result = WriteToArrayOutput(devices, output); + + callback->Run(result); +} + +void DeviceEnumerationResourceHelper::OnPluginMsgNotifyDeviceChange( + const ResourceMessageReplyParams& /* params */, + uint32_t callback_id, + const std::vector<DeviceRefData>& devices) { + if (monitor_callback_id_ != callback_id) { + // A new callback or NULL has been set. + return; + } + + CHECK(monitor_callback_.get()); + + scoped_ptr<PP_Resource[]> elements; + uint32_t size = devices.size(); + if (size > 0) { + elements.reset(new PP_Resource[size]); + for (size_t index = 0; index < size; ++index) { + PPB_DeviceRef_Shared* device_object = new PPB_DeviceRef_Shared( + OBJECT_IS_PROXY, owner_->pp_instance(), devices[index]); + elements[index] = device_object->GetReference(); + } + } + + monitor_callback_->RunOnTargetThread(monitor_user_data_, size, + elements.get()); + for (size_t index = 0; index < size; ++index) + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(elements[index]); +} + +int32_t DeviceEnumerationResourceHelper::WriteToArrayOutput( + const std::vector<DeviceRefData>& devices, + const PP_ArrayOutput& output) { + ArrayWriter writer(output); + if (!writer.is_valid()) + return PP_ERROR_BADARGUMENT; + + std::vector<scoped_refptr<Resource> > device_resources; + for (size_t i = 0; i < devices.size(); ++i) { + device_resources.push_back(new PPB_DeviceRef_Shared( + OBJECT_IS_PROXY, owner_->pp_instance(), devices[i])); + } + if (!writer.StoreResourceVector(device_resources)) + return PP_ERROR_FAILED; + + return PP_OK; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/device_enumeration_resource_helper.h b/chromium/ppapi/proxy/device_enumeration_resource_helper.h new file mode 100644 index 00000000000..a2574ec6461 --- /dev/null +++ b/chromium/ppapi/proxy/device_enumeration_resource_helper.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 PPAPI_PROXY_DEVICE_ENUMERATION_RESOURCE_HELPER_H_ +#define PPAPI_PROXY_DEVICE_ENUMERATION_RESOURCE_HELPER_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/c/dev/ppb_device_ref_dev.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/thread_aware_callback.h" + +namespace IPC { +class Message; +} + +struct PP_ArrayOutput; + +namespace ppapi { + +struct DeviceRefData; +class TrackedCallback; + +namespace proxy { + +class PluginResource; +class ResourceMessageReplyParams; + +class PPAPI_PROXY_EXPORT DeviceEnumerationResourceHelper + : public base::SupportsWeakPtr<DeviceEnumerationResourceHelper> { + public: + // |owner| must outlive this object. + explicit DeviceEnumerationResourceHelper(PluginResource* owner); + ~DeviceEnumerationResourceHelper(); + + int32_t EnumerateDevices0_2(PP_Resource* devices, + scoped_refptr<TrackedCallback> callback); + int32_t EnumerateDevices(const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback); + int32_t EnumerateDevicesSync(const PP_ArrayOutput& output); + int32_t MonitorDeviceChange(PP_MonitorDeviceChangeCallback callback, + void* user_data); + + // Returns true if the message has been handled. + bool HandleReply(const ResourceMessageReplyParams& params, + const IPC::Message& msg); + + void LastPluginRefWasDeleted(); + + private: + void OnPluginMsgEnumerateDevicesReply0_2( + PP_Resource* devices_resource, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::vector<DeviceRefData>& devices); + void OnPluginMsgEnumerateDevicesReply( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::vector<DeviceRefData>& devices); + void OnPluginMsgNotifyDeviceChange(const ResourceMessageReplyParams& params, + uint32_t callback_id, + const std::vector<DeviceRefData>& devices); + + int32_t WriteToArrayOutput(const std::vector<DeviceRefData>& devices, + const PP_ArrayOutput& output); + + // Not owned by this object. + PluginResource* owner_; + + bool pending_enumerate_devices_; + + uint32_t monitor_callback_id_; + scoped_ptr<ThreadAwareCallback<PP_MonitorDeviceChangeCallback> > + monitor_callback_; + void* monitor_user_data_; + + DISALLOW_COPY_AND_ASSIGN(DeviceEnumerationResourceHelper); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_DEVICE_ENUMERATION_RESOURCE_HELPER_H_ diff --git a/chromium/ppapi/proxy/device_enumeration_resource_helper_unittest.cc b/chromium/ppapi/proxy/device_enumeration_resource_helper_unittest.cc new file mode 100644 index 00000000000..56c09d7966c --- /dev/null +++ b/chromium/ppapi/proxy/device_enumeration_resource_helper_unittest.cc @@ -0,0 +1,409 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/device_enumeration_resource_helper.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_message_utils.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/ppb_device_ref_shared.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_device_ref_api.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest DeviceEnumerationResourceHelperTest; + +Connection GetConnection(PluginProxyTestHarness* harness) { + CHECK(harness->GetGlobals()->IsPluginGlobals()); + + return Connection( + static_cast<PluginGlobals*>(harness->GetGlobals())->GetBrowserSender(), + harness->plugin_dispatcher()); +} + +bool CompareDeviceRef(PluginVarTracker* var_tracker, + PP_Resource resource, + const DeviceRefData& expected) { + thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter(resource, true); + if (enter.failed()) + return false; + + if (expected.type != enter.object()->GetType()) + return false; + + PP_Var name_pp_var = enter.object()->GetName(); + bool result = false; + do { + Var* name_var = var_tracker->GetVar(name_pp_var); + if (!name_var) + break; + StringVar* name_string_var = name_var->AsStringVar(); + if (!name_string_var) + break; + if (expected.name != name_string_var->value()) + break; + + result = true; + } while (false); + var_tracker->ReleaseVar(name_pp_var); + return result; +} + +class TestResource : public PluginResource { + public: + TestResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance), + device_enumeration_(this) { + } + + virtual ~TestResource() {} + + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE { + if (!device_enumeration_.HandleReply(params, msg)) + PluginResource::OnReplyReceived(params, msg); + } + + DeviceEnumerationResourceHelper& device_enumeration() { + return device_enumeration_; + } + + private: + DeviceEnumerationResourceHelper device_enumeration_; + + DISALLOW_COPY_AND_ASSIGN(TestResource); +}; + +class TestCallback { + public: + TestCallback() : called_(false), result_(PP_ERROR_FAILED) { + } + ~TestCallback() { + CHECK(called_); + } + + PP_CompletionCallback MakeCompletionCallback() { + return PP_MakeCompletionCallback(&CompletionCallbackBody, this); + } + + bool called() const { return called_; } + int32_t result() const { return result_; } + + private: + static void CompletionCallbackBody(void* user_data, int32_t result) { + TestCallback* callback = static_cast<TestCallback*>(user_data); + + CHECK(!callback->called_); + callback->called_ = true; + callback->result_ = result; + } + + bool called_; + int32_t result_; + + DISALLOW_COPY_AND_ASSIGN(TestCallback); +}; + +class TestArrayOutput { + public: + explicit TestArrayOutput(PluginResourceTracker* resource_tracker) + : data_(NULL), + count_(0), + resource_tracker_(resource_tracker) { + } + + ~TestArrayOutput() { + if (count_ > 0) { + for (size_t i = 0; i < count_; ++i) + resource_tracker_->ReleaseResource(data_[i]); + delete [] data_; + } + } + + PP_ArrayOutput MakeArrayOutput() { + PP_ArrayOutput array_output = { &GetDataBuffer, this }; + return array_output; + } + + const PP_Resource* data() const { return data_; } + uint32_t count() const { return count_; } + + private: + static void* GetDataBuffer(void* user_data, + uint32_t element_count, + uint32_t element_size) { + CHECK_EQ(element_size, sizeof(PP_Resource)); + + TestArrayOutput* output = static_cast<TestArrayOutput*>(user_data); + CHECK(!output->data_); + + output->count_ = element_count; + if (element_count > 0) + output->data_ = new PP_Resource[element_count]; + else + output->data_ = NULL; + + return output->data_; + } + + PP_Resource* data_; + uint32_t count_; + PluginResourceTracker* resource_tracker_; + + DISALLOW_COPY_AND_ASSIGN(TestArrayOutput); +}; + +class TestMonitorDeviceChange { + public: + explicit TestMonitorDeviceChange(PluginVarTracker* var_tracker) + : called_(false), + same_as_expected_(false), + var_tracker_(var_tracker) { + } + + ~TestMonitorDeviceChange() {} + + void SetExpectedResult(const std::vector<DeviceRefData>& expected) { + called_ = false; + same_as_expected_ = false; + expected_ = expected; + } + + bool called() const { return called_; } + + bool same_as_expected() const { return same_as_expected_; } + + static void MonitorDeviceChangeCallback(void* user_data, + uint32_t device_count, + const PP_Resource devices[]) { + ProxyAutoLock lock; + TestMonitorDeviceChange* helper = + static_cast<TestMonitorDeviceChange*>(user_data); + CHECK(!helper->called_); + + helper->called_ = true; + helper->same_as_expected_ = false; + if (device_count != helper->expected_.size()) + return; + for (size_t i = 0; i < device_count; ++i) { + if (!CompareDeviceRef(helper->var_tracker_, devices[i], + helper->expected_[i])) { + return; + } + } + helper->same_as_expected_ = true; + } + + private: + bool called_; + bool same_as_expected_; + std::vector<DeviceRefData> expected_; + PluginVarTracker* var_tracker_; + + DISALLOW_COPY_AND_ASSIGN(TestMonitorDeviceChange); +}; + +} // namespace + +TEST_F(DeviceEnumerationResourceHelperTest, EnumerateDevices) { + ProxyAutoLock lock; + + scoped_refptr<TestResource> resource( + new TestResource(GetConnection(this), pp_instance())); + DeviceEnumerationResourceHelper& device_enumeration = + resource->device_enumeration(); + + TestArrayOutput output(&resource_tracker()); + TestCallback callback; + scoped_refptr<TrackedCallback> tracked_callback( + new TrackedCallback(resource.get(), callback.MakeCompletionCallback())); + int32_t result = device_enumeration.EnumerateDevices(output.MakeArrayOutput(), + tracked_callback); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + // Should have sent an EnumerateDevices message. + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID, ¶ms, &msg)); + + // Synthesize a response. + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(PP_OK); + std::vector<DeviceRefData> data; + DeviceRefData data_item; + data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; + data_item.name = "name_1"; + data_item.id = "id_1"; + data.push_back(data_item); + data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; + data_item.name = "name_2"; + data_item.id = "id_2"; + data.push_back(data_item); + + { + ProxyAutoUnlock unlock; + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply(data)))); + } + EXPECT_TRUE(callback.called()); + EXPECT_EQ(PP_OK, callback.result()); + EXPECT_EQ(2U, output.count()); + for (size_t i = 0; i < output.count(); ++i) + EXPECT_TRUE(CompareDeviceRef(&var_tracker(), output.data()[i], data[i])); +} + +TEST_F(DeviceEnumerationResourceHelperTest, MonitorDeviceChange) { + ProxyAutoLock lock; + + scoped_refptr<TestResource> resource( + new TestResource(GetConnection(this), pp_instance())); + DeviceEnumerationResourceHelper& device_enumeration = + resource->device_enumeration(); + + TestMonitorDeviceChange helper(&var_tracker()); + + int32_t result = device_enumeration.MonitorDeviceChange( + &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper); + ASSERT_EQ(PP_OK, result); + + // Should have sent a MonitorDeviceChange message. + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms, &msg)); + sink().ClearMessages(); + + uint32_t callback_id = 0; + ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>( + msg, &callback_id)); + + ResourceMessageReplyParams reply_params(params.pp_resource(), 0); + reply_params.set_result(PP_OK); + std::vector<DeviceRefData> data; + + helper.SetExpectedResult(data); + + { + ProxyAutoUnlock unlock; + // Synthesize a response with no device. + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( + callback_id, data)))); + } + EXPECT_TRUE(helper.called() && helper.same_as_expected()); + + DeviceRefData data_item; + data_item.type = PP_DEVICETYPE_DEV_AUDIOCAPTURE; + data_item.name = "name_1"; + data_item.id = "id_1"; + data.push_back(data_item); + data_item.type = PP_DEVICETYPE_DEV_VIDEOCAPTURE; + data_item.name = "name_2"; + data_item.id = "id_2"; + data.push_back(data_item); + + helper.SetExpectedResult(data); + + { + ProxyAutoUnlock unlock; + // Synthesize a response with some devices. + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( + callback_id, data)))); + } + EXPECT_TRUE(helper.called() && helper.same_as_expected()); + + TestMonitorDeviceChange helper2(&var_tracker()); + + result = device_enumeration.MonitorDeviceChange( + &TestMonitorDeviceChange::MonitorDeviceChangeCallback, &helper2); + ASSERT_EQ(PP_OK, result); + + // Should have sent another MonitorDeviceChange message. + ResourceMessageCallParams params2; + IPC::Message msg2; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange::ID, ¶ms2, &msg2)); + sink().ClearMessages(); + + uint32_t callback_id2 = 0; + ASSERT_TRUE(UnpackMessage<PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange>( + msg2, &callback_id2)); + + helper.SetExpectedResult(data); + helper2.SetExpectedResult(data); + { + ProxyAutoUnlock unlock; + // |helper2| should receive the result while |helper| shouldn't. + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( + callback_id2, data)))); + } + EXPECT_TRUE(helper2.called() && helper2.same_as_expected()); + EXPECT_FALSE(helper.called()); + + helper.SetExpectedResult(data); + helper2.SetExpectedResult(data); + { + ProxyAutoUnlock unlock; + // Even if a message with |callback_id| arrives. |helper| shouldn't receive + // the result. + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( + callback_id, data)))); + } + EXPECT_FALSE(helper2.called()); + EXPECT_FALSE(helper.called()); + + result = device_enumeration.MonitorDeviceChange(NULL, NULL); + ASSERT_EQ(PP_OK, result); + + // Should have sent a StopMonitoringDeviceChange message. + ResourceMessageCallParams params3; + IPC::Message msg3; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange::ID, + ¶ms3, &msg3)); + sink().ClearMessages(); + + helper2.SetExpectedResult(data); + { + ProxyAutoUnlock unlock; + // |helper2| shouldn't receive any result any more. + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange( + callback_id2, data)))); + } + EXPECT_FALSE(helper2.called()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/dispatch_reply_message.h b/chromium/ppapi/proxy/dispatch_reply_message.h new file mode 100644 index 00000000000..a380cdcf97b --- /dev/null +++ b/chromium/ppapi/proxy/dispatch_reply_message.h @@ -0,0 +1,164 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file provides infrastructure for dispatching messasges from host +// resource, inlcuding reply messages or unsolicited replies. Normal IPC Reply +// handlers can't take extra parameters. We want to take a +// ResourceMessageReplyParams as a parameter. + +#ifndef PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_ +#define PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_ + +#include "base/callback.h" +#include "base/profiler/scoped_profile.h" // For TRACK_RUN_IN_IPC_HANDLER. +#include "ipc/ipc_message_macros.h" +#include "ppapi/c/pp_errors.h" + +namespace ppapi { +namespace proxy { + +class ResourceMessageReplyParams; + +template <class ObjT, class Method> +inline void DispatchResourceReply(ObjT* obj, Method method, + const ResourceMessageReplyParams& params, + const Tuple0& arg) { + (obj->*method)(params); +} + +template <class ObjT, class Method, class A> +inline void DispatchResourceReply(ObjT* obj, Method method, + const ResourceMessageReplyParams& params, + const Tuple1<A>& arg) { + (obj->*method)(params, arg.a); +} + +template<class ObjT, class Method, class A, class B> +inline void DispatchResourceReply(ObjT* obj, Method method, + const ResourceMessageReplyParams& params, + const Tuple2<A, B>& arg) { + (obj->*method)(params, arg.a, arg.b); +} + +template<class ObjT, class Method, class A, class B, class C> +inline void DispatchResourceReply(ObjT* obj, Method method, + const ResourceMessageReplyParams& params, + const Tuple3<A, B, C>& arg) { + (obj->*method)(params, arg.a, arg.b, arg.c); +} + +template<class ObjT, class Method, class A, class B, class C, class D> +inline void DispatchResourceReply(ObjT* obj, Method method, + const ResourceMessageReplyParams& params, + const Tuple4<A, B, C, D>& arg) { + (obj->*method)(params, arg.a, arg.b, arg.c, arg.d); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E> +inline void DispatchResourceReply(ObjT* obj, Method method, + const ResourceMessageReplyParams& params, + const Tuple5<A, B, C, D, E>& arg) { + (obj->*method)(params, arg.a, arg.b, arg.c, arg.d, arg.e); +} + +// Used to dispatch resource replies. In most cases, you should not call this +// function to dispatch a resource reply manually, but instead use +// |PluginResource::CallBrowser|/|PluginResource::CallRenderer| with a +// |base::Callback| which will be called when a reply message is received +// (see plugin_resource.h). +// +// This function will call your callback with the nested reply message's +// parameters on success. On failure, your callback will be called with each +// parameter having its default constructed value. +// +// Resource replies are a bit weird in that the host will automatically +// generate a reply in error cases (when the call handler returns error rather +// than returning "completion pending"). This makes it more convenient to write +// the call message handlers. But this also means that the reply handler has to +// handle both the success case (when all of the reply message paramaters are +// specified) and the error case (when the nested reply message is empty). +// In both cases the resource will want to issue completion callbacks to the +// plugin. +// +// This function handles the error case by calling your reply handler with the +// default value for each paramater in the error case. In most situations this +// will be the right thing. You should always dispatch completion callbacks +// using the result code present in the ResourceMessageReplyParams. +template<class MsgClass, class ObjT, class Method> +void DispatchResourceReplyOrDefaultParams( + ObjT* obj, + Method method, + const ResourceMessageReplyParams& reply_params, + const IPC::Message& msg) { + typename MsgClass::Schema::Param msg_params; + // We either expect the nested message type to match, or that there is no + // nested message. No nested message indicates a default reply sent from + // the host: when the resource message handler returns an error, a reply + // is implicitly sent with no nested message. + DCHECK(msg.type() == MsgClass::ID || msg.type() == 0) + << "Resource reply message of unexpected type."; + if (msg.type() == MsgClass::ID && MsgClass::Read(&msg, &msg_params)) { + // Message type matches and the parameters were successfully read. + DispatchResourceReply(obj, method, reply_params, msg_params); + } else { + // The nested message is empty because the host handler didn't explicitly + // send a reply (likely), or you screwed up and didn't use the correct + // message type when calling this function (you should have hit the + // assertion above, Einstein). + // + // Dispatch the reply function with the default parameters. We explicitly + // use a new Params() structure since if the Read failed due to an invalid + // message, the params could have been partially filled in. + DispatchResourceReply(obj, method, reply_params, + typename MsgClass::Schema::Param()); + } +} + +// Template specialization for |Callback|s that only accept a +// |ResourceMessageReplyParams|. In this case |msg| shouldn't contain any +// arguments, so just call the |method| with the |reply_params|. +template<class MsgClass, class Method> +void DispatchResourceReplyOrDefaultParams( + base::Callback<void(const ResourceMessageReplyParams&)>* obj, + Method method, + const ResourceMessageReplyParams& reply_params, + const IPC::Message& msg) { + DCHECK(msg.type() == MsgClass::ID || msg.type() == 0) + << "Resource reply message of unexpected type."; + (obj->*method)(reply_params); +} + +// Note that this only works for message with 1 or more parameters. For +// 0-parameter messages you need to use the _0 version below (since there are +// no params in the message). +#define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(msg_class, member_func) \ + case msg_class::ID: { \ + msg_class::Schema::Param p; \ + if (msg_class::Read(&ipc_message__, &p)) { \ + ppapi::proxy::DispatchResourceReply( \ + this, \ + &_IpcMessageHandlerClass::member_func, \ + params, p); \ + } else { \ + NOTREACHED(); \ + } \ + break; \ + } + +#define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_0(msg_class, member_func) \ + case msg_class::ID: { \ + member_func(params); \ + break; \ + } + +#define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(code) \ + default: { \ + code; \ + } \ + break; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_ diff --git a/chromium/ppapi/proxy/dispatcher.cc b/chromium/ppapi/proxy/dispatcher.cc new file mode 100644 index 00000000000..3b18932447a --- /dev/null +++ b/chromium/ppapi/proxy/dispatcher.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/dispatcher.h" + +#include <string.h> // For memset. + +#include <map> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace ppapi { +namespace proxy { + +Dispatcher::Dispatcher(PP_GetInterface_Func local_get_interface, + const PpapiPermissions& permissions) + : local_get_interface_(local_get_interface), + permissions_(permissions) { +} + +Dispatcher::~Dispatcher() { +} + +void Dispatcher::AddFilter(IPC::Listener* listener) { + filters_.push_back(listener); +} + +InterfaceProxy* Dispatcher::GetInterfaceProxy(ApiID id) { + InterfaceProxy* proxy = proxies_[id].get(); + if (!proxy) { + // Handle the first time for a given API by creating the proxy for it. + InterfaceProxy::Factory factory = + InterfaceList::GetInstance()->GetFactoryForID(id); + if (!factory) { + NOTREACHED(); + return NULL; + } + proxy = factory(this); + DCHECK(proxy); + proxies_[id].reset(proxy); + } + return proxy; +} + +base::MessageLoopProxy* Dispatcher::GetIPCMessageLoop() { + return delegate()->GetIPCMessageLoop(); +} + +void Dispatcher::AddIOThreadMessageFilter( + IPC::ChannelProxy::MessageFilter* filter) { + // Our filter is refcounted. The channel will call the destruct method on the + // filter when the channel is done with it, so the corresponding Release() + // happens there. + channel()->AddFilter(filter); +} + +bool Dispatcher::OnMessageReceived(const IPC::Message& msg) { + if (msg.routing_id() <= 0 || msg.routing_id() >= API_ID_COUNT) { + OnInvalidMessageReceived(); + return true; + } + + InterfaceProxy* proxy = GetInterfaceProxy( + static_cast<ApiID>(msg.routing_id())); + if (!proxy) { + NOTREACHED(); + return true; + } + return proxy->OnMessageReceived(msg); +} + +void Dispatcher::SetSerializationRules( + VarSerializationRules* var_serialization_rules) { + serialization_rules_ = var_serialization_rules; +} + +void Dispatcher::OnInvalidMessageReceived() { +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/dispatcher.h b/chromium/ppapi/proxy/dispatcher.h new file mode 100644 index 00000000000..7bb2c7ec2a7 --- /dev/null +++ b/chromium/ppapi/proxy/dispatcher.h @@ -0,0 +1,124 @@ +// 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_PROXY_DISPATCHER_H_ +#define PPAPI_PROXY_DISPATCHER_H_ + +#include <set> +#include <string> +#include <vector> + +#include "base/callback_forward.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/tracked_objects.h" +#include "ipc/ipc_channel_proxy.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/ppp.h" +#include "ppapi/proxy/proxy_channel.h" +#include "ppapi/proxy/interface_list.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/shared_impl/api_id.h" + +namespace ppapi { + +namespace proxy { + +class VarSerializationRules; + +// An interface proxy can represent either end of a cross-process interface +// call. The "source" side is where the call is invoked, and the "target" side +// is where the call ends up being executed. +// +// Plugin side | Browser side +// -------------------------------------|-------------------------------------- +// | +// "Source" | "Target" +// InterfaceProxy ----------------------> InterfaceProxy +// | +// | +// "Target" | "Source" +// InterfaceProxy <---------------------- InterfaceProxy +// | +class PPAPI_PROXY_EXPORT Dispatcher : public ProxyChannel { + public: + virtual ~Dispatcher(); + + // Returns true if the dispatcher is on the plugin side, or false if it's the + // browser side. + virtual bool IsPlugin() const = 0; + + void AddFilter(IPC::Listener* listener); + + VarSerializationRules* serialization_rules() const { + return serialization_rules_.get(); + } + + // Returns a non-owning pointer to the interface proxy for the given ID, or + // NULL if the ID isn't found. This will create the proxy if it hasn't been + // created so far. + InterfaceProxy* GetInterfaceProxy(ApiID id); + + // Returns the pointer to the IO thread for processing IPC messages. + // TODO(brettw) remove this. It's a hack to support the Flash + // ModuleLocalThreadAdapter. When the thread stuff is sorted out, this + // implementation detail should be hidden. + base::MessageLoopProxy* GetIPCMessageLoop(); + + // Adds the given filter to the IO thread. Takes ownership of the pointer. + void AddIOThreadMessageFilter(IPC::ChannelProxy::MessageFilter* filter); + + // TODO(brettw): What is this comment referring to? + // Called if the remote side is declaring to us which interfaces it supports + // so we don't have to query for each one. We'll pre-create proxies for + // each of the given interfaces. + + // IPC::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + PP_GetInterface_Func local_get_interface() const { + return local_get_interface_; + } + + const PpapiPermissions& permissions() const { return permissions_; } + + protected: + explicit Dispatcher(PP_GetInterface_Func local_get_interface, + const PpapiPermissions& permissions); + + // Setter for the derived classes to set the appropriate var serialization. + // Takes one reference of the given pointer, which must be on the heap. + void SetSerializationRules(VarSerializationRules* var_serialization_rules); + + // Called when an invalid message is received from the remote site. The + // default implementation does nothing, derived classes can override. + virtual void OnInvalidMessageReceived(); + + protected: + std::vector<IPC::Listener*> filters_; + + private: + friend class HostDispatcherTest; + friend class PluginDispatcherTest; + + // Lists all lazily-created interface proxies. + scoped_ptr<InterfaceProxy> proxies_[API_ID_COUNT]; + + bool disallow_trusted_interfaces_; + + PP_GetInterface_Func local_get_interface_; + + scoped_refptr<VarSerializationRules> serialization_rules_; + + PpapiPermissions permissions_; + + DISALLOW_COPY_AND_ASSIGN(Dispatcher); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_DISPATCHER_H_ diff --git a/chromium/ppapi/proxy/enter_proxy.h b/chromium/ppapi/proxy/enter_proxy.h new file mode 100644 index 00000000000..4ad67b136c3 --- /dev/null +++ b/chromium/ppapi/proxy/enter_proxy.h @@ -0,0 +1,204 @@ +// 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_PROXY_ENTER_PROXY_H_ +#define PPAPI_PROXY_ENTER_PROXY_H_ + +#include "base/logging.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/thunk/enter.h" + +namespace ppapi { + +namespace proxy { + +// Wrapper around EnterResourceNoLock that takes a host resource. This is used +// when handling messages in the plugin from the host and we need to convert to +// an object in the plugin side corresponding to that. +// +// This never locks since we assume the host Resource is coming from IPC, and +// never logs errors since we assume the host is doing reasonable things. +template<typename ResourceT> +class EnterPluginFromHostResource + : public thunk::EnterResourceNoLock<ResourceT> { + public: + explicit EnterPluginFromHostResource(const HostResource& host_resource) + : thunk::EnterResourceNoLock<ResourceT>( + PluginGlobals::Get()->plugin_resource_tracker()-> + PluginResourceForHostResource(host_resource), + false) { + // Validate that we're in the plugin rather than the host. Otherwise this + // object will do the wrong thing. In the plugin, the instance should have + // a corresponding plugin dispatcher (assuming the resource is valid). + DCHECK(this->failed() || + PluginDispatcher::GetForInstance(host_resource.instance())); + } +}; + +template<typename ResourceT> +class EnterHostFromHostResource + : public thunk::EnterResourceNoLock<ResourceT> { + public: + explicit EnterHostFromHostResource(const HostResource& host_resource) + : thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(), + false) { + // Validate that we're in the host rather than the plugin. Otherwise this + // object will do the wrong thing. In the host, the instance should have + // a corresponding host disptacher (assuming the resource is valid). + DCHECK(this->failed() || + HostDispatcher::GetForInstance(host_resource.instance())); + } + + EnterHostFromHostResource(const HostResource& host_resource, + const pp::CompletionCallback& callback) + : thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(), + callback.pp_completion_callback(), + false) { + // Validate that we're in the host rather than the plugin. Otherwise this + // object will do the wrong thing. In the host, the instance should have + // a corresponding host disptacher (assuming the resource is valid). + DCHECK(this->failed() || + HostDispatcher::GetForInstance(host_resource.instance())); + } +}; + +// Enters a resource and forces a completion callback to be issued. +// +// This is used when implementing the host (renderer) side of a resource +// function that issues a completion callback. In all cases, we need to issue +// the callback to avoid hanging the plugin. +// +// This class automatically constructs a callback with the given factory +// calling the given method. The method will generally be the one that sends +// the message to trigger the completion callback in the plugin process. +// +// It will automatically issue the callback with PP_ERROR_NOINTERFACE if the +// host resource is invalid (i.e. failed() is set). In all other cases you +// should call SetResult(), which will issue the callback immediately if the +// result value isn't PP_OK_COMPLETIONPENDING. In the "completion pending" +// case, it's assumed the function the proxy is calling will take responsibility +// of executing the callback (returned by callback()). +// +// Example: +// EnterHostFromHostResourceForceCallback<PPB_Foo_API> enter( +// resource, callback_factory_, &MyClass::SendResult, resource); +// if (enter.failed()) +// return; // SendResult automatically called with PP_ERROR_BADRESOURCE. +// enter.SetResult(enter.object()->DoFoo(enter.callback())); +// +// Where DoFoo's signature looks like this: +// int32_t DoFoo(PP_CompletionCallback callback); +// And SendResult's implementation looks like this: +// void MyClass::SendResult(int32_t result, const HostResource& res) { +// Send(new FooMsg_FooComplete(..., result, res)); +// } +template<typename ResourceT> +class EnterHostFromHostResourceForceCallback + : public EnterHostFromHostResource<ResourceT> { + public: + EnterHostFromHostResourceForceCallback( + const HostResource& host_resource, + const pp::CompletionCallback& callback) + : EnterHostFromHostResource<ResourceT>(host_resource, callback), + needs_running_(true) { + } + + // For callbacks that take no parameters except the "int32_t result". Most + // implementations will use the 1-extra-argument constructor below. + template<class CallbackFactory, typename Method> + EnterHostFromHostResourceForceCallback( + const HostResource& host_resource, + CallbackFactory& factory, + Method method) + : EnterHostFromHostResource<ResourceT>(host_resource, + factory.NewOptionalCallback(method)), + needs_running_(true) { + if (this->failed()) + RunCallback(PP_ERROR_BADRESOURCE); + } + + // For callbacks that take an extra parameter as a closure. + template<class CallbackFactory, typename Method, typename A> + EnterHostFromHostResourceForceCallback( + const HostResource& host_resource, + CallbackFactory& factory, + Method method, + const A& a) + : EnterHostFromHostResource<ResourceT>(host_resource, + factory.NewOptionalCallback(method, a)), + needs_running_(true) { + if (this->failed()) + RunCallback(PP_ERROR_BADRESOURCE); + } + + // For callbacks that take two extra parameters as a closure. + template<class CallbackFactory, typename Method, typename A, typename B> + EnterHostFromHostResourceForceCallback( + const HostResource& host_resource, + CallbackFactory& factory, + Method method, + const A& a, + const B& b) + : EnterHostFromHostResource<ResourceT>(host_resource, + factory.NewOptionalCallback(method, a, b)), + needs_running_(true) { + if (this->failed()) + RunCallback(PP_ERROR_BADRESOURCE); + } + + // For callbacks that take three extra parameters as a closure. + template<class CallbackFactory, typename Method, typename A, typename B, + typename C> + EnterHostFromHostResourceForceCallback( + const HostResource& host_resource, + CallbackFactory& factory, + Method method, + const A& a, + const B& b, + const C& c) + : EnterHostFromHostResource<ResourceT>(host_resource, + factory.NewOptionalCallback(method, a, b, c)), + needs_running_(true) { + if (this->failed()) + RunCallback(PP_ERROR_BADRESOURCE); + } + + ~EnterHostFromHostResourceForceCallback() { + if (needs_running_) { + NOTREACHED() << "Should always call SetResult except in the " + "initialization failed case."; + RunCallback(PP_ERROR_FAILED); + } + } + + void SetResult(int32_t result) { + DCHECK(needs_running_) << "Don't call SetResult when there already is one."; + if (result != PP_OK_COMPLETIONPENDING) + RunCallback(result); + needs_running_ = false; + // Either we already ran the callback, or it will be run asynchronously. We + // clear the callback so it isn't accidentally run again (and because + // EnterBase checks that the callback has been cleared). + this->ClearCallback(); + } + + private: + void RunCallback(int32_t result) { + DCHECK(needs_running_); + needs_running_ = false; + this->callback()->Run(result); + this->ClearCallback(); + } + + bool needs_running_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_ENTER_PROXY_H_ diff --git a/chromium/ppapi/proxy/ext_crx_file_system_private_resource.cc b/chromium/ppapi/proxy/ext_crx_file_system_private_resource.cc new file mode 100644 index 00000000000..f0de598c2de --- /dev/null +++ b/chromium/ppapi/proxy/ext_crx_file_system_private_resource.cc @@ -0,0 +1,80 @@ +// 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 "ppapi/proxy/ext_crx_file_system_private_resource.h" + +#include "base/bind.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/enter.h" + +namespace ppapi { +namespace proxy { + +ExtCrxFileSystemPrivateResource::ExtCrxFileSystemPrivateResource( + Connection connection, PP_Instance instance) + : PluginResource(connection, instance), called_open_(false) { + SendCreate(BROWSER, PpapiHostMsg_Ext_CrxFileSystem_Create()); +} + +ExtCrxFileSystemPrivateResource::~ExtCrxFileSystemPrivateResource() { +} + +thunk::PPB_Ext_CrxFileSystem_Private_API* +ExtCrxFileSystemPrivateResource::AsPPB_Ext_CrxFileSystem_Private_API() { + return this; +} + +int32_t ExtCrxFileSystemPrivateResource::Open( + PP_Instance /* unused */, + PP_Resource* file_system_resource, + scoped_refptr<TrackedCallback> callback) { + if (called_open_) + return PP_ERROR_FAILED; + called_open_ = true; + + if (!file_system_resource) + return PP_ERROR_BADARGUMENT; + + Call<PpapiPluginMsg_Ext_CrxFileSystem_BrowserOpenReply>(BROWSER, + PpapiHostMsg_Ext_CrxFileSystem_BrowserOpen(), + base::Bind(&ExtCrxFileSystemPrivateResource::OnBrowserOpenComplete, this, + file_system_resource, + callback)); + return PP_OK_COMPLETIONPENDING; +} + +void ExtCrxFileSystemPrivateResource::OnBrowserOpenComplete( + PP_Resource* file_system_resource, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::string& fsid) { + if (!TrackedCallback::IsPending(callback)) + return; + + if (params.result() != PP_OK) { + callback->Run(params.result()); + return; + } + + thunk::EnterResourceCreationNoLock enter(pp_instance()); + if (enter.failed()) { + callback->Run(enter.retval()); + return; + } + + *file_system_resource = enter.functions()->CreateIsolatedFileSystem( + pp_instance(), fsid.c_str()); + if (*file_system_resource != 0) { + callback->Run(PP_OK); + } else { + callback->Run(PP_ERROR_FAILED); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ext_crx_file_system_private_resource.h b/chromium/ppapi/proxy/ext_crx_file_system_private_resource.h new file mode 100644 index 00000000000..5f2887a7181 --- /dev/null +++ b/chromium/ppapi/proxy/ext_crx_file_system_private_resource.h @@ -0,0 +1,68 @@ +// 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. +// +// CRX filesystem is a filesystem that allows an extension to read its own +// package directory tree. See ppapi/examples/crxfs for example. +// +// IMPLEMENTATION +// +// The implementation involves both browser and renderer. In order to provide +// readonly access to CRX filesystem (i.e. extension directory), we create an +// "isolated filesystem" pointing to current extension directory in browser. +// Then browser grants read permission to renderer, and tells plugin the +// filesystem id, or fsid. +// +// Once the plugin receives the fsid, it creates a PPB_FileSystem and forwards +// the fsid to PepperFileSystemHost in order to construct root url. + +#ifndef PPAPI_PROXY_EXT_CRX_FILE_SYSTEM_PRIVATE_RESOURCE_H_ +#define PPAPI_PROXY_EXT_CRX_FILE_SYSTEM_PRIVATE_RESOURCE_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_ext_crx_file_system_private_api.h" + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +class ResourceMessageReplyParams; + +class PPAPI_PROXY_EXPORT ExtCrxFileSystemPrivateResource + : public PluginResource, + public thunk::PPB_Ext_CrxFileSystem_Private_API { + public: + ExtCrxFileSystemPrivateResource(Connection connection, PP_Instance instance); + virtual ~ExtCrxFileSystemPrivateResource(); + + // Resource overrides. + virtual thunk::PPB_Ext_CrxFileSystem_Private_API* + AsPPB_Ext_CrxFileSystem_Private_API() OVERRIDE; + + // PPB_Ext_CrxFileSystem_Private_API implementation. + virtual int32_t Open(PP_Instance instance, + PP_Resource* file_system_resource, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + void OnBrowserOpenComplete(PP_Resource* file_system_resource, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::string& fsid); + + bool called_open_; + + DISALLOW_COPY_AND_ASSIGN(ExtCrxFileSystemPrivateResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_EXT_CRX_FILE_SYSTEM_PRIVATE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/extensions_common_resource.cc b/chromium/ppapi/proxy/extensions_common_resource.cc new file mode 100644 index 00000000000..40d03f97822 --- /dev/null +++ b/chromium/ppapi/proxy/extensions_common_resource.cc @@ -0,0 +1,139 @@ +// 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 "ppapi/proxy/extensions_common_resource.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/shared_impl/var_value_conversions.h" + +namespace ppapi { +namespace proxy { + +ExtensionsCommonResource::ExtensionsCommonResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(RENDERER, PpapiHostMsg_ExtensionsCommon_Create()); + SendCreate(BROWSER, PpapiHostMsg_ExtensionsCommon_Create()); +} + +ExtensionsCommonResource::~ExtensionsCommonResource() { +} + +thunk::ExtensionsCommon_API* +ExtensionsCommonResource::AsExtensionsCommon_API() { + return this; +} + +int32_t ExtensionsCommonResource::CallRenderer( + const std::string& request_name, + const std::vector<PP_Var>& input_args, + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback) { + return CommonCall(RENDERER, request_name, input_args, output_args, callback); +} + +void ExtensionsCommonResource::PostRenderer(const std::string& request_name, + const std::vector<PP_Var>& args) { + CommonPost(RENDERER, request_name, args); +} + +int32_t ExtensionsCommonResource::CallBrowser( + const std::string& request_name, + const std::vector<PP_Var>& input_args, + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback) { + return CommonCall(BROWSER, request_name, input_args, output_args, callback); +} + +void ExtensionsCommonResource::PostBrowser(const std::string& request_name, + const std::vector<PP_Var>& args) { + CommonPost(BROWSER, request_name, args); +} + +int32_t ExtensionsCommonResource::CommonCall( + Destination dest, + const std::string& request_name, + const std::vector<PP_Var>& input_args, + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback) { + // TODO(yzshen): CreateValueFromVar() doesn't generate null fields for + // dictionary values. That is the expected behavior for most APIs. If later we + // want to support APIs that require to preserve null fields in dictionaries, + // we should change the behavior to always preserve null fields at the plugin + // side, and figure out whether they should be stripped at the renderer side. + scoped_ptr<base::ListValue> input_args_value( + CreateListValueFromVarVector(input_args)); + if (!input_args_value.get()) { + LOG(WARNING) << "Failed to convert PP_Var input arguments."; + return PP_ERROR_BADARGUMENT; + } + + PluginResource::Call<PpapiPluginMsg_ExtensionsCommon_CallReply>( + dest, + PpapiHostMsg_ExtensionsCommon_Call(request_name, *input_args_value), + base::Bind(&ExtensionsCommonResource::OnPluginMsgCallReply, + base::Unretained(this), output_args, callback)); + return PP_OK_COMPLETIONPENDING; +} + +void ExtensionsCommonResource::CommonPost(Destination dest, + const std::string& request_name, + const std::vector<PP_Var>& args) { + scoped_ptr<base::ListValue> args_value(CreateListValueFromVarVector(args)); + if (!args_value.get()) { + LOG(WARNING) << "Failed to convert PP_Var input arguments."; + return; + } + + PluginResource::Post( + dest, PpapiHostMsg_ExtensionsCommon_Post(request_name, *args_value)); +} + +void ExtensionsCommonResource::OnPluginMsgCallReply( + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const base::ListValue& output) { + // |output_args| may be invalid and shouldn't be accessed if the callback has + // been called. + if (!TrackedCallback::IsPending(callback)) + return; + + int32_t result = params.result(); + + // If the size doesn't match, something must be really wrong. + CHECK_EQ(output_args.size(), output.GetSize()); + + std::vector<PP_Var> output_vars; + if (CreateVarVectorFromListValue(output, &output_vars)) { + DCHECK_EQ(output_args.size(), output_vars.size()); + std::vector<PP_Var>::const_iterator src_iter = output_vars.begin(); + std::vector<PP_Var*>::const_iterator dest_iter = output_args.begin(); + for (; src_iter != output_vars.end() && dest_iter != output_args.end(); + ++src_iter, ++dest_iter) { + **dest_iter = *src_iter; + } + } else { + NOTREACHED(); + result = PP_ERROR_FAILED; + for (std::vector<PP_Var*>::const_iterator dest_iter = output_args.begin(); + dest_iter != output_args.end(); + ++dest_iter) { + **dest_iter = PP_MakeUndefined(); + } + } + + callback->Run(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/extensions_common_resource.h b/chromium/ppapi/proxy/extensions_common_resource.h new file mode 100644 index 00000000000..b3ec366a0d9 --- /dev/null +++ b/chromium/ppapi/proxy/extensions_common_resource.h @@ -0,0 +1,68 @@ +// 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 PPAPI_PROXY_EXTENSIONS_COMMON_RESOURCE_H_ +#define PPAPI_PROXY_EXTENSIONS_COMMON_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/extensions_common_api.h" + +namespace base { +class ListValue; +} + +namespace ppapi { +namespace proxy { + +class ResourceMessageReplyParams; + +class ExtensionsCommonResource : public PluginResource, + public thunk::ExtensionsCommon_API { + public: + ExtensionsCommonResource(Connection connection, PP_Instance instance); + virtual ~ExtensionsCommonResource(); + + // Resource overrides. + virtual thunk::ExtensionsCommon_API* AsExtensionsCommon_API() OVERRIDE; + + // ExtensionsCommon_API implementation. + virtual int32_t CallRenderer( + const std::string& request_name, + const std::vector<PP_Var>& input_args, + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void PostRenderer(const std::string& request_name, + const std::vector<PP_Var>& args) OVERRIDE; + virtual int32_t CallBrowser(const std::string& request_name, + const std::vector<PP_Var>& input_args, + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void PostBrowser(const std::string& request_name, + const std::vector<PP_Var>& args) OVERRIDE; + + private: + int32_t CommonCall(Destination dest, + const std::string& request_name, + const std::vector<PP_Var>& input_args, + const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback); + void CommonPost(Destination dest, + const std::string& request_name, + const std::vector<PP_Var>& args); + + void OnPluginMsgCallReply(const std::vector<PP_Var*>& output_args, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const base::ListValue& output); + + DISALLOW_COPY_AND_ASSIGN(ExtensionsCommonResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_EXTENSIONS_COMMON_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/file_chooser_resource.cc b/chromium/ppapi/proxy/file_chooser_resource.cc new file mode 100644 index 00000000000..ebd545cfc38 --- /dev/null +++ b/chromium/ppapi/proxy/file_chooser_resource.cc @@ -0,0 +1,149 @@ +// 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 "ppapi/proxy/file_chooser_resource.h" + +#include "base/bind.h" +#include "base/strings/string_split.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +FileChooserResource::FileChooserResource(Connection connection, + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const std::string& accept_types) + : PluginResource(connection, instance), + mode_(mode) { + PopulateAcceptTypes(accept_types, &accept_types_); +} + +FileChooserResource::~FileChooserResource() { +} + +thunk::PPB_FileChooser_API* FileChooserResource::AsPPB_FileChooser_API() { + return this; +} + +int32_t FileChooserResource::Show(const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + return ShowWithoutUserGesture(PP_FALSE, PP_MakeUndefined(), output, callback); +} + +int32_t FileChooserResource::ShowWithoutUserGesture( + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + int32_t result = ShowInternal(save_as, suggested_file_name, callback); + if (result == PP_OK_COMPLETIONPENDING) + output_.set_pp_array_output(output); + return result; +} + +int32_t FileChooserResource::Show0_5(scoped_refptr<TrackedCallback> callback) { + return ShowInternal(PP_FALSE, PP_MakeUndefined(), callback); +} + +PP_Resource FileChooserResource::GetNextChosenFile() { + if (file_queue_.empty()) + return 0; + + // Return the next resource in the queue. It will already have been addrefed + // (they're currently owned by the FileChooser) and returning it transfers + // ownership of that reference to the plugin. + PP_Resource next = file_queue_.front(); + file_queue_.pop(); + return next; +} + +int32_t FileChooserResource::ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, + scoped_refptr<TrackedCallback> callback) { + return ShowInternal(save_as, suggested_file_name, callback); +} + +// static +void FileChooserResource::PopulateAcceptTypes( + const std::string& input, + std::vector<std::string>* output) { + if (input.empty()) + return; + + std::vector<std::string> type_list; + base::SplitString(input, ',', &type_list); + output->reserve(type_list.size()); + + for (size_t i = 0; i < type_list.size(); ++i) { + std::string type = type_list[i]; + TrimWhitespaceASCII(type, TRIM_ALL, &type); + + // If the type is a single character, it definitely cannot be valid. In the + // case of a file extension it would be a single ".". In the case of a MIME + // type it would just be a "/". + if (type.length() < 2) + continue; + if (type.find_first_of('/') == std::string::npos && type[0] != '.') + continue; + StringToLowerASCII(&type); + output->push_back(type); + } +} + +void FileChooserResource::OnPluginMsgShowReply( + const ResourceMessageReplyParams& params, + const std::vector<PPB_FileRef_CreateInfo>& chosen_files) { + if (output_.is_valid()) { + // Using v0.6 of the API with the output array. + std::vector<PP_Resource> files; + for (size_t i = 0; i < chosen_files.size(); i++) + files.push_back(PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); + output_.StoreResourceVector(files); + } else { + // Convert each of the passed in file infos to resources. These will be + // owned by the FileChooser object until they're passed to the plugin. + DCHECK(file_queue_.empty()); + for (size_t i = 0; i < chosen_files.size(); i++) { + file_queue_.push(PPB_FileRef_Proxy::DeserializeFileRef( + chosen_files[i])); + } + } + + // Notify the plugin of the new data. + callback_->Run(params.result()); + // DANGER: May delete |this|! +} + +int32_t FileChooserResource::ShowInternal( + PP_Bool save_as, + const PP_Var& suggested_file_name, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(callback_)) + return PP_ERROR_INPROGRESS; + + if (!sent_create_to_renderer()) + SendCreate(RENDERER, PpapiHostMsg_FileChooser_Create()); + + callback_ = callback; + StringVar* sugg_str = StringVar::FromPPVar(suggested_file_name); + + PpapiHostMsg_FileChooser_Show msg( + PP_ToBool(save_as), + mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE, + sugg_str ? sugg_str->value() : std::string(), + accept_types_); + Call<PpapiPluginMsg_FileChooser_ShowReply>(RENDERER, msg, + base::Bind(&FileChooserResource::OnPluginMsgShowReply, this)); + return PP_OK_COMPLETIONPENDING; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/file_chooser_resource.h b/chromium/ppapi/proxy/file_chooser_resource.h new file mode 100644 index 00000000000..58331db7f4f --- /dev/null +++ b/chromium/ppapi/proxy/file_chooser_resource.h @@ -0,0 +1,85 @@ +// 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_PROXY_FILE_CHOOSER_RESOURCE_H_ +#define PPAPI_PROXY_FILE_CHOOSER_RESOURCE_H_ + +#include <queue> +#include <string> +#include <vector> + +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_file_chooser_api.h" + +namespace ppapi { + +struct PPB_FileRef_CreateInfo; + +namespace proxy { + +class PPAPI_PROXY_EXPORT FileChooserResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_FileChooser_API) { + public: + FileChooserResource(Connection connection, + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const std::string& accept_types); + virtual ~FileChooserResource(); + + // Resource overrides. + virtual thunk::PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; + + // PPB_FileChooser_API. + virtual int32_t Show(const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t ShowWithoutUserGesture( + PP_Bool save_as, + PP_Var suggested_file_name, + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Show0_5(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Resource GetNextChosenFile() OVERRIDE; + virtual int32_t ShowWithoutUserGesture0_5( + PP_Bool save_as, + PP_Var suggested_file_name, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + // Parses the accept string into the given vector. + static void PopulateAcceptTypes(const std::string& input, + std::vector<std::string>* output); + + private: + void OnPluginMsgShowReply( + const ResourceMessageReplyParams& params, + const std::vector<PPB_FileRef_CreateInfo>& chosen_files); + + int32_t ShowInternal(PP_Bool save_as, + const PP_Var& suggested_file_name, + scoped_refptr<TrackedCallback> callback); + + PP_FileChooserMode_Dev mode_; + std::vector<std::string> accept_types_; + + // When using v0.6 of the API, contains the array output info. + ArrayWriter output_; + + // When using v0.5 of the API, contains all files returned by the current + // show callback that haven't yet been given to the plugin. The plugin will + // repeatedly call us to get the next file, and we'll vend those out of this + // queue, removing them when ownership has transferred to the plugin. + std::queue<PP_Resource> file_queue_; + + scoped_refptr<TrackedCallback> callback_; + + DISALLOW_COPY_AND_ASSIGN(FileChooserResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FILE_CHOOSER_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/file_chooser_resource_unittest.cc b/chromium/ppapi/proxy/file_chooser_resource_unittest.cc new file mode 100644 index 00000000000..a5801eed161 --- /dev/null +++ b/chromium/ppapi/proxy/file_chooser_resource_unittest.cc @@ -0,0 +1,146 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop/message_loop.h" +#include "ppapi/c/dev/ppb_file_chooser_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/file_chooser_resource.h" +#include "ppapi/proxy/locking_resource_releaser.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest FileChooserResourceTest; + +void* GetFileRefDataBuffer(void* user_data, + uint32_t element_count, + uint32_t element_size) { + EXPECT_TRUE(element_size == sizeof(PP_Resource)); + std::vector<PP_Resource>* output = + static_cast<std::vector<PP_Resource>*>(user_data); + output->resize(element_count); + if (element_count > 0) + return &(*output)[0]; + return NULL; +} + +void DoNothingCallback(void* user_data, int32_t result) { +} + +// Calls PopulateAcceptTypes and verifies that the resulting array contains +// the given values. The values may be NULL if there aren't expected to be +// that many results. +bool CheckParseAcceptType(const std::string& input, + const char* expected1, + const char* expected2) { + std::vector<std::string> output; + FileChooserResource::PopulateAcceptTypes(input, &output); + + const size_t kCount = 2; + const char* expected[kCount] = { expected1, expected2 }; + + for (size_t i = 0; i < kCount; i++) { + if (!expected[i]) + return i == output.size(); + if (output.size() <= i) + return false; + if (output[i] != expected[i]) + return false; + } + + return output.size() == kCount; +} + +} // namespace + +// Does a full test of Show() and reply functionality in the plugin side using +// the public C interfaces. +TEST_F(FileChooserResourceTest, Show) { + const PPB_FileChooser_Dev_0_6* chooser_iface = + thunk::GetPPB_FileChooser_Dev_0_6_Thunk(); + LockingResourceReleaser res( + chooser_iface->Create(pp_instance(), PP_FILECHOOSERMODE_OPEN, + PP_MakeUndefined())); + + std::vector<PP_Resource> dest; + PP_ArrayOutput output; + output.GetDataBuffer = &GetFileRefDataBuffer; + output.user_data = &dest; + + int32_t result = chooser_iface->Show( + res.get(), output, PP_MakeCompletionCallback(&DoNothingCallback, NULL)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + // Should have sent a "show" message. + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_FileChooser_Show::ID, ¶ms, &msg)); + + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(PP_OK); + + // Synthesize a response with one file ref in it. Note that it must have a + // host resource value set or deserialization will fail. Since there isn't + // actually a host, this can be whatever we want. + std::vector<PPB_FileRef_CreateInfo> create_info_array; + PPB_FileRef_CreateInfo create_info; + create_info.resource.SetHostResource(pp_instance(), 123); + create_info.path = "foo/bar"; + create_info.name = "baz"; + create_info_array.push_back(create_info); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply(reply_params, + PpapiPluginMsg_FileChooser_ShowReply(create_info_array)))); + + // Should have populated our vector. + ASSERT_EQ(1u, dest.size()); + LockingResourceReleaser dest_deletor(dest[0]); // Ensure it's cleaned up. + + const PPB_FileRef_1_0* file_ref_iface = thunk::GetPPB_FileRef_1_0_Thunk(); + EXPECT_EQ(PP_FILESYSTEMTYPE_EXTERNAL, + file_ref_iface->GetFileSystemType(dest[0])); + + PP_Var name_var(file_ref_iface->GetName(dest[0])); + { + ProxyAutoLock lock; + ScopedPPVar release_name_var(ScopedPPVar::PassRef(), name_var); + EXPECT_VAR_IS_STRING(create_info.name, name_var); + } + // Path should be undefined since it's external filesystem. + PP_Var path_var(file_ref_iface->GetPath(dest[0])); + { + ProxyAutoLock lock; + ScopedPPVar release_path_var(ScopedPPVar::PassRef(), path_var); + EXPECT_EQ(PP_VARTYPE_UNDEFINED, path_var.type); + } +} + +TEST_F(FileChooserResourceTest, PopulateAcceptTypes) { + EXPECT_TRUE(CheckParseAcceptType(std::string(), NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType("/", NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType(".", NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType(",, , ", NULL, NULL)); + + EXPECT_TRUE(CheckParseAcceptType("app/txt", "app/txt", NULL)); + EXPECT_TRUE(CheckParseAcceptType("app/txt,app/pdf", "app/txt", "app/pdf")); + EXPECT_TRUE(CheckParseAcceptType(" app/txt , app/pdf ", + "app/txt", "app/pdf")); + + // No dot or slash ones should be skipped. + EXPECT_TRUE(CheckParseAcceptType("foo", NULL, NULL)); + EXPECT_TRUE(CheckParseAcceptType("foo,.txt", ".txt", NULL)); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/file_io_resource.cc b/chromium/ppapi/proxy/file_io_resource.cc new file mode 100644 index 00000000000..76ee51c4e9c --- /dev/null +++ b/chromium/ppapi/proxy/file_io_resource.cc @@ -0,0 +1,451 @@ +// 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 "ppapi/proxy/file_io_resource.h" + +#include "base/bind.h" +#include "base/task_runner_util.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/file_type_conversion.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_file_ref_api.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_FileIO_API; +using ppapi::thunk::PPB_FileRef_API; + +namespace { + +// We must allocate a buffer sized according to the request of the plugin. To +// reduce the chance of out-of-memory errors, we cap the read size to 32MB. +// This is OK since the API specifies that it may perform a partial read. +static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB + +// An adapter to let Read() share the same implementation with ReadToArray(). +void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) { + return user_data; +} + +// File thread task to close the file handle. +void DoClose(base::PlatformFile file) { + base::ClosePlatformFile(file); +} + +} // namespace + +namespace ppapi { +namespace proxy { + +FileIOResource::QueryOp::QueryOp(PP_FileHandle file_handle) + : file_handle_(file_handle) { +} + +FileIOResource::QueryOp::~QueryOp() { +} + +int32_t FileIOResource::QueryOp::DoWork() { + return base::GetPlatformFileInfo(file_handle_, &file_info_) ? + PP_OK : PP_ERROR_FAILED; +} + +FileIOResource::ReadOp::ReadOp(PP_FileHandle file_handle, + int64_t offset, + int32_t bytes_to_read) + : file_handle_(file_handle), + offset_(offset), + bytes_to_read_(bytes_to_read) { +} + +FileIOResource::ReadOp::~ReadOp() { +} + +int32_t FileIOResource::ReadOp::DoWork() { + DCHECK(!buffer_.get()); + buffer_.reset(new char[bytes_to_read_]); + return base::ReadPlatformFile( + file_handle_, offset_, buffer_.get(), bytes_to_read_); +} + +FileIOResource::FileIOResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance), + file_handle_(base::kInvalidPlatformFileValue), + file_system_type_(PP_FILESYSTEMTYPE_INVALID) { + SendCreate(RENDERER, PpapiHostMsg_FileIO_Create()); +} + +FileIOResource::~FileIOResource() { + CloseFileHandle(); +} + +PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() { + return this; +} + +int32_t FileIOResource::Open(PP_Resource file_ref, + int32_t open_flags, + scoped_refptr<TrackedCallback> callback) { + EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true); + if (enter.failed()) + return PP_ERROR_BADRESOURCE; + + PPB_FileRef_API* file_ref_api = enter.object(); + PP_FileSystemType type = file_ref_api->GetFileSystemType(); + if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT && + type != PP_FILESYSTEMTYPE_LOCALTEMPORARY && + type != PP_FILESYSTEMTYPE_EXTERNAL && + type != PP_FILESYSTEMTYPE_ISOLATED) { + NOTREACHED(); + return PP_ERROR_FAILED; + } + file_system_type_ = type; + + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_EXCLUSIVE, false); + if (rv != PP_OK) + return rv; + + Call<PpapiPluginMsg_FileIO_OpenReply>(RENDERER, + PpapiHostMsg_FileIO_Open( + enter.resource()->host_resource().host_resource(), + open_flags), + base::Bind(&FileIOResource::OnPluginMsgOpenFileComplete, this, + callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::Query(PP_FileInfo* info, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_EXCLUSIVE, true); + if (rv != PP_OK) + return rv; + if (!info) + return PP_ERROR_BADARGUMENT; + if (file_handle_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_)); + + // If the callback is blocking, perform the task on the calling thread. + if (callback->is_blocking()) { + int32_t result; + { + // Release the proxy lock while making a potentially slow file call. + ProxyAutoUnlock unlock; + result = query_op->DoWork(); + } + return OnQueryComplete(query_op, info, result); + } + + // For the non-blocking case, post a task to the file thread and add a + // completion task to write the result. + base::PostTaskAndReplyWithResult( + PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()), + FROM_HERE, + Bind(&FileIOResource::QueryOp::DoWork, query_op), + RunWhileLocked(Bind(&TrackedCallback::Run, callback))); + callback->set_completion_task( + Bind(&FileIOResource::OnQueryComplete, this, query_op, info)); + + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::Touch(PP_Time last_access_time, + PP_Time last_modified_time, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_EXCLUSIVE, true); + if (rv != PP_OK) + return rv; + + Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, + PpapiHostMsg_FileIO_Touch(last_access_time, last_modified_time), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, + callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::Read(int64_t offset, + char* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_READ, true); + if (rv != PP_OK) + return rv; + + PP_ArrayOutput output_adapter; + output_adapter.GetDataBuffer = &DummyGetDataBuffer; + output_adapter.user_data = buffer; + return ReadValidated(offset, bytes_to_read, output_adapter, callback); +} + +int32_t FileIOResource::ReadToArray(int64_t offset, + int32_t max_read_length, + PP_ArrayOutput* array_output, + scoped_refptr<TrackedCallback> callback) { + DCHECK(array_output); + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_READ, true); + if (rv != PP_OK) + return rv; + + return ReadValidated(offset, max_read_length, *array_output, callback); +} + +int32_t FileIOResource::Write(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_WRITE, true); + if (rv != PP_OK) + return rv; + + // TODO(brettw) it would be nice to use a shared memory buffer for large + // writes rather than having to copy to a string (which will involve a number + // of extra copies to serialize over IPC). + Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, + PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, + callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::SetLength(int64_t length, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_EXCLUSIVE, true); + if (rv != PP_OK) + return rv; + + Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, + PpapiHostMsg_FileIO_SetLength(length), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, + callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_EXCLUSIVE, true); + if (rv != PP_OK) + return rv; + + Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, + PpapiHostMsg_FileIO_Flush(), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, + callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +void FileIOResource::Close() { + CloseFileHandle(); + Post(RENDERER, PpapiHostMsg_FileIO_Close()); +} + +int32_t FileIOResource::GetOSFileDescriptor() { + int32_t file_descriptor; + // Only available when running in process. + SyncCall<PpapiPluginMsg_FileIO_GetOSFileDescriptorReply>( + RENDERER, PpapiHostMsg_FileIO_GetOSFileDescriptor(), &file_descriptor); + return file_descriptor; +} + +int32_t FileIOResource::RequestOSFileHandle( + PP_FileHandle* handle, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = state_manager_.CheckOperationState( + FileIOStateManager::OPERATION_EXCLUSIVE, true); + if (rv != PP_OK) + return rv; + + Call<PpapiPluginMsg_FileIO_RequestOSFileHandleReply>(RENDERER, + PpapiHostMsg_FileIO_RequestOSFileHandle(), + base::Bind(&FileIOResource::OnPluginMsgRequestOSFileHandleComplete, this, + callback, handle)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::WillWrite(int64_t offset, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, + PpapiHostMsg_FileIO_WillWrite(offset, bytes_to_write), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::WillSetLength(int64_t length, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileIO_GeneralReply>(RENDERER, + PpapiHostMsg_FileIO_WillSetLength(length), + base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, callback)); + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileIOResource::ReadValidated(int64_t offset, + int32_t bytes_to_read, + const PP_ArrayOutput& array_output, + scoped_refptr<TrackedCallback> callback) { + if (bytes_to_read < 0) + return PP_ERROR_FAILED; + if (file_handle_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + + state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ); + + bytes_to_read = std::min(bytes_to_read, kMaxReadSize); + scoped_refptr<ReadOp> read_op( + new ReadOp(file_handle_, offset, bytes_to_read)); + if (callback->is_blocking()) { + int32_t result; + { + // Release the proxy lock while making a potentially slow file call. + ProxyAutoUnlock unlock; + result = read_op->DoWork(); + } + return OnReadComplete(read_op, array_output, result); + } + + // For the non-blocking case, post a task to the file thread. + base::PostTaskAndReplyWithResult( + PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()), + FROM_HERE, + Bind(&FileIOResource::ReadOp::DoWork, read_op), + RunWhileLocked(Bind(&TrackedCallback::Run, callback))); + callback->set_completion_task( + Bind(&FileIOResource::OnReadComplete, this, read_op, array_output)); + + return PP_OK_COMPLETIONPENDING; +} + +void FileIOResource::CloseFileHandle() { + if (file_handle_ != base::kInvalidPlatformFileValue) { + // Close our local fd on the file thread. + base::TaskRunner* file_task_runner = + PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()); + file_task_runner->PostTask(FROM_HERE, + base::Bind(&DoClose, file_handle_)); + + file_handle_ = base::kInvalidPlatformFileValue; + } +} + +int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op, + PP_FileInfo* info, + int32_t result) { + DCHECK(state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_EXCLUSIVE); + + if (result == PP_OK) { + // This writes the file info into the plugin's PP_FileInfo struct. + ppapi::PlatformFileInfoToPepperFileInfo(query_op->file_info(), + file_system_type_, + info); + } + state_manager_.SetOperationFinished(); + return result; +} + +int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op, + PP_ArrayOutput array_output, + int32_t result) { + DCHECK(state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_READ); + if (result >= 0) { + ArrayWriter output; + output.set_pp_array_output(array_output); + if (output.is_valid()) + output.StoreArray(read_op->buffer(), result); + else + result = PP_ERROR_FAILED; + } else { + // The read operation failed. + result = PP_ERROR_FAILED; + } + state_manager_.SetOperationFinished(); + return result; +} + +void FileIOResource::OnPluginMsgGeneralComplete( + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params) { + DCHECK(state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_EXCLUSIVE || + state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_WRITE); + // End this operation now, so the user's callback can execute another FileIO + // operation, assuming there are no other pending operations. + state_manager_.SetOperationFinished(); + callback->Run(params.result()); +} + +void FileIOResource::OnPluginMsgOpenFileComplete( + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params) { + DCHECK(state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_EXCLUSIVE); + if (params.result() == PP_OK) + state_manager_.SetOpenSucceed(); + + int32_t result = params.result(); + IPC::PlatformFileForTransit transit_file; + if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file)) + file_handle_ = IPC::PlatformFileForTransitToPlatformFile(transit_file); + // End this operation now, so the user's callback can execute another FileIO + // operation, assuming there are no other pending operations. + state_manager_.SetOperationFinished(); + callback->Run(result); +} + +void FileIOResource::OnPluginMsgRequestOSFileHandleComplete( + scoped_refptr<TrackedCallback> callback, + PP_FileHandle* output_handle, + const ResourceMessageReplyParams& params) { + DCHECK(state_manager_.get_pending_operation() == + FileIOStateManager::OPERATION_EXCLUSIVE); + + if (!TrackedCallback::IsPending(callback)) { + state_manager_.SetOperationFinished(); + return; + } + + int32_t result = params.result(); + IPC::PlatformFileForTransit transit_file; + if (!params.TakeFileHandleAtIndex(0, &transit_file)) + result = PP_ERROR_FAILED; + *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file); + + // End this operation now, so the user's callback can execute another FileIO + // operation, assuming there are no other pending operations. + state_manager_.SetOperationFinished(); + callback->Run(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/file_io_resource.h b/chromium/ppapi/proxy/file_io_resource.h new file mode 100644 index 00000000000..1a888d199d6 --- /dev/null +++ b/chromium/ppapi/proxy/file_io_resource.h @@ -0,0 +1,146 @@ +// 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_PROXY_FILE_IO_RESOURCE_H_ +#define PPAPI_PROXY_FILE_IO_RESOURCE_H_ + +#include <string> + +#include "ppapi/c/private/pp_file_handle.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/file_io_state_manager.h" +#include "ppapi/thunk/ppb_file_io_api.h" + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +class PPAPI_PROXY_EXPORT FileIOResource + : public PluginResource, + public thunk::PPB_FileIO_API { + public: + FileIOResource(Connection connection, PP_Instance instance); + virtual ~FileIOResource(); + + // Resource overrides. + virtual thunk::PPB_FileIO_API* AsPPB_FileIO_API() OVERRIDE; + + // PPB_FileIO_API implementation. + virtual int32_t Open(PP_Resource file_ref, + int32_t open_flags, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Query(PP_FileInfo* info, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Touch(PP_Time last_access_time, + PP_Time last_modified_time, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Read(int64_t offset, + char* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t ReadToArray(int64_t offset, + int32_t max_read_length, + PP_ArrayOutput* array_output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Write(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t SetLength(int64_t length, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Flush(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + virtual int32_t GetOSFileDescriptor() OVERRIDE; + virtual int32_t RequestOSFileHandle( + PP_FileHandle* handle, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t WillWrite(int64_t offset, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t WillSetLength( + int64_t length, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + // Class to perform file query operations across multiple threads. + class QueryOp : public base::RefCountedThreadSafe<QueryOp> { + public: + explicit QueryOp(PP_FileHandle file_handle); + + // Queries the file. Called on the file thread (non-blocking) or the plugin + // thread (blocking). This should not be called when we hold the proxy lock. + int32_t DoWork(); + + const base::PlatformFileInfo& file_info() const { return file_info_; } + + private: + friend class base::RefCountedThreadSafe<QueryOp>; + ~QueryOp(); + + PP_FileHandle file_handle_; + base::PlatformFileInfo file_info_; + }; + + // Class to perform file read operations across multiple threads. + class ReadOp : public base::RefCountedThreadSafe<ReadOp> { + public: + ReadOp(PP_FileHandle file_handle, int64_t offset, int32_t bytes_to_read); + + // Reads the file. Called on the file thread (non-blocking) or the plugin + // thread (blocking). This should not be called when we hold the proxy lock. + int32_t DoWork(); + + char* buffer() const { return buffer_.get(); } + + private: + friend class base::RefCountedThreadSafe<ReadOp>; + ~ReadOp(); + + PP_FileHandle file_handle_; + int64_t offset_; + int32_t bytes_to_read_; + scoped_ptr<char[]> buffer_; + }; + + int32_t ReadValidated(int64_t offset, + int32_t bytes_to_read, + const PP_ArrayOutput& array_output, + scoped_refptr<TrackedCallback> callback); + + void CloseFileHandle(); + + + // Completion tasks for file operations that are done in the plugin. + int32_t OnQueryComplete(scoped_refptr<QueryOp> query_op, + PP_FileInfo* info, + int32_t result); + int32_t OnReadComplete(scoped_refptr<ReadOp> read_op, + PP_ArrayOutput array_output, + int32_t result); + + // Reply message handlers for operations that are done in the host. + void OnPluginMsgGeneralComplete(scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params); + void OnPluginMsgOpenFileComplete(scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params); + void OnPluginMsgRequestOSFileHandleComplete( + scoped_refptr<TrackedCallback> callback, + PP_FileHandle* output_handle, + const ResourceMessageReplyParams& params); + + PP_FileHandle file_handle_; + PP_FileSystemType file_system_type_; + FileIOStateManager state_manager_; + + DISALLOW_COPY_AND_ASSIGN(FileIOResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FILE_IO_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/file_ref_resource.cc b/chromium/ppapi/proxy/file_ref_resource.cc new file mode 100644 index 00000000000..4c098a567a9 --- /dev/null +++ b/chromium/ppapi/proxy/file_ref_resource.cc @@ -0,0 +1,279 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/file_ref_resource.h" + +#include "ppapi/c/pp_directory_entry.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/file_ref_util.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_file_system_api.h" + +namespace ppapi { +namespace proxy { + +FileRefResource::FileRefResource( + Connection connection, + PP_Instance instance, + const FileRef_CreateInfo& create_info) + : PluginResource(connection, instance), + create_info_(create_info), + file_system_resource_(create_info.file_system_plugin_resource) { + if (create_info_.file_system_type != PP_FILESYSTEMTYPE_EXTERNAL) { + // If path ends with a slash, then normalize it away unless path is + // the root path. + int path_size = create_info_.internal_path.size(); + if (path_size > 1 && create_info_.internal_path.at(path_size - 1) == '/') + create_info_.internal_path.erase(path_size - 1, 1); + + path_var_ = new StringVar(create_info_.internal_path); + + create_info_.display_name = GetNameForInternalFilePath( + create_info_.internal_path); + } + name_var_ = new StringVar(create_info_.display_name); + + if (create_info_.pending_host_resource_id != 0) { + AttachToPendingHost(BROWSER, create_info_.pending_host_resource_id); + } else { + CHECK(create_info_.file_system_type != PP_FILESYSTEMTYPE_EXTERNAL); + SendCreate(BROWSER, PpapiHostMsg_FileRef_CreateInternal( + create_info.file_system_plugin_resource, + create_info.internal_path)); + } +} + +FileRefResource::~FileRefResource() { +} + +//static +PP_Resource FileRefResource::CreateFileRef( + Connection connection, + PP_Instance instance, + const FileRef_CreateInfo& create_info) { + // If we have a valid file_system resource, ensure that its type matches that + // of the fs_type parameter. + if (create_info.file_system_plugin_resource != 0) { + thunk::EnterResourceNoLock<thunk::PPB_FileSystem_API> enter( + create_info.file_system_plugin_resource, true); + if (enter.failed()) + return 0; + if (enter.object()->GetType() != create_info.file_system_type) { + NOTREACHED() << "file system type mismatch with resource"; + return 0; + } + } + + if (create_info.file_system_type == PP_FILESYSTEMTYPE_LOCALPERSISTENT || + create_info.file_system_type == PP_FILESYSTEMTYPE_LOCALTEMPORARY) { + if (!IsValidInternalPath(create_info.internal_path)) + return 0; + } + return (new FileRefResource(connection, + instance, + create_info))->GetReference(); +} + +thunk::PPB_FileRef_API* FileRefResource::AsPPB_FileRef_API() { + // TODO: return "this" once we update PPB_FileRef_API. + NOTREACHED(); + return NULL; +} + +PP_FileSystemType FileRefResource::GetFileSystemType() const { + return create_info_.file_system_type; +} + +PP_Var FileRefResource::GetName() const { + return name_var_->GetPPVar(); +} + +PP_Var FileRefResource::GetPath() const { + if (create_info_.file_system_type == PP_FILESYSTEMTYPE_EXTERNAL) + return PP_MakeUndefined(); + return path_var_->GetPPVar(); +} + +PP_Resource FileRefResource::GetParent() { + if (create_info_.file_system_type == PP_FILESYSTEMTYPE_EXTERNAL) + return 0; + + size_t pos = create_info_.internal_path.rfind('/'); + CHECK(pos != std::string::npos); + if (pos == 0) + pos++; + std::string parent_path = create_info_.internal_path.substr(0, pos); + + ppapi::FileRef_CreateInfo parent_info; + parent_info.file_system_type = create_info_.file_system_type; + parent_info.internal_path = parent_path; + parent_info.display_name = GetNameForInternalFilePath(parent_path); + parent_info.file_system_plugin_resource = + create_info_.file_system_plugin_resource; + + return (new FileRefResource(connection(), + pp_instance(), + parent_info))->GetReference(); +} + +int32_t FileRefResource::MakeDirectory( + PP_Bool make_ancestors, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileRef_MakeDirectoryReply>( + BROWSER, + PpapiHostMsg_FileRef_MakeDirectory(PP_TRUE == make_ancestors), + base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRefResource::Touch(PP_Time last_access_time, + PP_Time last_modified_time, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileRef_TouchReply>( + BROWSER, + PpapiHostMsg_FileRef_Touch(last_access_time, + last_modified_time), + base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRefResource::Delete(scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileRef_DeleteReply>( + BROWSER, + PpapiHostMsg_FileRef_Delete(), + base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRefResource::Rename(PP_Resource new_file_ref, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileRef_RenameReply>( + BROWSER, + PpapiHostMsg_FileRef_Rename(new_file_ref), + base::Bind(&FileRefResource::RunTrackedCallback, this, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRefResource::Query(PP_FileInfo* info, + scoped_refptr<TrackedCallback> callback) { + if (info == NULL) + return PP_ERROR_BADARGUMENT; + + Call<PpapiPluginMsg_FileRef_QueryReply>( + BROWSER, + PpapiHostMsg_FileRef_Query(), + base::Bind(&FileRefResource::OnQueryReply, this, info, callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRefResource::ReadDirectoryEntries( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply>( + BROWSER, + PpapiHostMsg_FileRef_ReadDirectoryEntries(), + base::Bind(&FileRefResource::OnDirectoryEntriesReply, + this, output, callback)); + return PP_OK_COMPLETIONPENDING; +} + +/* +const FileRef_CreateInfo& FileRefResource::GetCreateInfo() const { + return create_info_; +} +*/ +const PPB_FileRef_CreateInfo& FileRefResource::GetCreateInfo() const { + // FIXME + NOTREACHED(); + PPB_FileRef_CreateInfo *info = new PPB_FileRef_CreateInfo(); + return *info; +} + +// TODO(teravest): Remove this when we are finished moving to the new proxy. +int32_t FileRefResource::QueryInHost(linked_ptr<PP_FileInfo> info, + scoped_refptr<TrackedCallback> callback) { + NOTREACHED(); + return PP_ERROR_FAILED; +} + +// TODO(teravest): Remove this when we are finished moving to the new proxy. +int32_t FileRefResource::ReadDirectoryEntriesInHost( + linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > files, + linked_ptr<std::vector<PP_FileType> > file_types, + scoped_refptr<TrackedCallback> callback) { + NOTREACHED(); + return PP_ERROR_FAILED; +} + +PP_Var FileRefResource::GetAbsolutePath() { + if (!absolute_path_var_.get()) { + std::string absolute_path; + int32_t result = SyncCall<PpapiPluginMsg_FileRef_GetAbsolutePathReply>( + BROWSER, PpapiHostMsg_FileRef_GetAbsolutePath(), &absolute_path); + if (result != PP_OK) + return PP_MakeUndefined(); + absolute_path_var_ = new StringVar(absolute_path); + } + return absolute_path_var_->GetPPVar(); +} + +void FileRefResource::RunTrackedCallback( + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params) { + if (TrackedCallback::IsPending(callback)) + callback->Run(params.result()); +} + +void FileRefResource::OnQueryReply( + PP_FileInfo* out_info, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const PP_FileInfo& info) { + if (!TrackedCallback::IsPending(callback)) + return; + + if (params.result() == PP_OK) + *out_info = info; + callback->Run(params.result()); +} + +void FileRefResource::OnDirectoryEntriesReply( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::vector<ppapi::FileRef_CreateInfo>& infos, + const std::vector<PP_FileType>& file_types) { + if (!TrackedCallback::IsPending(callback)) + return; + + if (params.result() == PP_OK) { + ArrayWriter writer(output); + if (!writer.is_valid()) { + callback->Run(PP_ERROR_BADARGUMENT); + return; + } + + std::vector<PP_DirectoryEntry> entries; + for (size_t i = 0; i < infos.size(); ++i) { + PP_DirectoryEntry entry; + entry.file_ref = FileRefResource::CreateFileRef(connection(), + pp_instance(), + infos[i]); + entry.file_type = file_types[i]; + entries.push_back(entry); + } + + writer.StoreVector(entries); + } + callback->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/file_ref_resource.h b/chromium/ppapi/proxy/file_ref_resource.h new file mode 100644 index 00000000000..82570fbc09c --- /dev/null +++ b/chromium/ppapi/proxy/file_ref_resource.h @@ -0,0 +1,107 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ +#define PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/file_ref_create_info.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/thunk/ppb_file_ref_api.h" + +namespace ppapi { +class StringVar; + +namespace proxy { + +class PPAPI_PROXY_EXPORT FileRefResource + : public PluginResource, + public thunk::PPB_FileRef_API { + public: + static PP_Resource CreateFileRef(Connection connection, + PP_Instance instance, + const FileRef_CreateInfo& info); + + virtual ~FileRefResource(); + + // Resource implementation. + virtual thunk::PPB_FileRef_API* AsPPB_FileRef_API() OVERRIDE; + + // PPB_FileRef_API implementation. + virtual PP_FileSystemType GetFileSystemType() const OVERRIDE; + virtual PP_Var GetName() const OVERRIDE; + virtual PP_Var GetPath() const OVERRIDE; + virtual PP_Resource GetParent() OVERRIDE; + virtual int32_t MakeDirectory( + PP_Bool make_ancestors, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Touch(PP_Time last_access_time, + PP_Time last_modified_time, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Delete(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Rename(PP_Resource new_file_ref, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Query(PP_FileInfo* info, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t ReadDirectoryEntries( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual const PPB_FileRef_CreateInfo& GetCreateInfo() const OVERRIDE; + virtual int32_t QueryInHost(linked_ptr<PP_FileInfo> info, + scoped_refptr<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<TrackedCallback> callback) OVERRIDE; + + // Private API + virtual PP_Var GetAbsolutePath() OVERRIDE; + + private: + FileRefResource(Connection connection, + PP_Instance instance, + const FileRef_CreateInfo& info); + + void RunTrackedCallback(scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params); + + void OnQueryReply(PP_FileInfo* out_info, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const PP_FileInfo& info); + + void OnDirectoryEntriesReply( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::vector<ppapi::FileRef_CreateInfo>& infos, + const std::vector<PP_FileType>& file_types); + + // Populated after creation. + FileRef_CreateInfo create_info_; + + // Some file ref operations may fail if the the file system resource inside + // create_info_ is destroyed. Therefore, we explicitly hold a reference to + // the file system resource to make sure it outlives the file ref. + ScopedPPResource file_system_resource_; + + scoped_refptr<StringVar> name_var_; + scoped_refptr<StringVar> path_var_; + scoped_refptr<StringVar> absolute_path_var_; + + DISALLOW_COPY_AND_ASSIGN(FileRefResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ diff --git a/chromium/ppapi/proxy/file_system_resource.cc b/chromium/ppapi/proxy/file_system_resource.cc new file mode 100644 index 00000000000..5acac00964b --- /dev/null +++ b/chromium/ppapi/proxy/file_system_resource.cc @@ -0,0 +1,79 @@ +// 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 "ppapi/proxy/file_system_resource.h" + +#include "base/bind.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/tracked_callback.h" + +using ppapi::thunk::PPB_FileSystem_API; + +namespace ppapi { +namespace proxy { + +FileSystemResource::FileSystemResource(Connection connection, + PP_Instance instance, + PP_FileSystemType type) + : PluginResource(connection, instance), + type_(type), + called_open_(false), + callback_count_(0) { + DCHECK(type_ != PP_FILESYSTEMTYPE_INVALID); + // TODO(teravest): Temporarily create hosts in both the browser and renderer + // while we move file related hosts to the browser. + SendCreate(RENDERER, PpapiHostMsg_FileSystem_Create(type_)); + SendCreate(BROWSER, PpapiHostMsg_FileSystem_Create(type_)); +} + +FileSystemResource::~FileSystemResource() { +} + +PPB_FileSystem_API* FileSystemResource::AsPPB_FileSystem_API() { + return this; +} + +int32_t FileSystemResource::Open(int64_t expected_size, + scoped_refptr<TrackedCallback> callback) { + if (called_open_) + return PP_ERROR_FAILED; + called_open_ = true; + + Call<PpapiPluginMsg_FileSystem_OpenReply>(RENDERER, + PpapiHostMsg_FileSystem_Open(expected_size), + base::Bind(&FileSystemResource::OpenComplete, + this, + callback)); + Call<PpapiPluginMsg_FileSystem_OpenReply>(BROWSER, + PpapiHostMsg_FileSystem_Open(expected_size), + base::Bind(&FileSystemResource::OpenComplete, + this, + callback)); + return PP_OK_COMPLETIONPENDING; +} + +PP_FileSystemType FileSystemResource::GetType() { + return type_; +} + +void FileSystemResource::InitIsolatedFileSystem(const char* fsid) { + Post(RENDERER, + PpapiHostMsg_FileSystem_InitIsolatedFileSystem(std::string(fsid))); + Post(BROWSER, + PpapiHostMsg_FileSystem_InitIsolatedFileSystem(std::string(fsid))); +} + +void FileSystemResource::OpenComplete( + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params) { + ++callback_count_; + // Received callback from browser and renderer. + if (callback_count_ == 2) + callback->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/file_system_resource.h b/chromium/ppapi/proxy/file_system_resource.h new file mode 100644 index 00000000000..b104db32420 --- /dev/null +++ b/chromium/ppapi/proxy/file_system_resource.h @@ -0,0 +1,58 @@ +// 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 PPAPI_PROXY_FILE_SYSTEM_RESOURCE_H_ +#define PPAPI_PROXY_FILE_SYSTEM_RESOURCE_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/thunk/ppb_file_system_api.h" + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +class PPAPI_PROXY_EXPORT FileSystemResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_FileSystem_API) { + public: + FileSystemResource(Connection connection, + PP_Instance instance, + PP_FileSystemType type); + virtual ~FileSystemResource(); + + // Resource overrides. + virtual thunk::PPB_FileSystem_API* AsPPB_FileSystem_API() OVERRIDE; + + // PPB_FileSystem_API implementation. + virtual int32_t Open(int64_t expected_size, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_FileSystemType GetType() OVERRIDE; + + void InitIsolatedFileSystem(const char* fsid); + private: + + // Called when the host has responded to our open request. + void OpenComplete(scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params); + + PP_FileSystemType type_; + bool called_open_; + uint32_t callback_count_; + + DISALLOW_COPY_AND_ASSIGN(FileSystemResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FILE_SYSTEM_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_clipboard_resource.cc b/chromium/ppapi/proxy/flash_clipboard_resource.cc new file mode 100644 index 00000000000..5f064023f35 --- /dev/null +++ b/chromium/ppapi/proxy/flash_clipboard_resource.cc @@ -0,0 +1,156 @@ +// 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 "ppapi/proxy/flash_clipboard_resource.h" + +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// Returns whether the given clipboard type is valid. +bool IsValidClipboardType(PP_Flash_Clipboard_Type type) { + return type == PP_FLASH_CLIPBOARD_TYPE_STANDARD || + type == PP_FLASH_CLIPBOARD_TYPE_SELECTION; +} + +// Convert a PP_Var to/from a string which is transmitted to the pepper host. +// These functions assume the format is valid. +bool PPVarToClipboardString(int32_t format, + const PP_Var& var, + std::string* string_out) { + if (format == PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT || + format == PP_FLASH_CLIPBOARD_FORMAT_HTML) { + StringVar* string_var = StringVar::FromPPVar(var); + if (!string_var) + return false; + *string_out = string_var->value(); + return true; + } else { + // All other formats are expected to be array buffers. + ArrayBufferVar* array_buffer_var = ArrayBufferVar::FromPPVar(var); + if (!array_buffer_var) + return false; + *string_out = std::string(static_cast<const char*>(array_buffer_var->Map()), + array_buffer_var->ByteLength()); + return true; + } +} + +PP_Var ClipboardStringToPPVar(int32_t format, + const std::string& string) { + if (format == PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT || + format == PP_FLASH_CLIPBOARD_FORMAT_HTML) { + return StringVar::StringToPPVar(string); + } else { + // All other formats are expected to be array buffers. + return PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + string.size(), string.data()); + } +} +} // namespace + +FlashClipboardResource::FlashClipboardResource( + Connection connection, PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_FlashClipboard_Create()); +} + +FlashClipboardResource::~FlashClipboardResource() { +} + +thunk::PPB_Flash_Clipboard_API* +FlashClipboardResource::AsPPB_Flash_Clipboard_API() { + return this; +} + +uint32_t FlashClipboardResource::RegisterCustomFormat( + PP_Instance instance, + const char* format_name) { + // Check to see if the format has already been registered. + uint32_t format = clipboard_formats_.GetFormatID(format_name); + if (format != PP_FLASH_CLIPBOARD_FORMAT_INVALID) + return format; + int32_t result = + SyncCall<PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply>( + BROWSER, + PpapiHostMsg_FlashClipboard_RegisterCustomFormat(format_name), + &format); + if (result != PP_OK || format == PP_FLASH_CLIPBOARD_FORMAT_INVALID) + return PP_FLASH_CLIPBOARD_FORMAT_INVALID; + clipboard_formats_.SetRegisteredFormat(format_name, format); + return format; +} + +PP_Bool FlashClipboardResource::IsFormatAvailable( + PP_Instance instance, + PP_Flash_Clipboard_Type clipboard_type, + uint32_t format) { + if (IsValidClipboardType(clipboard_type) && + (FlashClipboardFormatRegistry::IsValidPredefinedFormat(format) || + clipboard_formats_.IsFormatRegistered(format))) { + int32_t result = SyncCall<IPC::Message>(BROWSER, + PpapiHostMsg_FlashClipboard_IsFormatAvailable(clipboard_type, format)); + return result == PP_OK ? PP_TRUE : PP_FALSE; + } + return PP_FALSE; +} + +PP_Var FlashClipboardResource::ReadData( + PP_Instance instance, + PP_Flash_Clipboard_Type clipboard_type, + uint32_t format) { + std::string value; + int32_t result = + SyncCall<PpapiPluginMsg_FlashClipboard_ReadDataReply>( + BROWSER, + PpapiHostMsg_FlashClipboard_ReadData(clipboard_type, format), + &value); + if (result != PP_OK) + return PP_MakeUndefined(); + + return ClipboardStringToPPVar(format, value); +} + +int32_t FlashClipboardResource::WriteData( + PP_Instance instance, + PP_Flash_Clipboard_Type clipboard_type, + uint32_t data_item_count, + const uint32_t formats[], + const PP_Var data_items[]) { + if (!IsValidClipboardType(clipboard_type)) + return PP_ERROR_BADARGUMENT; + std::vector<uint32_t> formats_vector; + std::vector<std::string> data_items_vector; + for (size_t i = 0; i < data_item_count; ++i) { + if (!clipboard_formats_.IsFormatRegistered(formats[i]) && + !FlashClipboardFormatRegistry::IsValidPredefinedFormat(formats[i])) { + return PP_ERROR_BADARGUMENT; + } + formats_vector.push_back(formats[i]); + std::string string; + if (!PPVarToClipboardString(formats[i], data_items[i], &string)) + return PP_ERROR_BADARGUMENT; + data_items_vector.push_back(string); + } + + Post(BROWSER, + PpapiHostMsg_FlashClipboard_WriteData( + static_cast<uint32_t>(clipboard_type), + formats_vector, + data_items_vector)); + + // Assume success, since it allows us to avoid a sync IPC. + return PP_OK; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_clipboard_resource.h b/chromium/ppapi/proxy/flash_clipboard_resource.h new file mode 100644 index 00000000000..fdb7e79a48e --- /dev/null +++ b/chromium/ppapi/proxy/flash_clipboard_resource.h @@ -0,0 +1,50 @@ +// 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_PROXY_FLASH_CLIPBOARD_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_CLIPBOARD_RESOURCE_H_ + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/shared_impl/flash_clipboard_format_registry.h" +#include "ppapi/thunk/ppb_flash_clipboard_api.h" + +namespace ppapi { +namespace proxy { + +class FlashClipboardResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_Flash_Clipboard_API) { + public: + FlashClipboardResource(Connection connection, PP_Instance instance); + virtual ~FlashClipboardResource(); + + // Resource implementation. + virtual thunk::PPB_Flash_Clipboard_API* AsPPB_Flash_Clipboard_API() OVERRIDE; + + // PPB_Flash_Clipboard_API implementation. + virtual uint32_t RegisterCustomFormat(PP_Instance instance, + const char* format_name) OVERRIDE; + virtual PP_Bool IsFormatAvailable(PP_Instance instance, + PP_Flash_Clipboard_Type clipboard_type, + uint32_t format) OVERRIDE; + virtual PP_Var ReadData(PP_Instance instance, + PP_Flash_Clipboard_Type clipboard_type, + uint32_t format) OVERRIDE; + virtual int32_t WriteData(PP_Instance instance, + PP_Flash_Clipboard_Type clipboard_type, + uint32_t data_item_count, + const uint32_t formats[], + const PP_Var data_items[]) OVERRIDE; + + private: + FlashClipboardFormatRegistry clipboard_formats_; + + DISALLOW_COPY_AND_ASSIGN(FlashClipboardResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_CLIPBOARD_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_drm_resource.cc b/chromium/ppapi/proxy/flash_drm_resource.cc new file mode 100644 index 00000000000..a4be23beb8a --- /dev/null +++ b/chromium/ppapi/proxy/flash_drm_resource.cc @@ -0,0 +1,100 @@ +// 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 "ppapi/proxy/flash_drm_resource.h" + +#include "base/bind.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/shared_impl/ppb_file_ref_shared.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +FlashDRMResource::FlashDRMResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_FlashDRM_Create()); + SendCreate(RENDERER, PpapiHostMsg_FlashDRM_Create()); +} + +FlashDRMResource::~FlashDRMResource() { +} + +thunk::PPB_Flash_DRM_API* FlashDRMResource::AsPPB_Flash_DRM_API() { + return this; +} + +int32_t FlashDRMResource::GetDeviceID(PP_Var* id, + scoped_refptr<TrackedCallback> callback) { + if (!id) + return PP_ERROR_BADARGUMENT; + + *id = PP_MakeUndefined(); + + Call<PpapiPluginMsg_FlashDRM_GetDeviceIDReply>( + BROWSER, + PpapiHostMsg_FlashDRM_GetDeviceID(), + base::Bind(&FlashDRMResource::OnPluginMsgGetDeviceIDReply, this, + id, callback)); + return PP_OK_COMPLETIONPENDING; +} + +PP_Bool FlashDRMResource::GetHmonitor(int64_t* hmonitor) { + int64_t hmonitor_out; + int32_t result = SyncCall<PpapiPluginMsg_FlashDRM_GetHmonitorReply>( + BROWSER, + PpapiHostMsg_FlashDRM_GetHmonitor(), + &hmonitor_out); + if (result != PP_OK) + return PP_FALSE; + *hmonitor = hmonitor_out; + return PP_TRUE; +} + +int32_t FlashDRMResource::GetVoucherFile( + PP_Resource* file_ref, + scoped_refptr<TrackedCallback> callback) { + if (!file_ref) + return PP_ERROR_BADARGUMENT; + + *file_ref = 0; + + Call<PpapiPluginMsg_FlashDRM_GetVoucherFileReply>( + RENDERER, + PpapiHostMsg_FlashDRM_GetVoucherFile(), + base::Bind(&FlashDRMResource::OnPluginMsgGetVoucherFileReply, this, + file_ref, callback)); + return PP_OK_COMPLETIONPENDING; +} + +void FlashDRMResource::OnPluginMsgGetDeviceIDReply( + PP_Var* dest, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::string& id) { + if (TrackedCallback::IsPending(callback)) { + if (params.result() == PP_OK) + *dest = StringVar::StringToPPVar(id); + callback->Run(params.result()); + } +} + +void FlashDRMResource::OnPluginMsgGetVoucherFileReply( + PP_Resource* dest, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const PPB_FileRef_CreateInfo& file_info) { + if (TrackedCallback::IsPending(callback)) { + if (params.result() == PP_OK) + *dest = PPB_FileRef_Proxy::DeserializeFileRef(file_info); + callback->Run(params.result()); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_drm_resource.h b/chromium/ppapi/proxy/flash_drm_resource.h new file mode 100644 index 00000000000..12c71e82817 --- /dev/null +++ b/chromium/ppapi/proxy/flash_drm_resource.h @@ -0,0 +1,55 @@ +// 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_PROXY_FLASH_DRM_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_DRM_RESOURCE_H_ + +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_flash_drm_api.h" + +namespace ppapi { +struct PPB_FileRef_CreateInfo; +} + +namespace ppapi { +namespace proxy { + +class FlashDRMResource + : public PluginResource, + public thunk::PPB_Flash_DRM_API { + public: + FlashDRMResource(Connection connection, + PP_Instance instance); + virtual ~FlashDRMResource(); + + // Resource override. + virtual thunk::PPB_Flash_DRM_API* AsPPB_Flash_DRM_API() OVERRIDE; + + // PPB_Flash_DRM_API implementation. + virtual int32_t GetDeviceID(PP_Var* id, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Bool GetHmonitor(int64_t* hmonitor) OVERRIDE; + virtual int32_t GetVoucherFile( + PP_Resource* file_ref, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + void OnPluginMsgGetDeviceIDReply(PP_Var* dest, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::string& id); + void OnPluginMsgGetVoucherFileReply(PP_Resource* dest, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const PPB_FileRef_CreateInfo& file_info); + + DISALLOW_COPY_AND_ASSIGN(FlashDRMResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_DRM_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_file_resource.cc b/chromium/ppapi/proxy/flash_file_resource.cc new file mode 100644 index 00000000000..1387eb7c58b --- /dev/null +++ b/chromium/ppapi/proxy/flash_file_resource.cc @@ -0,0 +1,230 @@ +// 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 "ppapi/proxy/flash_file_resource.h" + +#include "base/files/file_path.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/file_type_conversion.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/time_conversion.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// Returns the path that a PPB_FileRef resource references as long as it is an +// PP_FILESYSTEMTYPE_EXTERNAL path. Returns an empty string on error. +std::string GetPathFromFileRef(PP_Resource file_ref) { + thunk::EnterResourceNoLock<thunk::PPB_FileRef_API> enter(file_ref, true); + if (enter.failed()) + return std::string(); + if (enter.object()->GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL) + return std::string(); + ScopedPPVar var(ScopedPPVar::PassRef(), enter.object()->GetAbsolutePath()); + StringVar* string_var = StringVar::FromPPVar(var.get()); + if (!string_var) + return std::string(); + return string_var->value(); +} + +} // namespace + +FlashFileResource::FlashFileResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_FlashFile_Create()); +} + +FlashFileResource::~FlashFileResource() { +} + +thunk::PPB_Flash_File_API* FlashFileResource::AsPPB_Flash_File_API() { + return this; +} + +int32_t FlashFileResource::OpenFile(PP_Instance /*instance*/, + const char* path, + int32_t mode, + PP_FileHandle* file) { + return OpenFileHelper(path, PepperFilePath::DOMAIN_MODULE_LOCAL, mode, file); +} + +int32_t FlashFileResource::RenameFile(PP_Instance /*instance*/, + const char* path_from, + const char* path_to) { + PepperFilePath pepper_from(PepperFilePath::DOMAIN_MODULE_LOCAL, + base::FilePath::FromUTF8Unsafe(path_from)); + PepperFilePath pepper_to(PepperFilePath::DOMAIN_MODULE_LOCAL, + base::FilePath::FromUTF8Unsafe(path_to)); + + int32_t error = SyncCall<IPC::Message>( + BROWSER, PpapiHostMsg_FlashFile_RenameFile(pepper_from, pepper_to)); + + return error; +} + +int32_t FlashFileResource::DeleteFileOrDir(PP_Instance /*instance*/, + const char* path, + PP_Bool recursive) { + PepperFilePath pepper_path(PepperFilePath::DOMAIN_MODULE_LOCAL, + base::FilePath::FromUTF8Unsafe(path)); + + int32_t error = SyncCall<IPC::Message>( + BROWSER, PpapiHostMsg_FlashFile_DeleteFileOrDir(pepper_path, + PP_ToBool(recursive))); + + return error; +} + +int32_t FlashFileResource::CreateDir(PP_Instance /*instance*/, + const char* path) { + PepperFilePath pepper_path(PepperFilePath::DOMAIN_MODULE_LOCAL, + base::FilePath::FromUTF8Unsafe(path)); + + int32_t error = SyncCall<IPC::Message>(BROWSER, + PpapiHostMsg_FlashFile_CreateDir(pepper_path)); + + return error; +} + +int32_t FlashFileResource::QueryFile(PP_Instance /*instance*/, + const char* path, + PP_FileInfo* info) { + return QueryFileHelper(path, PepperFilePath::DOMAIN_MODULE_LOCAL, info); +} + +int32_t FlashFileResource::GetDirContents(PP_Instance /*instance*/, + const char* path, + PP_DirContents_Dev** contents) { + ppapi::DirContents entries; + PepperFilePath pepper_path(PepperFilePath::DOMAIN_MODULE_LOCAL, + base::FilePath::FromUTF8Unsafe(path)); + + int32_t error = SyncCall<PpapiPluginMsg_FlashFile_GetDirContentsReply>( + BROWSER, PpapiHostMsg_FlashFile_GetDirContents(pepper_path), &entries); + + if (error == PP_OK) { + // Copy the serialized dir entries to the output struct. + *contents = new PP_DirContents_Dev; + (*contents)->count = static_cast<int32_t>(entries.size()); + (*contents)->entries = new PP_DirEntry_Dev[entries.size()]; + for (size_t i = 0; i < entries.size(); i++) { + const ppapi::DirEntry& source = entries[i]; + PP_DirEntry_Dev* dest = &(*contents)->entries[i]; + std::string name = source.name.AsUTF8Unsafe(); + char* name_copy = new char[name.size() + 1]; + memcpy(name_copy, name.c_str(), name.size() + 1); + dest->name = name_copy; + dest->is_dir = PP_FromBool(source.is_dir); + } + } + + return error; +} + +void FlashFileResource::FreeDirContents(PP_Instance /*instance*/, + PP_DirContents_Dev* contents) { + for (int32_t i = 0; i < contents->count; ++i) + delete[] contents->entries[i].name; + delete[] contents->entries; + delete contents; +} + +int32_t FlashFileResource::CreateTemporaryFile(PP_Instance /*instance*/, + PP_FileHandle* file) { + if (!file) + return PP_ERROR_BADARGUMENT; + + IPC::Message unused; + ResourceMessageReplyParams reply_params; + int32_t error = GenericSyncCall(BROWSER, + PpapiHostMsg_FlashFile_CreateTemporaryFile(), &unused, &reply_params); + if (error != PP_OK) + return error; + + IPC::PlatformFileForTransit transit_file; + if (!reply_params.TakeFileHandleAtIndex(0, &transit_file)) + return PP_ERROR_FAILED; + + *file = IPC::PlatformFileForTransitToPlatformFile(transit_file); + return PP_OK; +} + +int32_t FlashFileResource::OpenFileRef(PP_Instance /*instance*/, + PP_Resource file_ref, + int32_t mode, + PP_FileHandle* file) { + return OpenFileHelper(GetPathFromFileRef(file_ref), + PepperFilePath::DOMAIN_ABSOLUTE, mode, file); +} + +int32_t FlashFileResource::QueryFileRef(PP_Instance /*instance*/, + PP_Resource file_ref, + PP_FileInfo* info) { + return QueryFileHelper(GetPathFromFileRef(file_ref), + PepperFilePath::DOMAIN_ABSOLUTE, info); +} + +int32_t FlashFileResource::OpenFileHelper(const std::string& path, + PepperFilePath::Domain domain_type, + int32_t mode, + PP_FileHandle* file) { + if (path.empty() || + !ppapi::PepperFileOpenFlagsToPlatformFileFlags(mode, NULL) || + !file) + return PP_ERROR_BADARGUMENT; + + PepperFilePath pepper_path(domain_type, base::FilePath::FromUTF8Unsafe(path)); + + IPC::Message unused; + ResourceMessageReplyParams reply_params; + int32_t error = GenericSyncCall(BROWSER, + PpapiHostMsg_FlashFile_OpenFile(pepper_path, mode), &unused, + &reply_params); + if (error != PP_OK) + return error; + + IPC::PlatformFileForTransit transit_file; + if (!reply_params.TakeFileHandleAtIndex(0, &transit_file)) + return PP_ERROR_FAILED; + + *file = IPC::PlatformFileForTransitToPlatformFile(transit_file); + return PP_OK; +} + +int32_t FlashFileResource::QueryFileHelper(const std::string& path, + PepperFilePath::Domain domain_type, + PP_FileInfo* info) { + if (path.empty() || !info) + return PP_ERROR_BADARGUMENT; + + base::PlatformFileInfo file_info; + PepperFilePath pepper_path(domain_type, base::FilePath::FromUTF8Unsafe(path)); + + int32_t error = SyncCall<PpapiPluginMsg_FlashFile_QueryFileReply>(BROWSER, + PpapiHostMsg_FlashFile_QueryFile(pepper_path), &file_info); + + if (error == PP_OK) { + info->size = file_info.size; + info->creation_time = TimeToPPTime(file_info.creation_time); + info->last_access_time = TimeToPPTime(file_info.last_accessed); + info->last_modified_time = TimeToPPTime(file_info.last_modified); + info->system_type = PP_FILESYSTEMTYPE_EXTERNAL; + if (file_info.is_directory) + info->type = PP_FILETYPE_DIRECTORY; + else + info->type = PP_FILETYPE_REGULAR; + } + + return error; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_file_resource.h b/chromium/ppapi/proxy/flash_file_resource.h new file mode 100644 index 00000000000..f8c4b18815b --- /dev/null +++ b/chromium/ppapi/proxy/flash_file_resource.h @@ -0,0 +1,73 @@ +// 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_PROXY_FLASH_FILE_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_FILE_RESOURCE_H_ + +#include <string> + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/shared_impl/file_path.h" +#include "ppapi/thunk/ppb_flash_file_api.h" + +namespace ppapi { +namespace proxy { + +class FlashFileResource + : public PluginResource, + public thunk::PPB_Flash_File_API { + public: + FlashFileResource(Connection connection, PP_Instance instance); + virtual ~FlashFileResource(); + + // Resource overrides. + virtual thunk::PPB_Flash_File_API* AsPPB_Flash_File_API() OVERRIDE; + + // PPB_Flash_Functions_API. + virtual int32_t OpenFile(PP_Instance instance, + const char* path, + int32_t mode, + PP_FileHandle* file) OVERRIDE; + virtual int32_t RenameFile(PP_Instance instance, + const char* path_from, + const char* path_to) OVERRIDE; + virtual int32_t DeleteFileOrDir(PP_Instance instance, + const char* path, + PP_Bool recursive) OVERRIDE; + virtual int32_t CreateDir(PP_Instance instance, const char* path) OVERRIDE; + virtual int32_t QueryFile(PP_Instance instance, + const char* path, + PP_FileInfo* info) OVERRIDE; + virtual int32_t GetDirContents(PP_Instance instance, + const char* path, + PP_DirContents_Dev** contents) OVERRIDE; + virtual void FreeDirContents(PP_Instance instance, + PP_DirContents_Dev* contents) OVERRIDE; + virtual int32_t CreateTemporaryFile(PP_Instance instance, + PP_FileHandle* file) OVERRIDE; + virtual int32_t OpenFileRef(PP_Instance instance, + PP_Resource file_ref, + int32_t mode, + PP_FileHandle* file) OVERRIDE; + virtual int32_t QueryFileRef(PP_Instance instance, + PP_Resource file_ref, + PP_FileInfo* info) OVERRIDE; + + private: + int32_t OpenFileHelper(const std::string& path, + PepperFilePath::Domain domain_type, + int32_t mode, + PP_FileHandle* file); + int32_t QueryFileHelper(const std::string& path, + PepperFilePath::Domain domain_type, + PP_FileInfo* info); + + DISALLOW_COPY_AND_ASSIGN(FlashFileResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_FILE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_font_file_resource.cc b/chromium/ppapi/proxy/flash_font_file_resource.cc new file mode 100644 index 00000000000..86caf1fff98 --- /dev/null +++ b/chromium/ppapi/proxy/flash_font_file_resource.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 "ppapi/proxy/flash_font_file_resource.h" + +#include <cstring> + +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +FlashFontFileResource::FlashFontFileResource( + Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description* description, + PP_PrivateFontCharset charset) + : PluginResource(connection, instance), + charset_(charset) { + description_.SetFromPPBrowserFontDescription(*description); +} + +FlashFontFileResource::~FlashFontFileResource() { +} + +thunk::PPB_Flash_FontFile_API* + FlashFontFileResource::AsPPB_Flash_FontFile_API() { + return this; +} + +PP_Bool FlashFontFileResource::GetFontTable(uint32_t table, + void* output, + uint32_t* output_length) { + if (!output_length) + return PP_FALSE; + + if (!sent_create_to_renderer()) { + SendCreate( + RENDERER, PpapiHostMsg_FlashFontFile_Create(description_, charset_)); + } + + std::string* contents = GetFontTable(table); + if (!contents) { + std::string out_contents; + int32_t result = SyncCall<PpapiPluginMsg_FlashFontFile_GetFontTableReply>( + RENDERER, PpapiHostMsg_FlashFontFile_GetFontTable(table), + &out_contents); + if (result != PP_OK) + return PP_FALSE; + + contents = AddFontTable(table, out_contents); + } + + // If we are going to copy the data into |output|, it must be big enough. + if (output && *output_length < contents->size()) + return PP_FALSE; + + *output_length = static_cast<uint32_t>(contents->size()); + if (output) + memcpy(output, contents->c_str(), *output_length); + return PP_TRUE; +} + +std::string* FlashFontFileResource::GetFontTable(uint32_t table) const { + FontTableMap::const_iterator found = font_tables_.find(table); + if (found == font_tables_.end()) + return NULL; + return found->second.get(); +} + +std::string* FlashFontFileResource::AddFontTable(uint32_t table, + const std::string& contents) { + linked_ptr<std::string> heap_string(new std::string(contents)); + font_tables_[table] = heap_string; + return heap_string.get(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_font_file_resource.h b/chromium/ppapi/proxy/flash_font_file_resource.h new file mode 100644 index 00000000000..5bc633a4fe6 --- /dev/null +++ b/chromium/ppapi/proxy/flash_font_file_resource.h @@ -0,0 +1,61 @@ +// 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_PROXY_FLASH_FONT_FILE_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_FONT_FILE_RESOURCE_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/linked_ptr.h" +#include "ppapi/c/private/pp_private_font_charset.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/thunk/ppb_flash_font_file_api.h" + +struct PP_BrowserFont_Trusted_Description; + +namespace ppapi { +namespace proxy { + +// TODO(yzshen): write unittest and browser test. +class FlashFontFileResource : public PluginResource, + public thunk::PPB_Flash_FontFile_API { + public: + FlashFontFileResource(Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description* description, + PP_PrivateFontCharset charset); + virtual ~FlashFontFileResource(); + + // Resource overrides. + virtual thunk::PPB_Flash_FontFile_API* AsPPB_Flash_FontFile_API() OVERRIDE; + + // PPB_Flash_FontFile_API. + virtual PP_Bool GetFontTable(uint32_t table, + void* output, + uint32_t* output_length) OVERRIDE; + + private: + // Sees if we have a cache of the font table and returns a pointer to it. + // Returns NULL if we don't have it. + std::string* GetFontTable(uint32_t table) const; + + std::string* AddFontTable(uint32_t table, const std::string& contents); + + typedef std::map<uint32_t, linked_ptr<std::string> > FontTableMap; + FontTableMap font_tables_; + + SerializedFontDescription description_; + PP_PrivateFontCharset charset_; + + DISALLOW_COPY_AND_ASSIGN(FlashFontFileResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_FONT_FILE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_fullscreen_resource.cc b/chromium/ppapi/proxy/flash_fullscreen_resource.cc new file mode 100644 index 00000000000..90a68fcf6b5 --- /dev/null +++ b/chromium/ppapi/proxy/flash_fullscreen_resource.cc @@ -0,0 +1,46 @@ +// 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 "ppapi/proxy/flash_fullscreen_resource.h" + +#include "ppapi/c/pp_bool.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +FlashFullscreenResource::FlashFullscreenResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + is_fullscreen_(PP_FALSE) { +} + +FlashFullscreenResource::~FlashFullscreenResource() { +} + +thunk::PPB_Flash_Fullscreen_API* +FlashFullscreenResource::AsPPB_Flash_Fullscreen_API() { + return this; +} + +PP_Bool FlashFullscreenResource::IsFullscreen(PP_Instance instance) { + return is_fullscreen_; +} + +PP_Bool FlashFullscreenResource::SetFullscreen(PP_Instance instance, + PP_Bool fullscreen) { + if (!sent_create_to_renderer()) + SendCreate(RENDERER, PpapiHostMsg_FlashFullscreen_Create()); + int32_t result = SyncCall<IPC::Message>(RENDERER, + PpapiHostMsg_FlashFullscreen_SetFullscreen(PP_ToBool(fullscreen))); + return PP_FromBool(result == PP_OK); +} + +void FlashFullscreenResource::SetLocalIsFullscreen(PP_Instance instance, + PP_Bool is_fullscreen) { + is_fullscreen_ = is_fullscreen; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_fullscreen_resource.h b/chromium/ppapi/proxy/flash_fullscreen_resource.h new file mode 100644 index 00000000000..c6d5ccbed53 --- /dev/null +++ b/chromium/ppapi/proxy/flash_fullscreen_resource.h @@ -0,0 +1,43 @@ +// 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_PROXY_FLASH_FULLSCREEN_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_FULLSCREEN_RESOURCE_H_ + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/ppb_flash_fullscreen_api.h" + +namespace ppapi { +namespace proxy { + +class FlashFullscreenResource + : public PluginResource, + public thunk::PPB_Flash_Fullscreen_API { + public: + FlashFullscreenResource(Connection connection, + PP_Instance instance); + virtual ~FlashFullscreenResource(); + + // Resource overrides. + virtual thunk::PPB_Flash_Fullscreen_API* + AsPPB_Flash_Fullscreen_API() OVERRIDE; + + // PPB_Flash_Fullscreen_API implementation. + virtual PP_Bool IsFullscreen(PP_Instance instance) OVERRIDE; + virtual PP_Bool SetFullscreen(PP_Instance instance, + PP_Bool fullscreen) OVERRIDE; + virtual void SetLocalIsFullscreen(PP_Instance instance, + PP_Bool is_fullscreen) OVERRIDE; + + private: + PP_Bool is_fullscreen_; + + DISALLOW_COPY_AND_ASSIGN(FlashFullscreenResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_FULLSCREEN_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_menu_resource.cc b/chromium/ppapi/proxy/flash_menu_resource.cc new file mode 100644 index 00000000000..1c3b7f03729 --- /dev/null +++ b/chromium/ppapi/proxy/flash_menu_resource.cc @@ -0,0 +1,97 @@ +// 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 "ppapi/proxy/flash_menu_resource.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_flash_menu.h" + +namespace ppapi { +namespace proxy { + +FlashMenuResource::FlashMenuResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + selected_id_dest_(NULL) { +} + +FlashMenuResource::~FlashMenuResource() { +} + +bool FlashMenuResource::Initialize(const PP_Flash_Menu* menu_data) { + SerializedFlashMenu serialized_menu; + if (!menu_data || !serialized_menu.SetPPMenu(menu_data)) + return false; + SendCreate(RENDERER, PpapiHostMsg_FlashMenu_Create(serialized_menu)); + return true; +} + +thunk::PPB_Flash_Menu_API* FlashMenuResource::AsPPB_Flash_Menu_API() { + return this; +} + +int32_t FlashMenuResource::Show( + const PP_Point* location, + int32_t* selected_id, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(callback_)) + return PP_ERROR_INPROGRESS; + + selected_id_dest_ = selected_id; + callback_ = callback; + + // This must be a sync message even though we don't care about the result. + // The actual reply will be sent asynchronously in the future. This sync + // request is due to the following deadlock: + // + // 1. Flash sends a show request to the renderer. + // 2. The show handler in the renderer (in the case of full screen) requests + // the window rect which is a sync message to the browser. This causes + // a nested message loop to be spun up in the renderer. + // 3. Flash expects context menus to be synchronous so it starts a nested + // message loop. This creates a second nested message loop in both the + // plugin and renderer process. + // 4. The browser sends the window rect reply to unblock the renderer, but + // it's in the second nested message loop and the reply will *not* + // unblock this loop. + // 5. The second loop won't exit until the message loop is complete, but + // that can't start until the first one exits. + // + // Having this message sync forces the sync request from the renderer to the + // browser for the window rect will complete before Flash can run a nested + // message loop to wait for the result of the menu. + SyncCall<IPC::Message>(RENDERER, PpapiHostMsg_FlashMenu_Show(*location)); + return PP_OK_COMPLETIONPENDING; +} + +void FlashMenuResource::OnReplyReceived( + const proxy::ResourceMessageReplyParams& params, + const IPC::Message& msg) { + // Because the Show call is synchronous but we ignore the sync result, we + // can't use the normal reply dispatch and have to do it manually here. + switch (msg.type()) { + case PpapiPluginMsg_FlashMenu_ShowReply::ID: { + int32_t selected_id; + if (ppapi::UnpackMessage<PpapiPluginMsg_FlashMenu_ShowReply>( + msg, &selected_id)) + OnShowReply(params, selected_id); + break; + } + } +} + +void FlashMenuResource::OnShowReply( + const proxy::ResourceMessageReplyParams& params, + int32_t selected_id) { + if (!TrackedCallback::IsPending(callback_)) + return; + + *selected_id_dest_ = selected_id; + selected_id_dest_ = NULL; + callback_->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_menu_resource.h b/chromium/ppapi/proxy/flash_menu_resource.h new file mode 100644 index 00000000000..46b227a6f75 --- /dev/null +++ b/chromium/ppapi/proxy/flash_menu_resource.h @@ -0,0 +1,57 @@ +// 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_PROXY_FLASH_MENU_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_MENU_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_flash_menu_api.h" + +struct PP_Flash_Menu; + +namespace ppapi { +namespace proxy { + +class FlashMenuResource + : public PluginResource, + public thunk::PPB_Flash_Menu_API { + public: + // You must call Initialize after construction. + FlashMenuResource(Connection connection, PP_Instance instance); + virtual ~FlashMenuResource(); + + // Returns true on success. False means that this object can not be used. + // This has to be separate from the constructor because the menu data could + // be invalid. + bool Initialize(const PP_Flash_Menu* menu_data); + + // Resource overrides. + virtual thunk::PPB_Flash_Menu_API* AsPPB_Flash_Menu_API() OVERRIDE; + + // PPB_Flash_Menu_API. + virtual int32_t Show(const PP_Point* location, + int32_t* selected_id, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + virtual void OnReplyReceived(const proxy::ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + void OnShowReply( + const proxy::ResourceMessageReplyParams& params, + int32_t selected_id); + + int* selected_id_dest_; + scoped_refptr<TrackedCallback> callback_; + + DISALLOW_COPY_AND_ASSIGN(FlashMenuResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_MENU_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_resource.cc b/chromium/ppapi/proxy/flash_resource.cc new file mode 100644 index 00000000000..26a80ae8222 --- /dev/null +++ b/chromium/ppapi/proxy/flash_resource.cc @@ -0,0 +1,256 @@ +// 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 "ppapi/proxy/flash_resource.h" + +#include <cmath> + +#include "base/containers/mru_cache.h" +#include "base/debug/crash_logging.h" +#include "base/lazy_instance.h" +#include "base/time/time.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/c/trusted/ppb_browser_font_trusted.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/ppapi_preferences.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/time_conversion.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_url_request_info_api.h" + +using ppapi::thunk::EnterResourceNoLock; + +namespace ppapi { +namespace proxy { + +namespace { + +struct LocalTimeZoneOffsetEntry { + base::TimeTicks expiration; + double offset; +}; + +class LocalTimeZoneOffsetCache + : public base::MRUCache<PP_Time, LocalTimeZoneOffsetEntry> { + public: + LocalTimeZoneOffsetCache() + : base::MRUCache<PP_Time, LocalTimeZoneOffsetEntry>(kCacheSize) {} + private: + static const size_t kCacheSize = 100; +}; + +base::LazyInstance<LocalTimeZoneOffsetCache>::Leaky + g_local_time_zone_offset_cache = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +FlashResource::FlashResource(Connection connection, + PP_Instance instance, + PluginDispatcher* plugin_dispatcher) + : PluginResource(connection, instance), + plugin_dispatcher_(plugin_dispatcher) { + SendCreate(RENDERER, PpapiHostMsg_Flash_Create()); + SendCreate(BROWSER, PpapiHostMsg_Flash_Create()); +} + +FlashResource::~FlashResource() { +} + +thunk::PPB_Flash_Functions_API* FlashResource::AsPPB_Flash_Functions_API() { + return this; +} + +PP_Var FlashResource::GetProxyForURL(PP_Instance instance, + const std::string& url) { + std::string proxy; + int32_t result = SyncCall<PpapiPluginMsg_Flash_GetProxyForURLReply>(RENDERER, + PpapiHostMsg_Flash_GetProxyForURL(url), &proxy); + + if (result == PP_OK) + return StringVar::StringToPPVar(proxy); + return PP_MakeUndefined(); +} + +void FlashResource::UpdateActivity(PP_Instance instance) { + Post(BROWSER, PpapiHostMsg_Flash_UpdateActivity()); +} + +PP_Bool FlashResource::SetCrashData(PP_Instance instance, + PP_FlashCrashKey key, + PP_Var value) { + StringVar* url_string_var(StringVar::FromPPVar(value)); + if (!url_string_var) + return PP_FALSE; + switch (key) { + case PP_FLASHCRASHKEY_URL: { + PluginGlobals::Get()->SetActiveURL(url_string_var->value()); + return PP_TRUE; + } + case PP_FLASHCRASHKEY_RESOURCE_URL: { + base::debug::SetCrashKeyValue("subresource_url", url_string_var->value()); + return PP_TRUE; + } + } + return PP_FALSE; +} + +double FlashResource::GetLocalTimeZoneOffset(PP_Instance instance, + PP_Time t) { + LocalTimeZoneOffsetCache& cache = g_local_time_zone_offset_cache.Get(); + + // Get the minimum PP_Time value that shares the same minute as |t|. + // Use cached offset if cache hasn't expired and |t| is in the same minute as + // the time for the cached offset (assume offsets change on minute + // boundaries). + PP_Time t_minute_base = floor(t / 60.0) * 60.0; + LocalTimeZoneOffsetCache::iterator iter = cache.Get(t_minute_base); + base::TimeTicks now = base::TimeTicks::Now(); + if (iter != cache.end() && now < iter->second.expiration) + return iter->second.offset; + + // Cache the local offset for ten seconds, since it's slow on XP and Linux. + // Note that TimeTicks does not continue counting across sleep/resume on all + // platforms. This may be acceptable for 10 seconds, but if in the future this + // is changed to one minute or more, then we should consider using base::Time. + const int64 kMaxCachedLocalOffsetAgeInSeconds = 10; + base::TimeDelta expiration_delta = + base::TimeDelta::FromSeconds(kMaxCachedLocalOffsetAgeInSeconds); + + LocalTimeZoneOffsetEntry cache_entry; + cache_entry.expiration = now + expiration_delta; + cache_entry.offset = 0.0; + + // We can't do the conversion here on Linux because the localtime calls + // require filesystem access prohibited by the sandbox. + // TODO(shess): Figure out why OSX needs the access, the sandbox warmup should + // handle it. http://crbug.com/149006 +#if defined(OS_LINUX) || defined(OS_MACOSX) + int32_t result = SyncCall<PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply>( + BROWSER, + PpapiHostMsg_Flash_GetLocalTimeZoneOffset(PPTimeToTime(t)), + &cache_entry.offset); + if (result != PP_OK) + cache_entry.offset = 0.0; +#else + cache_entry.offset = PPGetLocalTimeZoneOffset(PPTimeToTime(t)); +#endif + + cache.Put(t_minute_base, cache_entry); + return cache_entry.offset; +} + +PP_Var FlashResource::GetSetting(PP_Instance instance, + PP_FlashSetting setting) { + switch (setting) { + case PP_FLASHSETTING_3DENABLED: + return PP_MakeBool(PP_FromBool( + plugin_dispatcher_->preferences().is_3d_supported)); + case PP_FLASHSETTING_INCOGNITO: + return PP_MakeBool(PP_FromBool(plugin_dispatcher_->incognito())); + case PP_FLASHSETTING_STAGE3DENABLED: + return PP_MakeBool(PP_FromBool( + plugin_dispatcher_->preferences().is_stage3d_supported)); + case PP_FLASHSETTING_STAGE3DBASELINEENABLED: + return PP_MakeBool(PP_FromBool( + plugin_dispatcher_->preferences().is_stage3d_baseline_supported)); + case PP_FLASHSETTING_LANGUAGE: + return StringVar::StringToPPVar( + PluginGlobals::Get()->GetUILanguage()); + case PP_FLASHSETTING_NUMCORES: + return PP_MakeInt32( + plugin_dispatcher_->preferences().number_of_cpu_cores); + case PP_FLASHSETTING_LSORESTRICTIONS: { + int32_t restrictions; + int32_t result = + SyncCall<PpapiPluginMsg_Flash_GetLocalDataRestrictionsReply>(BROWSER, + PpapiHostMsg_Flash_GetLocalDataRestrictions(), &restrictions); + if (result != PP_OK) + return PP_MakeInt32(PP_FLASHLSORESTRICTIONS_NONE); + return PP_MakeInt32(restrictions); + } + } + return PP_MakeUndefined(); +} + +void FlashResource::SetInstanceAlwaysOnTop(PP_Instance instance, + PP_Bool on_top) { + Post(RENDERER, PpapiHostMsg_Flash_SetInstanceAlwaysOnTop(PP_ToBool(on_top))); +} + +PP_Bool FlashResource::DrawGlyphs( + PP_Instance instance, + PP_Resource pp_image_data, + const PP_BrowserFont_Trusted_Description* font_desc, + uint32_t color, + const PP_Point* position, + const PP_Rect* clip, + const float transformation[3][3], + PP_Bool allow_subpixel_aa, + uint32_t glyph_count, + const uint16_t glyph_indices[], + const PP_Point glyph_advances[]) { + EnterResourceNoLock<thunk::PPB_ImageData_API> enter(pp_image_data, true); + if (enter.failed()) + return PP_FALSE; + // The instance parameter isn't strictly necessary but we check that it + // matches anyway. + if (enter.resource()->pp_instance() != instance) + return PP_FALSE; + + PPBFlash_DrawGlyphs_Params params; + params.image_data = enter.resource()->host_resource(); + params.font_desc.SetFromPPBrowserFontDescription(*font_desc); + params.color = color; + params.position = *position; + params.clip = *clip; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) + params.transformation[i][j] = transformation[i][j]; + } + params.allow_subpixel_aa = allow_subpixel_aa; + + params.glyph_indices.insert(params.glyph_indices.begin(), + &glyph_indices[0], + &glyph_indices[glyph_count]); + params.glyph_advances.insert(params.glyph_advances.begin(), + &glyph_advances[0], + &glyph_advances[glyph_count]); + + // This has to be synchronous because the caller may want to composite on + // top of the resulting text after the call is complete. + int32_t result = SyncCall<IPC::Message>(RENDERER, + PpapiHostMsg_Flash_DrawGlyphs(params)); + return PP_FromBool(result == PP_OK); +} + +int32_t FlashResource::Navigate(PP_Instance instance, + PP_Resource request_info, + const char* target, + PP_Bool from_user_action) { + EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_info, + true); + if (enter.failed()) + return PP_ERROR_BADRESOURCE; + return SyncCall<IPC::Message>(RENDERER, PpapiHostMsg_Flash_Navigate( + enter.object()->GetData(), target, PP_ToBool(from_user_action))); +} + +PP_Bool FlashResource::IsRectTopmost(PP_Instance instance, + const PP_Rect* rect) { + int32_t result = SyncCall<IPC::Message>(RENDERER, + PpapiHostMsg_Flash_IsRectTopmost(*rect)); + return PP_FromBool(result == PP_OK); +} + +void FlashResource::InvokePrinting(PP_Instance instance) { + Post(RENDERER, PpapiHostMsg_Flash_InvokePrinting()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/flash_resource.h b/chromium/ppapi/proxy/flash_resource.h new file mode 100644 index 00000000000..cfb6b1e7123 --- /dev/null +++ b/chromium/ppapi/proxy/flash_resource.h @@ -0,0 +1,75 @@ +// 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_PROXY_FLASH_RESOURCE_H_ +#define PPAPI_PROXY_FLASH_RESOURCE_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/ppb_flash_functions_api.h" + +namespace ppapi { +namespace proxy { + +class PluginDispatcher; + +class FlashResource + : public PluginResource, + public thunk::PPB_Flash_Functions_API { + public: + FlashResource(Connection connection, + PP_Instance instance, + PluginDispatcher* plugin_dispatcher); + virtual ~FlashResource(); + + // Resource override. + virtual thunk::PPB_Flash_Functions_API* AsPPB_Flash_Functions_API() OVERRIDE; + + // PPB_Flash_Functions_API implementation. + virtual PP_Var GetProxyForURL(PP_Instance instance, + const std::string& url) OVERRIDE; + virtual void UpdateActivity(PP_Instance instance) OVERRIDE; + virtual PP_Bool SetCrashData(PP_Instance instance, + PP_FlashCrashKey key, + PP_Var value) OVERRIDE; + virtual double GetLocalTimeZoneOffset(PP_Instance instance, + PP_Time t) OVERRIDE; + virtual PP_Var GetSetting(PP_Instance instance, + PP_FlashSetting setting) OVERRIDE; + virtual void SetInstanceAlwaysOnTop(PP_Instance instance, + PP_Bool on_top) OVERRIDE; + virtual PP_Bool DrawGlyphs( + PP_Instance instance, + PP_Resource pp_image_data, + const PP_BrowserFont_Trusted_Description* font_desc, + uint32_t color, + const PP_Point* position, + const PP_Rect* clip, + const float transformation[3][3], + PP_Bool allow_subpixel_aa, + uint32_t glyph_count, + const uint16_t glyph_indices[], + const PP_Point glyph_advances[]) OVERRIDE; + virtual int32_t Navigate(PP_Instance instance, + PP_Resource request_info, + const char* target, + PP_Bool from_user_action) OVERRIDE; + virtual PP_Bool IsRectTopmost(PP_Instance instance, + const PP_Rect* rect) OVERRIDE; + virtual void InvokePrinting(PP_Instance instance) OVERRIDE; + + private: + // Non-owning pointer to the PluginDispatcher that owns this object. + PluginDispatcher* plugin_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(FlashResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FLASH_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/flash_resource_unittest.cc b/chromium/ppapi/proxy/flash_resource_unittest.cc new file mode 100644 index 00000000000..1a5e7c644d4 --- /dev/null +++ b/chromium/ppapi/proxy/flash_resource_unittest.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/c/dev/ppb_video_capture_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/proxy/locking_resource_releaser.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest FlashResourceTest; + +void* Unused(void* user_data, uint32_t element_count, uint32_t element_size) { + return NULL; +} + +} // namespace + +// Does a test of EnumerateVideoCaptureDevices() and reply functionality in +// the plugin side using the public C interfaces. +TEST_F(FlashResourceTest, EnumerateVideoCaptureDevices) { + // TODO(raymes): This doesn't actually check that the data is converted from + // |ppapi::DeviceRefData| to |PPB_DeviceRef| correctly, just that the right + // messages are sent. + + // Set up a sync call handler that should return this message. + std::vector<ppapi::DeviceRefData> reply_device_ref_data; + int32_t expected_result = PP_OK; + PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply reply_msg( + reply_device_ref_data); + ResourceSyncCallHandler enumerate_video_devices_handler( + &sink(), + PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID, + expected_result, + reply_msg); + sink().AddFilter(&enumerate_video_devices_handler); + + // Set up the arguments to the call. + LockingResourceReleaser video_capture( + ::ppapi::thunk::GetPPB_VideoCapture_Dev_0_3_Thunk()->Create( + pp_instance())); + std::vector<PP_Resource> unused; + PP_ArrayOutput output; + output.GetDataBuffer = &Unused; + output.user_data = &unused; + + // Make the call. + const PPB_Flash_12_6* flash_iface = ::ppapi::thunk::GetPPB_Flash_12_6_Thunk(); + int32_t actual_result = flash_iface->EnumerateVideoCaptureDevices( + pp_instance(), video_capture.get(), output); + + // Check the result is as expected. + EXPECT_EQ(expected_result, actual_result); + + // Should have sent an "DeviceEnumeration_EnumerateDevices" message. + ASSERT_TRUE(enumerate_video_devices_handler.last_handled_msg().type() == + PpapiHostMsg_DeviceEnumeration_EnumerateDevices::ID); + + // Remove the filter or it will be destroyed before the sink() is destroyed. + sink().RemoveFilter(&enumerate_video_devices_handler); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/gamepad_resource.cc b/chromium/ppapi/proxy/gamepad_resource.cc new file mode 100644 index 00000000000..1cfc0419705 --- /dev/null +++ b/chromium/ppapi/proxy/gamepad_resource.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 "ppapi/proxy/gamepad_resource.h" + +#include <string.h> + +#include "base/bind.h" +#include "base/threading/platform_thread.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppb_gamepad_shared.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// This is the read logic from content/common/gamepad_seqlock.h +base::subtle::Atomic32 ReadBegin(const base::subtle::Atomic32* sequence) { + base::subtle::Atomic32 version; + for (;;) { + version = base::subtle::NoBarrier_Load(sequence); + + // If the counter is even, then the associated data might be in a + // consistent state, so we can try to read. + if ((version & 1) == 0) + break; + + // Otherwise, the writer is in the middle of an update. Retry the read. + base::PlatformThread::YieldCurrentThread(); + } + return version; +} + +bool ReadRetry(const base::subtle::Atomic32* sequence, + base::subtle::Atomic32 version) { + // If the sequence number was updated then a read should be re-attempted. + // -- Load fence, read membarrier + return base::subtle::Release_Load(sequence) != version; +} + +} // namespace + +GamepadResource::GamepadResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance), + buffer_(NULL) { + memset(&last_read_, 0, sizeof(last_read_)); + + SendCreate(BROWSER, PpapiHostMsg_Gamepad_Create()); + Call<PpapiPluginMsg_Gamepad_SendMemory>( + BROWSER, + PpapiHostMsg_Gamepad_RequestMemory(), + base::Bind(&GamepadResource::OnPluginMsgSendMemory, this)); +} + +GamepadResource::~GamepadResource() { +} + +thunk::PPB_Gamepad_API* GamepadResource::AsPPB_Gamepad_API() { + return this; +} + +void GamepadResource::Sample(PP_Instance /* instance */, + PP_GamepadsSampleData* data) { + if (!buffer_) { + // Browser hasn't sent back our shared memory, give the plugin gamepad + // data corresponding to "not connected". + memset(data, 0, sizeof(PP_GamepadsSampleData)); + return; + } + + // ========== + // DANGER + // ========== + // + // This logic is duplicated in the renderer as well. If you change it, that + // also needs to be in sync. See gamepad_shared_memory_reader.cc. + + // Only try to read this many times before failing to avoid waiting here + // very long in case of contention with the writer. + const int kMaximumContentionCount = 10; + int contention_count = -1; + base::subtle::Atomic32 version; + WebKitGamepads read_into; + do { + version = ReadBegin(&buffer_->sequence); + memcpy(&read_into, &buffer_->buffer, sizeof(read_into)); + ++contention_count; + if (contention_count == kMaximumContentionCount) + break; + } while (ReadRetry(&buffer_->sequence, version)); + + // In the event of a read failure, just leave the last read data as-is (the + // hardware thread is taking unusally long). + if (contention_count < kMaximumContentionCount) + ConvertWebKitGamepadData(read_into, &last_read_); + + memcpy(data, &last_read_, sizeof(PP_GamepadsSampleData)); +} + +void GamepadResource::OnPluginMsgSendMemory( + const ResourceMessageReplyParams& params) { + // On failure, the handle will be null and the CHECK below will be tripped. + base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle(); + params.TakeSharedMemoryHandleAtIndex(0, &handle); + + shared_memory_.reset(new base::SharedMemory(handle, true)); + CHECK(shared_memory_->Map(sizeof(ContentGamepadHardwareBuffer))); + buffer_ = static_cast<const ContentGamepadHardwareBuffer*>( + shared_memory_->memory()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/gamepad_resource.h b/chromium/ppapi/proxy/gamepad_resource.h new file mode 100644 index 00000000000..1a1de3cf5e6 --- /dev/null +++ b/chromium/ppapi/proxy/gamepad_resource.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 PPAPI_PROXY_GAMEPAD_RESOURCE_H_ +#define PPAPI_PROXY_GAMEPAD_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "ppapi/c/ppb_gamepad.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/ppb_gamepad_shared.h" +#include "ppapi/thunk/ppb_gamepad_api.h" + +struct PP_GamepadsSampleData; + +namespace base { +class SharedMemory; +} + +namespace ppapi { +namespace proxy { + +// This class is a bit weird. It isn't a true resource from the plugin's +// perspective. But we need to make requests to the browser and get replies. +// It's more convenient to do this as a resource, so the instance just +// maintains an internal lazily instantiated copy of this resource. +class PPAPI_PROXY_EXPORT GamepadResource + : public PluginResource, + public thunk::PPB_Gamepad_API { + public: + GamepadResource(Connection connection, PP_Instance instance); + virtual ~GamepadResource(); + + // Resource implementation. + virtual thunk::PPB_Gamepad_API* AsPPB_Gamepad_API() OVERRIDE; + + // PPB_Gamepad_API. + virtual void Sample(PP_Instance instance, + PP_GamepadsSampleData* data) OVERRIDE; + + private: + void OnPluginMsgSendMemory(const ResourceMessageReplyParams& params); + + scoped_ptr<base::SharedMemory> shared_memory_; + const ContentGamepadHardwareBuffer* buffer_; + + // Last data returned so we can use this in the event of a read failure. + PP_GamepadsSampleData last_read_; + + DISALLOW_COPY_AND_ASSIGN(GamepadResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_GAMEPAD_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/graphics_2d_resource.cc b/chromium/ppapi/proxy/graphics_2d_resource.cc new file mode 100644 index 00000000000..3bad2e4e13c --- /dev/null +++ b/chromium/ppapi/proxy/graphics_2d_resource.cc @@ -0,0 +1,147 @@ +// 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 "ppapi/proxy/graphics_2d_resource.h" + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/ppb_graphics_2d.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" + +namespace ppapi { +namespace proxy { + +Graphics2DResource::Graphics2DResource(Connection connection, + PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque) + : PluginResource(connection, instance), + size_(size), + is_always_opaque_(is_always_opaque), + scale_(1.0f) { + // These checks are copied from PPB_ImageData_Impl::Init to make tests passed. + // Let's remove/refactor this when start to refactor ImageData. + bool bad_args = size.width <= 0 || size.height <= 0 || + static_cast<int64>(size.width) * static_cast<int64>(size.height) >= + std::numeric_limits<int32>::max() / 4; + if (!bad_args && !sent_create_to_renderer()) { + SendCreate(RENDERER, + PpapiHostMsg_Graphics2D_Create(size, is_always_opaque)); + } +} + +Graphics2DResource::~Graphics2DResource() { +} + +PP_Bool Graphics2DResource::Describe(PP_Size* size, PP_Bool* is_always_opaque) { + *size = size_; + *is_always_opaque = is_always_opaque_; + return PP_TRUE; +} + +thunk::PPB_Graphics2D_API* Graphics2DResource::AsPPB_Graphics2D_API() { + return this; +} + +void Graphics2DResource::PaintImageData(PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect) { + Resource* image_object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(image_data); + if (!image_object || pp_instance() != image_object->pp_instance()) { + Log(PP_LOGLEVEL_ERROR, + "Graphics2DResource.PaintImageData: Bad image resource."); + return; + } + + PP_Rect dummy; + memset(&dummy, 0, sizeof(PP_Rect)); + Post(RENDERER, PpapiHostMsg_Graphics2D_PaintImageData( + image_object->host_resource(), *top_left, + !!src_rect, src_rect ? *src_rect : dummy)); +} + +void Graphics2DResource::Scroll(const PP_Rect* clip_rect, + const PP_Point* amount) { + PP_Rect dummy; + memset(&dummy, 0, sizeof(PP_Rect)); + Post(RENDERER, PpapiHostMsg_Graphics2D_Scroll( + !!clip_rect, clip_rect ? *clip_rect : dummy, *amount)); +} + +void Graphics2DResource::ReplaceContents(PP_Resource image_data) { + thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_image( + image_data, true); + if (enter_image.failed()) + return; + + // Check that the PP_Instance matches. + Resource* image_object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(image_data); + if (!image_object || pp_instance() != image_object->pp_instance()) { + Log(PP_LOGLEVEL_ERROR, + "Graphics2DResource.PaintImageData: Bad image resource."); + return; + } + enter_image.object()->SetIsCandidateForReuse(); + + Post(RENDERER, PpapiHostMsg_Graphics2D_ReplaceContents( + image_object->host_resource())); +} + +PP_Bool Graphics2DResource::SetScale(float scale) { + if (scale <= 0.0f) + return PP_FALSE; + Post(RENDERER, PpapiHostMsg_Graphics2D_Dev_SetScale(scale)); + scale_ = scale; + return PP_TRUE; +} + +float Graphics2DResource::GetScale() { + return scale_; +} + +int32_t Graphics2DResource::Flush(scoped_refptr<TrackedCallback> callback) { + // If host is not even created, return failure immediately. This can happen + // when failed to initialize (in constructor). + if (!sent_create_to_renderer()) + return PP_ERROR_FAILED; + + if (TrackedCallback::IsPending(current_flush_callback_)) + return PP_ERROR_INPROGRESS; // Can't have >1 flush pending. + current_flush_callback_ = callback; + + Call<PpapiPluginMsg_Graphics2D_FlushAck>( + RENDERER, + PpapiHostMsg_Graphics2D_Flush(), + base::Bind(&Graphics2DResource::OnPluginMsgFlushACK, this)); + return PP_OK_COMPLETIONPENDING; +} + +bool Graphics2DResource::ReadImageData(PP_Resource image, + const PP_Point* top_left) { + if (!top_left) + return false; + int32_t result = SyncCall<PpapiPluginMsg_Graphics2D_ReadImageDataAck>( + RENDERER, + PpapiHostMsg_Graphics2D_ReadImageData(image, *top_left)); + return result == PP_OK; +} + +void Graphics2DResource::OnPluginMsgFlushACK( + const ResourceMessageReplyParams& params) { + current_flush_callback_->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/graphics_2d_resource.h b/chromium/ppapi/proxy/graphics_2d_resource.h new file mode 100644 index 00000000000..b7ec30c710d --- /dev/null +++ b/chromium/ppapi/proxy/graphics_2d_resource.h @@ -0,0 +1,62 @@ +// 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_PROXY_GRAPHICS_2D_RESOURCE_H_ +#define PPAPI_PROXY_GRAPHICS_2D_RESOURCE_H_ + +#include "base/compiler_specific.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_graphics_2d_api.h" + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +class PPAPI_PROXY_EXPORT Graphics2DResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_Graphics2D_API) { + public: + Graphics2DResource(Connection connection, + PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque); + + virtual ~Graphics2DResource(); + + // Resource overrides. + virtual thunk::PPB_Graphics2D_API* AsPPB_Graphics2D_API() OVERRIDE; + + // PPB_Graphics2D_API overrides. + virtual PP_Bool Describe(PP_Size* size, PP_Bool* is_always_opaque) OVERRIDE; + virtual void PaintImageData(PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect) OVERRIDE; + virtual void Scroll(const PP_Rect* clip_rect, + const PP_Point* amount) OVERRIDE; + virtual void ReplaceContents(PP_Resource image_data) OVERRIDE; + virtual PP_Bool SetScale(float scale) OVERRIDE; + virtual float GetScale() OVERRIDE; + virtual int32_t Flush(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual bool ReadImageData(PP_Resource image, + const PP_Point* top_left) OVERRIDE; + + private: + void OnPluginMsgFlushACK(const ResourceMessageReplyParams& params); + + const PP_Size size_; + const PP_Bool is_always_opaque_; + float scale_; + + scoped_refptr<TrackedCallback> current_flush_callback_; + + DISALLOW_COPY_AND_ASSIGN(Graphics2DResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_GRAPHICS_2D_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/handle_converter.cc b/chromium/ppapi/proxy/handle_converter.cc new file mode 100644 index 00000000000..534a8ae5945 --- /dev/null +++ b/chromium/ppapi/proxy/handle_converter.cc @@ -0,0 +1,285 @@ +// 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 "ppapi/proxy/handle_converter.h" + +#include <vector> +#include "base/bind.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/serialized_handle.h" +#include "ppapi/proxy/serialized_var.h" + +class NaClDescImcShm; + +namespace IPC { +class Message; +} + +namespace { + +void WriteHandle(int handle_index, + const ppapi::proxy::SerializedHandle& handle, + IPC::Message* message) { + ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), message); + + // Now write the handle itself in POSIX style. + message->WriteBool(true); // valid == true + message->WriteInt(handle_index); +} + +typedef std::vector<ppapi::proxy::SerializedHandle> Handles; + +// We define overloads for catching SerializedHandles so that we can share +// them correctly to the untrusted side. +// See ConvertHandlesImpl for how these get used. +void ConvertHandlesInParam(const ppapi::proxy::SerializedHandle& handle, + Handles* handles, + IPC::Message* msg, + int* handle_index) { + handles->push_back(handle); + if (msg) + WriteHandle((*handle_index)++, handle, msg); +} + +void HandleWriter(int* handle_index, + IPC::Message* m, + const ppapi::proxy::SerializedHandle& handle) { + WriteHandle((*handle_index)++, handle, m); +} + +void ConvertHandlesInParam(const ppapi::proxy::SerializedVar& var, + Handles* handles, + IPC::Message* msg, + int* handle_index) { + std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles(); + if (var_handles.empty()) + return; + + for (size_t i = 0; i < var_handles.size(); ++i) + handles->push_back(*var_handles[i]); + if (msg) + var.WriteDataToMessage(msg, base::Bind(&HandleWriter, handle_index)); +} + +// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall, +// the handles are carried inside the ResourceMessageReplyParams. +// NOTE: We only translate handles from host->NaCl. The only kind of +// ResourceMessageParams that travels this direction is +// ResourceMessageReplyParams, so that's the only one we need to handle. +void ConvertHandlesInParam( + const ppapi::proxy::ResourceMessageReplyParams& params, + Handles* handles, + IPC::Message* msg, + int* handle_index) { + // First, if we need to rewrite the message parameters, write everything + // before the handles (there's nothing after the handles). + if (msg) { + params.WriteReplyHeader(msg); + // IPC writes the vector length as an int before the contents of the + // vector. + msg->WriteInt(static_cast<int>(params.handles().size())); + } + for (Handles::const_iterator iter = params.handles().begin(); + iter != params.handles().end(); + ++iter) { + // ConvertHandle will write each handle to |msg|, if necessary. + ConvertHandlesInParam(*iter, handles, msg, handle_index); + } + // Tell ResourceMessageReplyParams that we have taken the handles, so it + // shouldn't close them. The NaCl runtime will take ownership of them. + params.ConsumeHandles(); +} + +// This overload is to catch all types other than SerializedHandle or +// ResourceMessageReplyParams. On Windows, |msg| will be a valid pointer, and we +// must write |param| to it. +template <class T> +void ConvertHandlesInParam(const T& param, + Handles* /* handles */, + IPC::Message* msg, + int* /* handle_index */) { + // It's not a handle, so just write to the output message, if necessary. + if (msg) + IPC::WriteParam(msg, param); +} + +// These just break apart the given tuple and run ConvertHandle over each param. +// The idea is to extract any handles in the tuple, while writing all data to +// msg (if msg is valid). The msg will only be valid on Windows, where we need +// to re-write all of the message parameters, writing the handles in POSIX style +// for NaCl. +template <class A> +void ConvertHandlesImpl(const Tuple1<A>& t1, Handles* handles, + IPC::Message* msg) { + int handle_index = 0; + ConvertHandlesInParam(t1.a, handles, msg, &handle_index); +} +template <class A, class B> +void ConvertHandlesImpl(const Tuple2<A, B>& t1, Handles* handles, + IPC::Message* msg) { + int handle_index = 0; + ConvertHandlesInParam(t1.a, handles, msg, &handle_index); + ConvertHandlesInParam(t1.b, handles, msg, &handle_index); +} +template <class A, class B, class C> +void ConvertHandlesImpl(const Tuple3<A, B, C>& t1, Handles* handles, + IPC::Message* msg) { + int handle_index = 0; + ConvertHandlesInParam(t1.a, handles, msg, &handle_index); + ConvertHandlesInParam(t1.b, handles, msg, &handle_index); + ConvertHandlesInParam(t1.c, handles, msg, &handle_index); +} +template <class A, class B, class C, class D> +void ConvertHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles, + IPC::Message* msg) { + int handle_index = 0; + ConvertHandlesInParam(t1.a, handles, msg, &handle_index); + ConvertHandlesInParam(t1.b, handles, msg, &handle_index); + ConvertHandlesInParam(t1.c, handles, msg, &handle_index); + ConvertHandlesInParam(t1.d, handles, msg, &handle_index); +} + +template <class MessageType> +class HandleConverterImpl { + public: + explicit HandleConverterImpl(const IPC::Message* msg) + : msg_(static_cast<const MessageType*>(msg)) { + } + bool ConvertMessage(Handles* handles, IPC::Message* out_msg) { + typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params; + if (!MessageType::Read(msg_, ¶ms)) + return false; + ConvertHandlesImpl(params, handles, out_msg); + return true; + } + + bool ConvertReply(Handles* handles, IPC::SyncMessage* out_msg) { + typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple + params; + if (!MessageType::ReadReplyParam(msg_, ¶ms)) + return false; + // If we need to rewrite the message (i.e., on Windows), we need to make + // sure we write the message id first. + if (out_msg) { + out_msg->set_reply(); + int id = IPC::SyncMessage::GetMessageId(*msg_); + out_msg->WriteInt(id); + } + ConvertHandlesImpl(params, handles, out_msg); + return true; + } + // TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we + // ever pass handles in one of those. + + private: + const MessageType* msg_; +}; + +} // namespace + +#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ + case MESSAGE_TYPE::ID: { \ + HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \ + if (!extractor.ConvertMessage(handles, new_msg_ptr->get())) \ + return false; \ + break; \ + } +#define CASE_FOR_REPLY(MESSAGE_TYPE) \ + case MESSAGE_TYPE::ID: { \ + HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \ + if (!extractor.ConvertReply( \ + handles, \ + static_cast<IPC::SyncMessage*>(new_msg_ptr->get()))) \ + return false; \ + break; \ + } + +namespace ppapi { +namespace proxy { + +class SerializedHandle; + +HandleConverter::HandleConverter() { +} + +bool HandleConverter::ConvertNativeHandlesToPosix( + const IPC::Message& msg, + std::vector<SerializedHandle>* handles, + scoped_ptr<IPC::Message>* new_msg_ptr) { + DCHECK(handles); + DCHECK(new_msg_ptr); + DCHECK(!new_msg_ptr->get()); + + // In Windows, we need to re-write the contents of the message. This is + // because in Windows IPC code, native HANDLE values are serialized in the + // body of the message. + // + // In POSIX, we only serialize an index in to a FileDescriptorSet, and the + // actual file descriptors are sent out-of-band. So on Windows, to make a + // message that's compatible with Windows, we need to write a new message that + // has simple indices in the message body instead of the HANDLEs. + // + // NOTE: This means on Windows, new_msg_ptr's serialized contents are not + // compatible with Windows IPC deserialization code; it is intended to be + // passed to NaCl. +#if defined(OS_WIN) + new_msg_ptr->reset( + new IPC::Message(msg.routing_id(), msg.type(), msg.priority())); +#else + // Even on POSIX, we have to rewrite messages to create channels, because + // these contain a handle with an invalid (place holder) descriptor. The + // message sending code sees this and doesn't pass the descriptor over + // correctly. + if (msg.type() == PpapiMsg_CreateNaClChannel::ID) { + new_msg_ptr->reset( + new IPC::Message(msg.routing_id(), msg.type(), msg.priority())); + } +#endif + + switch (msg.type()) { + CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel) + CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) + CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage) + CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) + case IPC_REPLY_ID: { + int id = IPC::SyncMessage::GetMessageId(msg); + PendingSyncMsgMap::iterator iter(pending_sync_msgs_.find(id)); + if (iter == pending_sync_msgs_.end()) { + NOTREACHED(); + return false; + } + uint32_t type = iter->second; + pending_sync_msgs_.erase(iter); + switch (type) { + CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) + CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple) + CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) + CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory) + default: + // Do nothing for messages we don't know. + break; + } + break; + } + default: + // Do nothing for messages we don't know. + break; + } + return true; +} + +void HandleConverter::RegisterSyncMessageForReply(const IPC::Message& msg) { + DCHECK(msg.is_sync()); + + int msg_id = IPC::SyncMessage::GetMessageId(msg); + DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end()); + + pending_sync_msgs_[msg_id] = msg.type(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/handle_converter.h b/chromium/ppapi/proxy/handle_converter.h new file mode 100644 index 00000000000..456ee8db71c --- /dev/null +++ b/chromium/ppapi/proxy/handle_converter.h @@ -0,0 +1,62 @@ +// 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 PPAPI_PROXY_HANDLE_CONVERTER_H_ +#define PPAPI_PROXY_HANDLE_CONVERTER_H_ + +#include <map> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace proxy { + +class SerializedHandle; + +class PPAPI_PROXY_EXPORT HandleConverter { + public: + HandleConverter(); + + // Convert the native handles in |msg| to NaCl style. + // In some cases (e.g., Windows), we need to re-write the contents of the + // message; in those cases, |new_msg_ptr| will be set to the new message. + // If |msg| is already in a good form for NaCl, |new_msg_ptr| is left NULL. + // See the explanation in the body of the method. + // + // In either case, all the handles in |msg| are extracted into |handles| so + // that they can be converted to NaClDesc handles. + // See chrome/nacl/nacl_ipc_adapter.cc for where this gets used. + bool ConvertNativeHandlesToPosix(const IPC::Message& msg, + std::vector<SerializedHandle>* handles, + scoped_ptr<IPC::Message>* new_msg_ptr); + + // This method informs HandleConverter that a sync message is being sent so + // that it can associate reply messages with their type. + // + // Users of HandleConverter must call this when they send a synchronous + // message, otherwise HandleConverter won't be able to convert handles in + // replies. + void RegisterSyncMessageForReply(const IPC::Message& msg); + + private: + // When we send a synchronous message (from untrusted to trusted), we store + // its type here, so that later we can associate the reply with its type + // and potentially translate handles in the message. + typedef std::map<int, uint32> PendingSyncMsgMap; + PendingSyncMsgMap pending_sync_msgs_; + + DISALLOW_COPY_AND_ASSIGN(HandleConverter); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_HANDLE_CONVERTER_H_ diff --git a/chromium/ppapi/proxy/host_dispatcher.cc b/chromium/ppapi/proxy/host_dispatcher.cc new file mode 100644 index 00000000000..cea7ab31f08 --- /dev/null +++ b/chromium/ppapi/proxy/host_dispatcher.cc @@ -0,0 +1,277 @@ +// 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 "ppapi/proxy/host_dispatcher.h" + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/host_var_serialization_rules.h" +#include "ppapi/proxy/interface_list.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_creation_proxy.h" +#include "ppapi/shared_impl/ppapi_globals.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef std::map<PP_Instance, HostDispatcher*> InstanceToDispatcherMap; +InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; + +typedef std::map<PP_Module, HostDispatcher*> ModuleToDispatcherMap; +ModuleToDispatcherMap* g_module_to_dispatcher = NULL; + +PP_Bool ReserveInstanceID(PP_Module module, PP_Instance instance) { + // Default to returning true (usable) failure. Otherwise, if there's some + // kind of communication error or the plugin just crashed, we'll get into an + // infinite loop generating new instnace IDs since we think they're all in + // use. + ModuleToDispatcherMap::const_iterator found = + g_module_to_dispatcher->find(module); + if (found == g_module_to_dispatcher->end()) { + NOTREACHED(); + return PP_TRUE; + } + + bool usable = true; + if (!found->second->Send(new PpapiMsg_ReserveInstanceId(instance, &usable))) + return PP_TRUE; + return PP_FromBool(usable); +} + +// Saves the state of the given bool and puts it back when it goes out of +// scope. +class BoolRestorer { + public: + BoolRestorer(bool* var) : var_(var), old_value_(*var) { + } + ~BoolRestorer() { + *var_ = old_value_; + } + private: + bool* var_; + bool old_value_; +}; + +} // namespace + +HostDispatcher::HostDispatcher(PP_Module module, + PP_GetInterface_Func local_get_interface, + SyncMessageStatusReceiver* sync_status, + const PpapiPermissions& permissions) + : Dispatcher(local_get_interface, permissions), + sync_status_(sync_status), + pp_module_(module), + ppb_proxy_(NULL), + allow_plugin_reentrancy_(false) { + if (!g_module_to_dispatcher) + g_module_to_dispatcher = new ModuleToDispatcherMap; + (*g_module_to_dispatcher)[pp_module_] = this; + + SetSerializationRules(new HostVarSerializationRules); + + ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>( + local_get_interface(PPB_PROXY_PRIVATE_INTERFACE)); + DCHECK(ppb_proxy_) << "The proxy interface should always be supported."; + + ppb_proxy_->SetReserveInstanceIDCallback(pp_module_, &ReserveInstanceID); +} + +HostDispatcher::~HostDispatcher() { + g_module_to_dispatcher->erase(pp_module_); +} + +bool HostDispatcher::InitHostWithChannel( + Delegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client, + const ppapi::Preferences& preferences) { + if (!Dispatcher::InitWithChannel(delegate, peer_pid, channel_handle, + is_client)) + return false; + AddIOThreadMessageFilter(sync_status_.get()); + + Send(new PpapiMsg_SetPreferences(preferences)); + return true; +} + +// static +HostDispatcher* HostDispatcher::GetForInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + return NULL; + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found == g_instance_to_dispatcher->end()) + return NULL; + return found->second; +} + +// static +void HostDispatcher::SetForInstance(PP_Instance instance, + HostDispatcher* dispatcher) { + if (!g_instance_to_dispatcher) + g_instance_to_dispatcher = new InstanceToDispatcherMap; + (*g_instance_to_dispatcher)[instance] = dispatcher; +} + +// static +void HostDispatcher::RemoveForInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + return; + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found != g_instance_to_dispatcher->end()) + g_instance_to_dispatcher->erase(found); +} + +bool HostDispatcher::IsPlugin() const { + return false; +} + +bool HostDispatcher::Send(IPC::Message* msg) { + TRACE_EVENT2("ppapi proxy", "HostDispatcher::Send", + "Class", IPC_MESSAGE_ID_CLASS(msg->type()), + "Line", IPC_MESSAGE_ID_LINE(msg->type())); + + // Normal sync messages are set to unblock, which would normally cause the + // plugin to be reentered to process them. We only want to do this when we + // know the plugin is in a state to accept reentrancy. Since the plugin side + // never clears this flag on messages it sends, we can't get deadlock, but we + // may still get reentrancy in the host as a result. + if (!allow_plugin_reentrancy_) + msg->set_unblock(false); + + if (msg->is_sync()) { + // Don't allow sending sync messages during module shutdown. Seee the "else" + // block below for why. + CHECK(!PP_ToBool(ppb_proxy()->IsInModuleDestructor(pp_module()))); + + // Prevent the dispatcher from going away during sync calls. Scenarios + // where this could happen include a Send for a sync message which while + // waiting for the reply, dispatches an incoming ExecuteScript call which + // destroys the plugin module and in turn the dispatcher. + ScopedModuleReference scoped_ref(this); + + sync_status_->BeginBlockOnSyncMessage(); + bool result = Dispatcher::Send(msg); + sync_status_->EndBlockOnSyncMessage(); + + return result; + } else { + // We don't want to have a scoped ref for async message cases since since + // async messages are sent during module desruction. In this case, the + // module will have a 0 refcount and addrefing and releasing it will + // reenter the destructor and it will crash. + return Dispatcher::Send(msg); + } +} + +bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { + // Prevent the dispatcher from going away during a message handler. This must + // be at the outermost scope so it's released last. + ScopedModuleReference death_grip(this); + + TRACE_EVENT2("ppapi proxy", "HostDispatcher::OnMessageReceived", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + + // We only want to allow reentrancy when the most recent message from the + // plugin was a scripting message. We save the old state of the flag on the + // stack in case we're (we are the host) being reentered ourselves. The flag + // is set to false here for all messages, and then the scripting API will + // explicitly set it to true during processing of those messages that can be + // reentered. + BoolRestorer restorer(&allow_plugin_reentrancy_); + allow_plugin_reentrancy_ = false; + + for (size_t i = 0; i < filters_.size(); i++) { + if (filters_[i]->OnMessageReceived(msg)) + return true; + } + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(HostDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_LogWithSource, OnHostMsgLogWithSource) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + if (handled) + return true; + return Dispatcher::OnMessageReceived(msg); + + // Note: |this| may be deleted once the death_grip goes out of scope! +} + +void HostDispatcher::OnChannelError() { + Dispatcher::OnChannelError(); // Stop using the channel. + + // Tell the host about the crash so it can clean up and display notification. + ppb_proxy_->PluginCrashed(pp_module()); +} + +const void* HostDispatcher::GetProxiedInterface(const std::string& iface_name) { + const void* proxied_interface = + InterfaceList::GetInstance()->GetInterfaceForPPP(iface_name); + if (!proxied_interface) + return NULL; // Don't have a proxy for this interface, don't query further. + + PluginSupportedMap::iterator iter(plugin_supported_.find(iface_name)); + if (iter == plugin_supported_.end()) { + // Need to query. Cache the result so we only do this once. + bool supported = false; + + bool previous_reentrancy_value = allow_plugin_reentrancy_; + allow_plugin_reentrancy_ = true; + Send(new PpapiMsg_SupportsInterface(iface_name, &supported)); + allow_plugin_reentrancy_ = previous_reentrancy_value; + + std::pair<PluginSupportedMap::iterator, bool> iter_success_pair; + iter_success_pair = plugin_supported_.insert( + PluginSupportedMap::value_type(iface_name, supported)); + iter = iter_success_pair.first; + } + if (iter->second) + return proxied_interface; + return NULL; +} + +void HostDispatcher::OnInvalidMessageReceived() { + // TODO(brettw) bug 95345 kill the plugin when an invalid message is + // received. +} + +void HostDispatcher::OnHostMsgLogWithSource(PP_Instance instance, + int int_log_level, + const std::string& source, + const std::string& value) { + PP_LogLevel level = static_cast<PP_LogLevel>(int_log_level); + if (instance) { + PpapiGlobals::Get()->LogWithSource(instance, level, source, value); + } else { + PpapiGlobals::Get()->BroadcastLogWithSource(pp_module_, level, + source, value); + } +} + +// ScopedModuleReference ------------------------------------------------------- + +ScopedModuleReference::ScopedModuleReference(Dispatcher* dispatcher) + : dispatcher_(NULL) { + if (!dispatcher->IsPlugin()) { + dispatcher_ = static_cast<HostDispatcher*>(dispatcher); + dispatcher_->ppb_proxy()->AddRefModule(dispatcher_->pp_module()); + } +} + +ScopedModuleReference::~ScopedModuleReference() { + if (dispatcher_) + dispatcher_->ppb_proxy()->ReleaseModule(dispatcher_->pp_module()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/host_dispatcher.h b/chromium/ppapi/proxy/host_dispatcher.h new file mode 100644 index 00000000000..ebd6ef96587 --- /dev/null +++ b/chromium/ppapi/proxy/host_dispatcher.h @@ -0,0 +1,156 @@ +// 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_PROXY_HOST_DISPATCHER_H_ +#define PPAPI_PROXY_HOST_DISPATCHER_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/process/process.h" +#include "ipc/ipc_channel_proxy.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/dispatcher.h" + +struct PPB_Proxy_Private; + +namespace ppapi { + +struct Preferences; + +namespace proxy { + +class PPAPI_PROXY_EXPORT HostDispatcher : public Dispatcher { + public: + // This interface receives notifications about sync messages being sent by + // the dispatcher to the plugin process. It is used to detect a hung plugin. + // + // Note that there can be nested sync messages, so the begin/end status + // actually represents a stack of blocking messages. + class SyncMessageStatusReceiver : public IPC::ChannelProxy::MessageFilter { + public: + // Notification that a sync message is about to be sent out. + virtual void BeginBlockOnSyncMessage() = 0; + + // Notification that a sync message reply was received and the dispatcher + // is no longer blocked on a sync message. + virtual void EndBlockOnSyncMessage() = 0; + + protected: + virtual ~SyncMessageStatusReceiver() {} + }; + + // Constructor for the renderer side. This will take a reference to the + // SyncMessageStatusReceiver. + // + // You must call InitHostWithChannel after the constructor. + HostDispatcher(PP_Module module, + PP_GetInterface_Func local_get_interface, + SyncMessageStatusReceiver* sync_status, + const PpapiPermissions& permissions); + ~HostDispatcher(); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitHostWithChannel(Delegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client, + const Preferences& preferences); + + // The host side maintains a mapping from PP_Instance to Dispatcher so + // that we can send the messages to the right channel. + static HostDispatcher* GetForInstance(PP_Instance instance); + static void SetForInstance(PP_Instance instance, + HostDispatcher* dispatcher); + static void RemoveForInstance(PP_Instance instance); + + // Returns the host's notion of our PP_Module. This will be different than + // the plugin's notion of its PP_Module because the plugin process may be + // used by multiple renderer processes. + // + // Use this value instead of a value from the plugin whenever talking to the + // host. + PP_Module pp_module() const { return pp_module_; } + + // Dispatcher overrides. + virtual bool IsPlugin() const; + virtual bool Send(IPC::Message* msg); + + // IPC::Listener. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + virtual void OnChannelError() OVERRIDE; + + // Proxied version of calling GetInterface on the plugin. This will check + // if the plugin supports the given interface (with caching) and returns the + // pointer to the proxied interface if it is supported. Returns NULL if the + // given interface isn't supported by the plugin or the proxy. + const void* GetProxiedInterface(const std::string& iface_name); + + // See the value below. Call this when processing a scripting message from + // the plugin that can be reentered. This is set to false at the beginning + // of processing of each message from the plugin. + void set_allow_plugin_reentrancy() { + allow_plugin_reentrancy_ = true; + } + + // Returns the proxy interface for talking to the implementation. + const PPB_Proxy_Private* ppb_proxy() const { return ppb_proxy_; } + + protected: + // Overridden from Dispatcher. + virtual void OnInvalidMessageReceived(); + + private: + void OnHostMsgLogWithSource(PP_Instance instance, + int int_log_level, + const std::string& source, + const std::string& value); + + scoped_refptr<SyncMessageStatusReceiver> sync_status_; + + PP_Module pp_module_; + + // Maps interface name to whether that interface is supported. If an interface + // name is not in the map, that implies that we haven't queried for it yet. + typedef base::hash_map<std::string, bool> PluginSupportedMap; + PluginSupportedMap plugin_supported_; + + // Guaranteed non-NULL. + const PPB_Proxy_Private* ppb_proxy_; + + // Set to true when the plugin is in a state that it can be reentered by a + // sync message from the host. We allow reentrancy only when we're processing + // a sync message from the renderer that is a scripting command. When the + // plugin is in this state, it needs to accept reentrancy since scripting may + // ultimately call back into the plugin. + bool allow_plugin_reentrancy_; + + DISALLOW_COPY_AND_ASSIGN(HostDispatcher); +}; + +// Create this object on the stack to prevent the module (and hence the +// dispatcher) from being deleted out from under you. This is necessary when +// calling some scripting functions that may delete the plugin. +// +// This class does nothing if used on the plugin side. +class ScopedModuleReference { + public: + explicit ScopedModuleReference(Dispatcher* dispatcher); + ~ScopedModuleReference(); + + private: + HostDispatcher* dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ScopedModuleReference); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_HOST_DISPATCHER_H_ diff --git a/chromium/ppapi/proxy/host_resolver_private_resource.cc b/chromium/ppapi/proxy/host_resolver_private_resource.cc new file mode 100644 index 00000000000..10ff06a9382 --- /dev/null +++ b/chromium/ppapi/proxy/host_resolver_private_resource.cc @@ -0,0 +1,57 @@ +// 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 "ppapi/proxy/host_resolver_private_resource.h" + +#include "ppapi/proxy/net_address_resource.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace ppapi { +namespace proxy { + +HostResolverPrivateResource::HostResolverPrivateResource(Connection connection, + PP_Instance instance) + : HostResolverResourceBase(connection, instance, true) { +} + +HostResolverPrivateResource::~HostResolverPrivateResource() { +} + +thunk::PPB_HostResolver_Private_API* +HostResolverPrivateResource::AsPPB_HostResolver_Private_API() { + return this; +} + +int32_t HostResolverPrivateResource::Resolve( + const char* host, + uint16_t port, + const PP_HostResolver_Private_Hint* hint, + scoped_refptr<TrackedCallback> callback) { + return ResolveImpl(host, port, hint, callback); +} + +PP_Var HostResolverPrivateResource::GetCanonicalName() { + return GetCanonicalNameImpl(); +} + +uint32_t HostResolverPrivateResource::GetSize() { + return GetSizeImpl(); +} + +bool HostResolverPrivateResource::GetNetAddress( + uint32_t index, + PP_NetAddress_Private* address) { + if (!address) + return false; + + scoped_refptr<NetAddressResource> addr_resource = GetNetAddressImpl(index); + if (!addr_resource.get()) + return false; + + *address = addr_resource->GetNetAddressPrivate(); + return true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/host_resolver_private_resource.h b/chromium/ppapi/proxy/host_resolver_private_resource.h new file mode 100644 index 00000000000..8281a1f9d3c --- /dev/null +++ b/chromium/ppapi/proxy/host_resolver_private_resource.h @@ -0,0 +1,46 @@ +// 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_PROXY_HOST_RESOLVER_PRIVATE_RESOURCE_H_ +#define PPAPI_PROXY_HOST_RESOLVER_PRIVATE_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/host_resolver_resource_base.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_host_resolver_private_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT HostResolverPrivateResource + : public HostResolverResourceBase, + public thunk::PPB_HostResolver_Private_API { + public: + HostResolverPrivateResource(Connection connection, + PP_Instance instance); + virtual ~HostResolverPrivateResource(); + + // PluginResource overrides. + virtual thunk::PPB_HostResolver_Private_API* + AsPPB_HostResolver_Private_API() OVERRIDE; + + // PPB_HostResolver_Private_API implementation. + virtual int32_t Resolve(const char* host, + uint16_t port, + const PP_HostResolver_Private_Hint* hint, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Var GetCanonicalName() OVERRIDE; + virtual uint32_t GetSize() OVERRIDE; + virtual bool GetNetAddress(uint32_t index, + PP_NetAddress_Private* address) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(HostResolverPrivateResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_HOST_RESOLVER_PRIVATE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/host_resolver_resource.cc b/chromium/ppapi/proxy/host_resolver_resource.cc new file mode 100644 index 00000000000..a2898566f7f --- /dev/null +++ b/chromium/ppapi/proxy/host_resolver_resource.cc @@ -0,0 +1,85 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/host_resolver_resource.h" + +#include "base/logging.h" +#include "ppapi/c/private/ppb_host_resolver_private.h" +#include "ppapi/proxy/net_address_resource.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace ppapi { +namespace proxy { + +namespace { + +PP_HostResolver_Private_Hint ConvertToHostResolverPrivateHint( + const PP_HostResolver_Hint& hint) { + PP_HostResolver_Private_Hint private_hint; + switch (hint.family) { + case PP_NETADDRESS_FAMILY_UNSPECIFIED: + private_hint.family = PP_NETADDRESSFAMILY_PRIVATE_UNSPECIFIED; + break; + case PP_NETADDRESS_FAMILY_IPV4: + private_hint.family = PP_NETADDRESSFAMILY_PRIVATE_IPV4; + break; + case PP_NETADDRESS_FAMILY_IPV6: + private_hint.family = PP_NETADDRESSFAMILY_PRIVATE_IPV6; + break; + default: + NOTREACHED(); + private_hint.family = PP_NETADDRESSFAMILY_PRIVATE_UNSPECIFIED; + } + + private_hint.flags = 0; + if (hint.flags & PP_HOSTRESOLVER_FLAG_CANONNAME) + private_hint.flags |= PP_HOST_RESOLVER_PRIVATE_FLAGS_CANONNAME; + + return private_hint; +} + +} // namespace + +HostResolverResource::HostResolverResource(Connection connection, + PP_Instance instance) + : HostResolverResourceBase(connection, instance, false) { +} + +HostResolverResource::~HostResolverResource() { +} + +thunk::PPB_HostResolver_API* HostResolverResource::AsPPB_HostResolver_API() { + return this; +} + +int32_t HostResolverResource::Resolve(const char* host, + uint16_t port, + const PP_HostResolver_Hint* hint, + scoped_refptr<TrackedCallback> callback) { + if (!hint) + return PP_ERROR_BADARGUMENT; + + PP_HostResolver_Private_Hint private_hint = + ConvertToHostResolverPrivateHint(*hint); + return ResolveImpl(host, port, &private_hint, callback); +} + +PP_Var HostResolverResource::GetCanonicalName() { + return GetCanonicalNameImpl(); +} + +uint32_t HostResolverResource::GetNetAddressCount() { + return GetSizeImpl(); +} + +PP_Resource HostResolverResource::GetNetAddress(uint32_t index) { + scoped_refptr<NetAddressResource> addr_resource = GetNetAddressImpl(index); + if (!addr_resource.get()) + return 0; + + return addr_resource->GetReference(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/host_resolver_resource.h b/chromium/ppapi/proxy/host_resolver_resource.h new file mode 100644 index 00000000000..055dfb81071 --- /dev/null +++ b/chromium/ppapi/proxy/host_resolver_resource.h @@ -0,0 +1,43 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_HOST_RESOLVER_RESOURCE_H_ +#define PPAPI_PROXY_HOST_RESOLVER_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/host_resolver_resource_base.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_host_resolver_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT HostResolverResource + : public HostResolverResourceBase, + public thunk::PPB_HostResolver_API { + public: + HostResolverResource(Connection connection, PP_Instance instance); + virtual ~HostResolverResource(); + + // PluginResource overrides. + virtual thunk::PPB_HostResolver_API* AsPPB_HostResolver_API() OVERRIDE; + + // thunk::PPB_HostResolver_API implementation. + virtual int32_t Resolve(const char* host, + uint16_t port, + const PP_HostResolver_Hint* hint, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Var GetCanonicalName() OVERRIDE; + virtual uint32_t GetNetAddressCount() OVERRIDE; + virtual PP_Resource GetNetAddress(uint32_t index) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(HostResolverResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_HOST_RESOLVER_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/host_resolver_resource_base.cc b/chromium/ppapi/proxy/host_resolver_resource_base.cc new file mode 100644 index 00000000000..5cbbbb2aa9a --- /dev/null +++ b/chromium/ppapi/proxy/host_resolver_resource_base.cc @@ -0,0 +1,132 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/host_resolver_resource_base.h" + +#include "base/bind.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/net_address_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +namespace { + +int32_t ConvertPPError(int32_t pp_error, bool private_api) { + // The private API doesn't return network-specific error codes or + // PP_ERROR_NOACCESS. In order to preserve the behavior, we convert those to + // PP_ERROR_FAILED. + // TODO(yzshen): Consider defining ranges for different kinds of PP_Error + // codes, so that we can detect network-specific error codes in a better way. + if (private_api && + (pp_error <= PP_ERROR_CONNECTION_CLOSED || + pp_error == PP_ERROR_NOACCESS)) { + return PP_ERROR_FAILED; + } + + return pp_error; +} + +} // namespace + +HostResolverResourceBase::HostResolverResourceBase(Connection connection, + PP_Instance instance, + bool private_api) + : PluginResource(connection, instance), + private_api_(private_api), + allow_get_results_(false) { + if (private_api) + SendCreate(BROWSER, PpapiHostMsg_HostResolver_CreatePrivate()); + else + SendCreate(BROWSER, PpapiHostMsg_HostResolver_Create()); +} + +HostResolverResourceBase::~HostResolverResourceBase() { +} + +int32_t HostResolverResourceBase::ResolveImpl( + const char* host, + uint16_t port, + const PP_HostResolver_Private_Hint* hint, + scoped_refptr<TrackedCallback> callback) { + allow_get_results_ = false; + if (!host || !hint) + return PP_ERROR_BADARGUMENT; + if (ResolveInProgress()) + return PP_ERROR_INPROGRESS; + + resolve_callback_ = callback; + + HostPortPair host_port; + host_port.host = host; + host_port.port = port; + + SendResolve(host_port, hint); + return PP_OK_COMPLETIONPENDING; +} + +PP_Var HostResolverResourceBase::GetCanonicalNameImpl() { + if (!allow_get_results_) + return PP_MakeUndefined(); + + return StringVar::StringToPPVar(canonical_name_); +} + +uint32_t HostResolverResourceBase::GetSizeImpl() { + if (!allow_get_results_) + return 0; + return static_cast<uint32_t>(net_address_list_.size()); +} + +scoped_refptr<NetAddressResource> HostResolverResourceBase::GetNetAddressImpl( + uint32_t index) { + if (!allow_get_results_ || index >= GetSizeImpl()) + return scoped_refptr<NetAddressResource>(); + + return net_address_list_[index]; +} + +void HostResolverResourceBase::OnPluginMsgResolveReply( + const ResourceMessageReplyParams& params, + const std::string& canonical_name, + const std::vector<PP_NetAddress_Private>& net_address_list) { + if (params.result() == PP_OK) { + allow_get_results_ = true; + canonical_name_ = canonical_name; + + net_address_list_.clear(); + for (std::vector<PP_NetAddress_Private>::const_iterator iter = + net_address_list.begin(); + iter != net_address_list.end(); + ++iter) { + net_address_list_.push_back( + new NetAddressResource(connection(), pp_instance(), *iter)); + } + } else { + canonical_name_.clear(); + net_address_list_.clear(); + } + resolve_callback_->Run(ConvertPPError(params.result(), private_api_)); +} + +void HostResolverResourceBase::SendResolve( + const HostPortPair& host_port, + const PP_HostResolver_Private_Hint* hint) { + PpapiHostMsg_HostResolver_Resolve msg(host_port, *hint); + Call<PpapiPluginMsg_HostResolver_ResolveReply>( + BROWSER, + msg, + base::Bind(&HostResolverResourceBase::OnPluginMsgResolveReply, + base::Unretained(this))); +} + +bool HostResolverResourceBase::ResolveInProgress() const { + return TrackedCallback::IsPending(resolve_callback_); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/host_resolver_resource_base.h b/chromium/ppapi/proxy/host_resolver_resource_base.h new file mode 100644 index 00000000000..d27d9888179 --- /dev/null +++ b/chromium/ppapi/proxy/host_resolver_resource_base.h @@ -0,0 +1,74 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_HOST_RESOLVER_RESOURCE_BASE_H_ +#define PPAPI_PROXY_HOST_RESOLVER_RESOURCE_BASE_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "ppapi/c/private/ppb_host_resolver_private.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +namespace ppapi { + +class TrackedCallback; + +struct HostPortPair { + std::string host; + uint16_t port; +}; + +namespace proxy { + +class NetAddressResource; + +class PPAPI_PROXY_EXPORT HostResolverResourceBase: public PluginResource { + public: + HostResolverResourceBase(Connection connection, + PP_Instance instance, + bool private_api); + virtual ~HostResolverResourceBase(); + + int32_t ResolveImpl(const char* host, + uint16_t port, + const PP_HostResolver_Private_Hint* hint, + scoped_refptr<TrackedCallback> callback); + PP_Var GetCanonicalNameImpl(); + uint32_t GetSizeImpl(); + scoped_refptr<NetAddressResource> GetNetAddressImpl(uint32_t index); + + private: + // IPC message handlers. + void OnPluginMsgResolveReply( + const ResourceMessageReplyParams& params, + const std::string& canonical_name, + const std::vector<PP_NetAddress_Private>& net_address_list); + + void SendResolve(const HostPortPair& host_port, + const PP_HostResolver_Private_Hint* hint); + + bool ResolveInProgress() const; + + bool private_api_; + + scoped_refptr<TrackedCallback> resolve_callback_; + + // Set to false if there is a pending resolve request or the previous request + // failed. + bool allow_get_results_; + std::string canonical_name_; + std::vector<scoped_refptr<NetAddressResource> > net_address_list_; + + DISALLOW_COPY_AND_ASSIGN(HostResolverResourceBase); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_HOST_RESOLVER_RESOURCE_BASE_H_ diff --git a/chromium/ppapi/proxy/host_var_serialization_rules.cc b/chromium/ppapi/proxy/host_var_serialization_rules.cc new file mode 100644 index 00000000000..dcc965bd691 --- /dev/null +++ b/chromium/ppapi/proxy/host_var_serialization_rules.cc @@ -0,0 +1,58 @@ +// 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 "ppapi/proxy/host_var_serialization_rules.h" + +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/var_tracker.h" + +using ppapi::PpapiGlobals; +using ppapi::VarTracker; + +namespace ppapi { +namespace proxy { + +HostVarSerializationRules::HostVarSerializationRules() { +} + +HostVarSerializationRules::~HostVarSerializationRules() { +} + +PP_Var HostVarSerializationRules::SendCallerOwned(const PP_Var& var) { + return var; +} + +PP_Var HostVarSerializationRules::BeginReceiveCallerOwned(const PP_Var& var) { + return var; +} + +void HostVarSerializationRules::EndReceiveCallerOwned(const PP_Var& var) { + if (var.type != PP_VARTYPE_OBJECT && var.type >= PP_VARTYPE_STRING) { + // Release our reference to the local Var. + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var); + } +} + +PP_Var HostVarSerializationRules::ReceivePassRef(const PP_Var& var) { + // See PluginVarSerialization::BeginSendPassRef for an example. + if (var.type == PP_VARTYPE_OBJECT) + PpapiGlobals::Get()->GetVarTracker()->AddRefVar(var); + return var; +} + +PP_Var HostVarSerializationRules::BeginSendPassRef(const PP_Var& var) { + return var; +} + +void HostVarSerializationRules::EndSendPassRef(const PP_Var& /* var */) { + // See PluginVarSerialization::ReceivePassRef for an example. We don't need + // to do anything here. +} + +void HostVarSerializationRules::ReleaseObjectRef(const PP_Var& var) { + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/host_var_serialization_rules.h b/chromium/ppapi/proxy/host_var_serialization_rules.h new file mode 100644 index 00000000000..8de6cdecf34 --- /dev/null +++ b/chromium/ppapi/proxy/host_var_serialization_rules.h @@ -0,0 +1,39 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_HOST_VAR_SERIALIZATION_RULES_H_ +#define PPAPI_PROXY_HOST_VAR_SERIALIZATION_RULES_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace ppapi { +namespace proxy { + +// Implementation of the VarSerializationRules interface for the host side. +class HostVarSerializationRules : public VarSerializationRules { + public: + HostVarSerializationRules(); + ~HostVarSerializationRules(); + + // VarSerialization implementation. + virtual PP_Var SendCallerOwned(const PP_Var& var); + virtual PP_Var BeginReceiveCallerOwned(const PP_Var& var); + virtual void EndReceiveCallerOwned(const PP_Var& var); + virtual PP_Var ReceivePassRef(const PP_Var& var); + virtual PP_Var BeginSendPassRef(const PP_Var& var); + virtual void EndSendPassRef(const PP_Var& var); + virtual void ReleaseObjectRef(const PP_Var& var); + + private: + DISALLOW_COPY_AND_ASSIGN(HostVarSerializationRules); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_HOST_VAR_SERIALIZATION_RULES_H_ diff --git a/chromium/ppapi/proxy/interface_list.cc b/chromium/ppapi/proxy/interface_list.cc new file mode 100644 index 00000000000..d9feb89d08c --- /dev/null +++ b/chromium/ppapi/proxy/interface_list.cc @@ -0,0 +1,392 @@ +// 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 "ppapi/proxy/interface_list.h" + +#include "base/lazy_instance.h" +#include "base/memory/singleton.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_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_ime_input_event_dev.h" +#include "ppapi/c/dev/ppb_keyboard_input_event_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_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_view_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/ppb_audio_config.h" +#include "ppapi/c/ppb_audio.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_host_resolver.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/c/ppb_input_event.h" +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppb_message_loop.h" +#include "ppapi/c/ppb_messaging.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_text_input_controller.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/pp_errors.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/c/private/ppb_content_decryptor_private.h" +#include "ppapi/c/private/ppb_ext_crx_file_system_private.h" +#include "ppapi/c/private/ppb_file_io_private.h" +#include "ppapi/c/private/ppb_file_ref_private.h" +#include "ppapi/c/private/ppb_flash_clipboard.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.h" +#include "ppapi/c/private/ppb_flash_device_id.h" +#include "ppapi/c/private/ppb_flash_drm.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_host_resolver_private.h" +#include "ppapi/c/private/ppb_net_address_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_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_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/private/ppp_content_decryptor_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/proxy/interface_proxy.h" +#include "ppapi/proxy/ppb_audio_proxy.h" +#include "ppapi/proxy/ppb_broker_proxy.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/ppb_core_proxy.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/ppb_flash_message_loop_proxy.h" +#include "ppapi/proxy/ppb_graphics_3d_proxy.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/ppb_instance_proxy.h" +#include "ppapi/proxy/ppb_message_loop_proxy.h" +#include "ppapi/proxy/ppb_network_monitor_private_proxy.h" +#include "ppapi/proxy/ppb_tcp_socket_private_proxy.h" +#include "ppapi/proxy/ppb_tcp_socket_proxy.h" +#include "ppapi/proxy/ppb_testing_proxy.h" +#include "ppapi/proxy/ppb_var_deprecated_proxy.h" +#include "ppapi/proxy/ppb_video_decoder_proxy.h" +#include "ppapi/proxy/ppb_x509_certificate_private_proxy.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/ppp_content_decryptor_private_proxy.h" +#include "ppapi/proxy/ppp_graphics_3d_proxy.h" +#include "ppapi/proxy/ppp_input_event_proxy.h" +#include "ppapi/proxy/ppp_instance_private_proxy.h" +#include "ppapi/proxy/ppp_instance_proxy.h" +#include "ppapi/proxy/ppp_messaging_proxy.h" +#include "ppapi/proxy/ppp_mouse_lock_proxy.h" +#include "ppapi/proxy/ppp_printing_proxy.h" +#include "ppapi/proxy/ppp_text_input_proxy.h" +#include "ppapi/proxy/ppp_video_decoder_proxy.h" +#include "ppapi/proxy/resource_creation_proxy.h" +#include "ppapi/shared_impl/ppb_opengles2_shared.h" +#include "ppapi/shared_impl/ppb_var_shared.h" +#include "ppapi/thunk/thunk.h" + +// Helper to get the proxy name PPB_Foo_Proxy given the API name PPB_Foo. +#define PROXY_CLASS_NAME(api_name) api_name##_Proxy + +// Helper to get the interface ID PPB_Foo_Proxy::kApiID given the API +// name PPB_Foo. +#define PROXY_API_ID(api_name) PROXY_CLASS_NAME(api_name)::kApiID + +// Helper to get the name of the templatized factory function. +#define PROXY_FACTORY_NAME(api_name) ProxyFactory<PROXY_CLASS_NAME(api_name)> + +// Helper to get the name of the thunk GetPPB_Foo_1_0_Thunk given the interface +// struct name PPB_Foo_1_0. +#define INTERFACE_THUNK_NAME(iface_struct) thunk::Get##iface_struct##_Thunk + +namespace ppapi { +namespace proxy { + +namespace { + +// The interface list has interfaces with no ID listed as "NoAPIName" which +// means there's no corresponding _Proxy object. Our macros expand this to +// NoAPIName_Proxy, and then they look for kApiID inside it. +// +// This dummy class provides the correct definition for that interface ID, +// which is "NONE". +class NoAPIName_Proxy { + public: + static const ApiID kApiID = API_ID_NONE; +}; + +template<typename ProxyClass> +InterfaceProxy* ProxyFactory(Dispatcher* dispatcher) { + return new ProxyClass(dispatcher); +} + +base::LazyInstance<PpapiPermissions> g_process_global_permissions; + +} // namespace + +InterfaceList::InterfaceList() { + memset(id_to_factory_, 0, sizeof(id_to_factory_)); + + // Register the API factories for each of the API types. This calls AddProxy + // for each InterfaceProxy type we support. + #define PROXIED_API(api_name) \ + AddProxy(PROXY_API_ID(api_name), &PROXY_FACTORY_NAME(api_name)); + + // Register each proxied interface by calling AddPPB for each supported + // interface. Set current_required_permission to the appropriate value for + // the value you want expanded by this macro. + #define PROXIED_IFACE(api_name, iface_str, iface_struct) \ + AddPPB(iface_str, PROXY_API_ID(api_name), \ + INTERFACE_THUNK_NAME(iface_struct)(), \ + current_required_permission); + + { + Permission current_required_permission = PERMISSION_NONE; + #include "ppapi/thunk/interfaces_ppb_private_no_permissions.h" + #include "ppapi/thunk/interfaces_ppb_public_stable.h" + } + + { + Permission current_required_permission = PERMISSION_DEV; + #include "ppapi/thunk/interfaces_ppb_public_dev.h" + } + { + Permission current_required_permission = PERMISSION_PRIVATE; + #include "ppapi/thunk/interfaces_ppb_private.h" + } + { +#if !defined(OS_NACL) + Permission current_required_permission = PERMISSION_FLASH; + #include "ppapi/thunk/interfaces_ppb_private_flash.h" +#endif // !defined(OS_NACL) + } + + #undef PROXIED_API + #undef PROXIED_IFACE + + // Manually add some special proxies. Some of these don't have interfaces + // that they support, so aren't covered by the macros above, but have proxies + // for message routing. Others have different implementations between the + // proxy and the impl and there's no obvious message routing. + AddProxy(API_ID_RESOURCE_CREATION, &ResourceCreationProxy::Create); + AddProxy(API_ID_PPP_CLASS, &PPP_Class_Proxy::Create); + AddPPB(PPB_CORE_INTERFACE_1_0, API_ID_PPB_CORE, + PPB_Core_Proxy::GetPPB_Core_Interface(), PERMISSION_NONE); + AddPPB(PPB_MESSAGELOOP_INTERFACE_1_0, API_ID_NONE, + PPB_MessageLoop_Proxy::GetInterface(), PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetInterface(), PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_INSTANCEDARRAYS_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetInstancedArraysInterface(), PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_FRAMEBUFFERBLIT_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetFramebufferBlitInterface(), PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_FRAMEBUFFERMULTISAMPLE_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetFramebufferMultisampleInterface(), + PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_CHROMIUMENABLEFEATURE_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetChromiumEnableFeatureInterface(), + PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_CHROMIUMMAPSUB_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetChromiumMapSubInterface(), PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_CHROMIUMMAPSUB_DEV_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetChromiumMapSubInterface(), PERMISSION_NONE); + AddPPB(PPB_OPENGLES2_QUERY_INTERFACE_1_0, API_ID_NONE, + PPB_OpenGLES2_Shared::GetQueryInterface(), PERMISSION_NONE); + AddPPB(PPB_VAR_ARRAY_BUFFER_INTERFACE_1_0, API_ID_NONE, + PPB_Var_Shared::GetVarArrayBufferInterface1_0(), + PERMISSION_NONE); + AddPPB(PPB_VAR_INTERFACE_1_1, API_ID_NONE, + PPB_Var_Shared::GetVarInterface1_1(), PERMISSION_NONE); + AddPPB(PPB_VAR_INTERFACE_1_0, API_ID_NONE, + PPB_Var_Shared::GetVarInterface1_0(), PERMISSION_NONE); + +#if !defined(OS_NACL) + // PPB (browser) interfaces. + // Do not add more stuff here, they should be added to interface_list*.h + // TODO(brettw) remove these. + AddPPB(PPB_Instance_Proxy::GetInfoPrivate(), PERMISSION_PRIVATE); + AddPPB(PPB_Var_Deprecated_Proxy::GetInfo(), PERMISSION_DEV); + + // TODO(tomfinegan): Figure out where to put these once we refactor things + // to load the PPP interface struct from the PPB interface. + AddProxy(API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + &ProxyFactory<PPP_ContentDecryptor_Private_Proxy>); + AddPPP(PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE, + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + PPP_ContentDecryptor_Private_Proxy::GetProxyInterface()); +#endif + AddPPB(PPB_Testing_Proxy::GetInfo(), PERMISSION_TESTING); + + // PPP (plugin) interfaces. + // TODO(brettw) move these to interface_list*.h + AddProxy(API_ID_PPP_INSTANCE, &ProxyFactory<PPP_Instance_Proxy>); + #if !defined(OS_NACL) + AddPPP(PPP_INSTANCE_INTERFACE_1_1, API_ID_PPP_INSTANCE, + PPP_Instance_Proxy::GetInstanceInterface()); + #endif + AddProxy(API_ID_PPP_PRINTING, &ProxyFactory<PPP_Printing_Proxy>); + AddPPP(PPP_PRINTING_DEV_INTERFACE, API_ID_PPP_PRINTING, + PPP_Printing_Proxy::GetProxyInterface()); + AddProxy(API_ID_PPP_TEXT_INPUT, &ProxyFactory<PPP_TextInput_Proxy>); + AddPPP(PPP_TEXTINPUT_DEV_INTERFACE, API_ID_PPP_TEXT_INPUT, + PPP_TextInput_Proxy::GetProxyInterface()); + + // Old-style GetInfo PPP interfaces. + // Do not add more stuff here, they should be added to interface_list*.h + // TODO(brettw) remove these. + AddPPP(PPP_InputEvent_Proxy::GetInfo()); + AddPPP(PPP_Messaging_Proxy::GetInfo()); + AddPPP(PPP_MouseLock_Proxy::GetInfo()); + AddPPP(PPP_Graphics3D_Proxy::GetInfo()); +#if !defined(OS_NACL) + AddPPP(PPP_Instance_Private_Proxy::GetInfo()); + AddPPP(PPP_VideoDecoder_Proxy::GetInfo()); +#endif +} + +InterfaceList::~InterfaceList() { +} + +// static +InterfaceList* InterfaceList::GetInstance() { + return Singleton<InterfaceList>::get(); +} + +// static +void InterfaceList::SetProcessGlobalPermissions( + const PpapiPermissions& permissions) { + g_process_global_permissions.Get() = permissions; +} + +ApiID InterfaceList::GetIDForPPBInterface(const std::string& name) const { + NameToInterfaceInfoMap::const_iterator found = + name_to_browser_info_.find(name); + if (found == name_to_browser_info_.end()) + return API_ID_NONE; + return found->second.id; +} + +ApiID InterfaceList::GetIDForPPPInterface(const std::string& name) const { + NameToInterfaceInfoMap::const_iterator found = + name_to_plugin_info_.find(name); + if (found == name_to_plugin_info_.end()) + return API_ID_NONE; + return found->second.id; +} + +InterfaceProxy::Factory InterfaceList::GetFactoryForID(ApiID id) const { + int index = static_cast<int>(id); + COMPILE_ASSERT(API_ID_NONE == 0, none_must_be_zero); + if (id <= 0 || id >= API_ID_COUNT) + return NULL; + return id_to_factory_[index]; +} + +const void* InterfaceList::GetInterfaceForPPB(const std::string& name) const { + NameToInterfaceInfoMap::const_iterator found = + name_to_browser_info_.find(name); + if (found == name_to_browser_info_.end()) + return NULL; + + if (g_process_global_permissions.Get().HasPermission( + found->second.required_permission)) + return found->second.iface; + return NULL; +} + +const void* InterfaceList::GetInterfaceForPPP(const std::string& name) const { + NameToInterfaceInfoMap::const_iterator found = + name_to_plugin_info_.find(name); + if (found == name_to_plugin_info_.end()) + return NULL; + return found->second.iface; +} + +void InterfaceList::AddProxy(ApiID id, + InterfaceProxy::Factory factory) { + // For interfaces with no corresponding _Proxy objects, the macros will + // generate calls to this function with API_ID_NONE. This means we + // should just skip adding a factory for these functions. + if (id == API_ID_NONE) + return; + + // The factory should be an exact dupe of the one we already have if it + // has already been registered before. + int index = static_cast<int>(id); + DCHECK(!id_to_factory_[index] || id_to_factory_[index] == factory); + + id_to_factory_[index] = factory; +} + +void InterfaceList::AddPPB(const char* name, + ApiID id, + const void* iface, + Permission perm) { + DCHECK(name_to_browser_info_.find(name) == name_to_browser_info_.end()); + name_to_browser_info_[name] = InterfaceInfo(id, iface, perm); +} + +void InterfaceList::AddPPP(const char* name, + ApiID id, + const void* iface) { + DCHECK(name_to_plugin_info_.find(name) == name_to_plugin_info_.end()); + name_to_plugin_info_[name] = InterfaceInfo(id, iface, PERMISSION_NONE); +} + +void InterfaceList::AddPPB(const InterfaceProxy::Info* info, Permission perm) { + AddProxy(info->id, info->create_proxy); + AddPPB(info->name, info->id, info->interface_ptr, perm); +} + +void InterfaceList::AddPPP(const InterfaceProxy::Info* info) { + AddProxy(info->id, info->create_proxy); + AddPPP(info->name, info->id, info->interface_ptr); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/interface_list.h b/chromium/ppapi/proxy/interface_list.h new file mode 100644 index 00000000000..9ef91dcc1f9 --- /dev/null +++ b/chromium/ppapi/proxy/interface_list.h @@ -0,0 +1,105 @@ +// 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_PROXY_INTERFACE_LIST_H_ +#define PPAPI_PROXY_INTERFACE_LIST_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/ppapi_permissions.h" + +namespace ppapi { +namespace proxy { + +class InterfaceList { + public: + InterfaceList(); + ~InterfaceList(); + + static InterfaceList* GetInstance(); + + // Sets the permissions that the interface list will use to compute + // whether an interface is available to the current process. By default, + // this will be "no permissions", which will give only access to public + // stable interfaces via GetInterface. + // + // IMPORTANT: This is not a security boundary. Malicious plugins can bypass + // this check since they run in the same address space as this code in the + // plugin process. A real security check is required for all IPC messages. + // This check just allows us to return NULL for interfaces you "shouldn't" be + // using to keep honest plugins honest. + static PPAPI_PROXY_EXPORT void SetProcessGlobalPermissions( + const PpapiPermissions& permissions); + + // Looks up the ID for the given interface name. Returns API_ID_NONE if + // the interface string is not found. + ApiID GetIDForPPBInterface(const std::string& name) const; + ApiID GetIDForPPPInterface(const std::string& name) const; + + // Looks up the factory function for the given ID. Returns NULL if not + // supported. + InterfaceProxy::Factory GetFactoryForID(ApiID id) const; + + // Returns the interface pointer for the given browser or plugin interface, + // or NULL if it's not supported. + const void* GetInterfaceForPPB(const std::string& name) const; + const void* GetInterfaceForPPP(const std::string& name) const; + + private: + struct InterfaceInfo { + InterfaceInfo() + : id(API_ID_NONE), + iface(NULL), + required_permission(PERMISSION_NONE) { + } + InterfaceInfo(ApiID in_id, const void* in_interface, Permission in_perm) + : id(in_id), + iface(in_interface), + required_permission(in_perm) { + } + + ApiID id; + const void* iface; + + // Permission required to return non-null for this interface. This will + // be checked with the value set via SetProcessGlobalPermissionBits when + // an interface is requested. + Permission required_permission; + }; + + typedef std::map<std::string, InterfaceInfo> NameToInterfaceInfoMap; + + void AddProxy(ApiID id, InterfaceProxy::Factory factory); + + // Permissions is the type of permission required to access the corresponding + // interface. Currently this must be just one unique permission (rather than + // a bitfield). + void AddPPB(const char* name, ApiID id, const void* iface, + Permission permission); + void AddPPP(const char* name, ApiID id, const void* iface); + + // Old-style add functions. These should be removed when the rest of the + // proxies are converted over to using the new system. + void AddPPB(const InterfaceProxy::Info* info, Permission perm); + void AddPPP(const InterfaceProxy::Info* info); + + PpapiPermissions permissions_; + + NameToInterfaceInfoMap name_to_browser_info_; + NameToInterfaceInfoMap name_to_plugin_info_; + + InterfaceProxy::Factory id_to_factory_[API_ID_COUNT]; + + DISALLOW_COPY_AND_ASSIGN(InterfaceList); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_INTERFACE_LIST_H_ + diff --git a/chromium/ppapi/proxy/interface_proxy.cc b/chromium/ppapi/proxy/interface_proxy.cc new file mode 100644 index 00000000000..2de48033944 --- /dev/null +++ b/chromium/ppapi/proxy/interface_proxy.cc @@ -0,0 +1,25 @@ +// 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 "ppapi/proxy/interface_proxy.h" + +#include "base/logging.h" +#include "ppapi/proxy/dispatcher.h" + +namespace ppapi { +namespace proxy { + +InterfaceProxy::InterfaceProxy(Dispatcher* dispatcher) + : dispatcher_(dispatcher) { +} + +InterfaceProxy::~InterfaceProxy() { +} + +bool InterfaceProxy::Send(IPC::Message* msg) { + return dispatcher_->Send(msg); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/interface_proxy.h b/chromium/ppapi/proxy/interface_proxy.h new file mode 100644 index 00000000000..dcab5473c9c --- /dev/null +++ b/chromium/ppapi/proxy/interface_proxy.h @@ -0,0 +1,68 @@ +// 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 PPAPI_PROXY_INTERFACE_PROXY_H_ +#define PPAPI_PROXY_INTERFACE_PROXY_H_ + +#include "base/basictypes.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_sender.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/api_id.h" + +namespace ppapi { +namespace proxy { + +class Dispatcher; + +class InterfaceProxy : public IPC::Listener, public IPC::Sender { + public: + // Factory function type for interfaces. Ownership of the returned pointer + // is transferred to the caller. + typedef InterfaceProxy* (*Factory)(Dispatcher* dispatcher); + + // DEPRECATED: New classes should be registered directly in the interface + // list. This is kept around until we convert all the existing code. + // + // Information about the interface. Each interface has a static function to + // return its info, which allows either construction on the target side, and + // getting the proxied interface on the source side (see dispatcher.h for + // terminology). + struct Info { + const void* interface_ptr; + + const char* name; + ApiID id; + + bool is_trusted; + + InterfaceProxy::Factory create_proxy; + }; + + virtual ~InterfaceProxy(); + + Dispatcher* dispatcher() const { return dispatcher_; } + + // IPC::Sender implementation. + virtual bool Send(IPC::Message* msg); + + // Sub-classes must implement IPC::Listener which contains this: + //virtual bool OnMessageReceived(const IPC::Message& msg); + + protected: + // Creates the given interface associated with the given dispatcher. The + // dispatcher manages our lifetime. + InterfaceProxy(Dispatcher* dispatcher); + + private: + Dispatcher* dispatcher_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_INTERFACE_PROXY_H_ + diff --git a/chromium/ppapi/proxy/locking_resource_releaser.h b/chromium/ppapi/proxy/locking_resource_releaser.h new file mode 100644 index 00000000000..d390ac4426e --- /dev/null +++ b/chromium/ppapi/proxy/locking_resource_releaser.h @@ -0,0 +1,41 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_LOCKING_RESOURCE_RELEASER_H_ +#define PPAPI_PROXY_LOCKING_RESOURCE_RELEASER_H_ + +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource_tracker.h" + +namespace ppapi { +namespace proxy { + +// LockingResourceReleaser is a simple RAII class for releasing a resource at +// the end of scope. This acquires the ProxyLock before releasing the resource. +// It is for use in unit tests. Most proxy or implementation code should use +// ScopedPPResource instead. Unit tests sometimes can't use ScopedPPResource +// because it asserts that the ProxyLock is already held. +class LockingResourceReleaser { + public: + explicit LockingResourceReleaser(PP_Resource resource) + : resource_(resource) { + } + ~LockingResourceReleaser() { + ProxyAutoLock lock; + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(resource_); + } + + PP_Resource get() { return resource_; } + + private: + PP_Resource resource_; + + DISALLOW_COPY_AND_ASSIGN(LockingResourceReleaser); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_LOCKING_RESOURCE_RELEASER_H_ diff --git a/chromium/ppapi/proxy/mock_resource.cc b/chromium/ppapi/proxy/mock_resource.cc new file mode 100644 index 00000000000..9662bad4f41 --- /dev/null +++ b/chromium/ppapi/proxy/mock_resource.cc @@ -0,0 +1,18 @@ +// 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 "ppapi/proxy/mock_resource.h" + +namespace ppapi { +namespace proxy { + +MockResource::MockResource(const HostResource& resource) + : Resource(OBJECT_IS_PROXY, resource) { +} + +MockResource::~MockResource() { +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/mock_resource.h b/chromium/ppapi/proxy/mock_resource.h new file mode 100644 index 00000000000..768929da4f5 --- /dev/null +++ b/chromium/ppapi/proxy/mock_resource.h @@ -0,0 +1,26 @@ +// 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 PPAPI_PROXY_MOCK_RESOURCE_H_ +#define PPAPI_PROXY_MOCK_RESOURCE_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/shared_impl/resource.h" + +namespace ppapi { +namespace proxy { + +class MockResource : public ppapi::Resource { + public: + MockResource(const ppapi::HostResource& resource); + virtual ~MockResource(); + + private: + DISALLOW_COPY_AND_ASSIGN(MockResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_MOCK_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/net_address_resource.cc b/chromium/ppapi/proxy/net_address_resource.cc new file mode 100644 index 00000000000..9d906a5e062 --- /dev/null +++ b/chromium/ppapi/proxy/net_address_resource.cc @@ -0,0 +1,81 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/net_address_resource.h" + +#include <string> + +#include "ppapi/c/pp_bool.h" +#include "ppapi/shared_impl/private/net_address_private_impl.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +NetAddressResource::NetAddressResource( + Connection connection, + PP_Instance instance, + const PP_NetAddress_IPv4& ipv4_addr) + : PluginResource(connection, instance) { + NetAddressPrivateImpl::CreateNetAddressPrivateFromIPv4Address(ipv4_addr, + &address_); +} + +NetAddressResource::NetAddressResource( + Connection connection, + PP_Instance instance, + const PP_NetAddress_IPv6& ipv6_addr) + : PluginResource(connection, instance) { + NetAddressPrivateImpl::CreateNetAddressPrivateFromIPv6Address(ipv6_addr, + &address_); +} + +NetAddressResource::NetAddressResource( + Connection connection, + PP_Instance instance, + const PP_NetAddress_Private& private_addr) + : PluginResource(connection, instance) { + address_ = private_addr; +} + +NetAddressResource::~NetAddressResource() { +} + +thunk::PPB_NetAddress_API* NetAddressResource::AsPPB_NetAddress_API() { + return this; +} + +PP_NetAddress_Family NetAddressResource::GetFamily() { + return NetAddressPrivateImpl::GetFamilyFromNetAddressPrivate(address_); +} + +PP_Var NetAddressResource::DescribeAsString(PP_Bool include_port) { + std::string description = NetAddressPrivateImpl::DescribeNetAddress( + address_, PP_ToBool(include_port)); + + if (description.empty()) + return PP_MakeUndefined(); + return StringVar::StringToPPVar(description); +} + +PP_Bool NetAddressResource::DescribeAsIPv4Address( + PP_NetAddress_IPv4* ipv4_addr) { + return PP_FromBool( + NetAddressPrivateImpl::DescribeNetAddressPrivateAsIPv4Address( + address_, ipv4_addr)); +} + +PP_Bool NetAddressResource::DescribeAsIPv6Address( + PP_NetAddress_IPv6* ipv6_addr) { + return PP_FromBool( + NetAddressPrivateImpl::DescribeNetAddressPrivateAsIPv6Address( + address_, ipv6_addr)); +} + +const PP_NetAddress_Private& NetAddressResource::GetNetAddressPrivate() { + return address_; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/net_address_resource.h b/chromium/ppapi/proxy/net_address_resource.h new file mode 100644 index 00000000000..4d236049f91 --- /dev/null +++ b/chromium/ppapi/proxy/net_address_resource.h @@ -0,0 +1,56 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_NET_ADDRESS_RESOURCE_H_ +#define PPAPI_PROXY_NET_ADDRESS_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/private/ppb_net_address_private.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_net_address_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT NetAddressResource : public PluginResource, + public thunk::PPB_NetAddress_API { + public: + NetAddressResource(Connection connection, + PP_Instance instance, + const PP_NetAddress_IPv4& ipv4_addr); + NetAddressResource(Connection connection, + PP_Instance instance, + const PP_NetAddress_IPv6& ipv6_addr); + NetAddressResource(Connection connection, + PP_Instance instance, + const PP_NetAddress_Private& private_addr); + + virtual ~NetAddressResource(); + + // PluginResource implementation. + virtual thunk::PPB_NetAddress_API* AsPPB_NetAddress_API() OVERRIDE; + + // PPB_NetAddress_API implementation. + virtual PP_NetAddress_Family GetFamily() OVERRIDE; + virtual PP_Var DescribeAsString(PP_Bool include_port) OVERRIDE; + virtual PP_Bool DescribeAsIPv4Address( + PP_NetAddress_IPv4* ipv4_addr) OVERRIDE; + virtual PP_Bool DescribeAsIPv6Address( + PP_NetAddress_IPv6* ipv6_addr) OVERRIDE; + virtual const PP_NetAddress_Private& GetNetAddressPrivate() OVERRIDE; + + private: + // TODO(yzshen): Refactor the code so that PPB_NetAddress resource doesn't + // use PP_NetAddress_Private as storage type. + PP_NetAddress_Private address_; + + DISALLOW_COPY_AND_ASSIGN(NetAddressResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_NET_ADDRESS_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/network_proxy_resource.cc b/chromium/ppapi/proxy/network_proxy_resource.cc new file mode 100644 index 00000000000..b004130f018 --- /dev/null +++ b/chromium/ppapi/proxy/network_proxy_resource.cc @@ -0,0 +1,66 @@ +// 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 "ppapi/proxy/network_proxy_resource.h" + +#include "base/bind.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +NetworkProxyResource::NetworkProxyResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_NetworkProxy_Create()); +} + +NetworkProxyResource::~NetworkProxyResource() { +} + +thunk::PPB_NetworkProxy_API* NetworkProxyResource::AsPPB_NetworkProxy_API() { + return this; +} + +int32_t NetworkProxyResource::GetProxyForURL( + PP_Instance /* instance */, + PP_Var url, + PP_Var* proxy_string, + scoped_refptr<TrackedCallback> callback) { + StringVar* string_url = StringVar::FromPPVar(url); + if (!string_url) + return PP_ERROR_BADARGUMENT; + Call<PpapiPluginMsg_NetworkProxy_GetProxyForURLReply>( + BROWSER, + PpapiHostMsg_NetworkProxy_GetProxyForURL(string_url->value()), + base::Bind(&NetworkProxyResource::OnPluginMsgGetProxyForURLReply, + base::Unretained(this), + base::Unretained(proxy_string), + callback)); + return PP_OK_COMPLETIONPENDING; +} + +void NetworkProxyResource::OnPluginMsgGetProxyForURLReply( + PP_Var* proxy_string_out_param, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::string& proxy_string) { + if (!TrackedCallback::IsPending(callback)) { + // The callback should not have already been run. If this resource is + // deleted, LastPluginRefWasReleased in PluginResource should abort the + // callback and should not run this callback. + NOTREACHED(); + return; + } + if (params.result() == PP_OK) { + *proxy_string_out_param = (new StringVar(proxy_string))->GetPPVar(); + } + callback->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/network_proxy_resource.h b/chromium/ppapi/proxy/network_proxy_resource.h new file mode 100644 index 00000000000..f2084ab3fd8 --- /dev/null +++ b/chromium/ppapi/proxy/network_proxy_resource.h @@ -0,0 +1,45 @@ +// 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 PPAPI_PROXY_NETWORK_PROXY_RESOURCE_H_ +#define PPAPI_PROXY_NETWORK_PROXY_RESOURCE_H_ + +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_network_proxy_api.h" + +namespace ppapi { +namespace proxy { + +// The proxy-side resource for PPB_NetworkProxy. +class PPAPI_PROXY_EXPORT NetworkProxyResource + : public PluginResource, + public thunk::PPB_NetworkProxy_API { + public: + NetworkProxyResource(Connection connection, PP_Instance instance); + virtual ~NetworkProxyResource(); + + private: + // Resource implementation. + virtual thunk::PPB_NetworkProxy_API* AsPPB_NetworkProxy_API() OVERRIDE; + + // PPB_NetworkProxy_API implementation. + virtual int32_t GetProxyForURL( + PP_Instance instance, + PP_Var url, + PP_Var* proxy_string, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + void OnPluginMsgGetProxyForURLReply(PP_Var* proxy_string_out_param, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const std::string& proxy_string); + + DISALLOW_COPY_AND_ASSIGN(NetworkProxyResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_NETWORK_PROXY_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/pdf_resource.cc b/chromium/ppapi/proxy/pdf_resource.cc new file mode 100644 index 00000000000..8e0a2e0bbf1 --- /dev/null +++ b/chromium/ppapi/proxy/pdf_resource.cc @@ -0,0 +1,192 @@ +// 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 "ppapi/proxy/pdf_resource.h" + +#include <stdlib.h> +#include <string.h> + +#include "base/command_line.h" +#include "base/metrics/histogram.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_pdf.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/shared_impl/var.h" +#include "third_party/icu/source/i18n/unicode/usearch.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// TODO(raymes): This is just copied from render_thread_impl.cc. We should have +// generic code somewhere to get the locale in the plugin. +std::string GetLocale() { + // The browser process should have passed the locale to the plugin via the + // --lang command line flag. + const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + const std::string& lang = parsed_command_line.GetSwitchValueASCII("lang"); + DCHECK(!lang.empty()); + return lang; +} + +} // namespace + +PDFResource::PDFResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(RENDERER, PpapiHostMsg_PDF_Create()); +} + +PDFResource::~PDFResource() { +} + +thunk::PPB_PDF_API* PDFResource::AsPPB_PDF_API() { + return this; +} + +PP_Var PDFResource::GetLocalizedString(PP_ResourceString string_id) { + std::string localized_string; + int32_t result = SyncCall<PpapiPluginMsg_PDF_GetLocalizedStringReply>( + RENDERER, PpapiHostMsg_PDF_GetLocalizedString(string_id), + &localized_string); + if (result != PP_OK) + return PP_MakeUndefined(); + return ppapi::StringVar::StringToPPVar(localized_string); +} + +void PDFResource::SearchString(const unsigned short* input_string, + const unsigned short* input_term, + bool case_sensitive, + PP_PrivateFindResult** results, int* count) { + if (locale_.empty()) + locale_ = GetLocale(); + const char16* string = reinterpret_cast<const char16*>(input_string); + const char16* term = reinterpret_cast<const char16*>(input_term); + + UErrorCode status = U_ZERO_ERROR; + UStringSearch* searcher = usearch_open(term, -1, string, -1, locale_.c_str(), + 0, &status); + DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING || + status == U_USING_DEFAULT_WARNING); + UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY; + + UCollator* collator = usearch_getCollator(searcher); + if (ucol_getStrength(collator) != strength) { + ucol_setStrength(collator, strength); + usearch_reset(searcher); + } + + status = U_ZERO_ERROR; + int match_start = usearch_first(searcher, &status); + DCHECK(status == U_ZERO_ERROR); + + std::vector<PP_PrivateFindResult> pp_results; + while (match_start != USEARCH_DONE) { + size_t matched_length = usearch_getMatchedLength(searcher); + PP_PrivateFindResult result; + result.start_index = match_start; + result.length = matched_length; + pp_results.push_back(result); + match_start = usearch_next(searcher, &status); + DCHECK(status == U_ZERO_ERROR); + } + + *count = pp_results.size(); + if (*count) { + *results = reinterpret_cast<PP_PrivateFindResult*>(malloc( + *count * sizeof(PP_PrivateFindResult))); + memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult)); + } else { + *results = NULL; + } + + usearch_close(searcher); +} + +void PDFResource::DidStartLoading() { + Post(RENDERER, PpapiHostMsg_PDF_DidStartLoading()); +} + +void PDFResource::DidStopLoading() { + Post(RENDERER, PpapiHostMsg_PDF_DidStopLoading()); +} + +void PDFResource::SetContentRestriction(int restrictions) { + Post(RENDERER, PpapiHostMsg_PDF_SetContentRestriction(restrictions)); +} + +void PDFResource::HistogramPDFPageCount(int count) { + UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count); +} + +void PDFResource::UserMetricsRecordAction(const PP_Var& action) { + scoped_refptr<ppapi::StringVar> action_str( + ppapi::StringVar::FromPPVar(action)); + if (action_str.get()) { + Post(RENDERER, + PpapiHostMsg_PDF_UserMetricsRecordAction(action_str->value())); + } +} + +void PDFResource::HasUnsupportedFeature() { + Post(RENDERER, PpapiHostMsg_PDF_HasUnsupportedFeature()); +} + +void PDFResource::Print() { + Post(RENDERER, PpapiHostMsg_PDF_Print()); +} + +void PDFResource::SaveAs() { + Post(RENDERER, PpapiHostMsg_PDF_SaveAs()); +} + +PP_Bool PDFResource::IsFeatureEnabled(PP_PDFFeature feature) { + PP_Bool result = PP_FALSE; + switch (feature) { + case PP_PDFFEATURE_HIDPI: + result = PP_TRUE; + break; + case PP_PDFFEATURE_PRINTING: + // TODO(raymes): Use PrintWebViewHelper::IsPrintingEnabled. + result = PP_FALSE; + break; + } + return result; +} + +PP_Resource PDFResource::GetResourceImageForScale(PP_ResourceImage image_id, + float scale) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + int32_t result = GenericSyncCall( + RENDERER, PpapiHostMsg_PDF_GetResourceImage(image_id, scale), &reply, + &reply_params); + if (result != PP_OK) + return 0; + + HostResource resource; + PP_ImageDataDesc image_desc; + if (!UnpackMessage<PpapiPluginMsg_PDF_GetResourceImageReply>( + reply, &resource, &image_desc)) { + return 0; + } + + if (resource.is_null()) + return 0; + if (!PPB_ImageData_Shared::IsImageDataDescValid(image_desc)) + return 0; + + base::SharedMemoryHandle handle; + if (!reply_params.TakeSharedMemoryHandleAtIndex(0, &handle)) + return 0; + return (new SimpleImageData(resource, image_desc, handle))->GetReference(); +} + +PP_Resource PDFResource::GetResourceImage(PP_ResourceImage image_id) { + return GetResourceImageForScale(image_id, 1.0f); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/pdf_resource.h b/chromium/ppapi/proxy/pdf_resource.h new file mode 100644 index 00000000000..704e1d4a44e --- /dev/null +++ b/chromium/ppapi/proxy/pdf_resource.h @@ -0,0 +1,67 @@ +// 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 PPAPI_PROXY_PDF_RESOURCE_H_ +#define PPAPI_PROXY_PDF_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_pdf_api.h" + +namespace ppapi { +namespace proxy { + +class PluginDispatcher; + +class PPAPI_PROXY_EXPORT PDFResource + : public PluginResource, + public thunk::PPB_PDF_API { + public: + PDFResource(Connection connection, PP_Instance instance); + virtual ~PDFResource(); + + // For unittesting with a given locale. + void SetLocaleForTest(const std::string& locale) { + locale_ = locale; + } + + // Resource override. + virtual thunk::PPB_PDF_API* AsPPB_PDF_API() OVERRIDE; + + // PPB_PDF_API implementation. + PP_Var GetLocalizedString(PP_ResourceString string_id) OVERRIDE; + virtual void SearchString(const unsigned short* input_string, + const unsigned short* input_term, + bool case_sensitive, + PP_PrivateFindResult** results, + int* count) OVERRIDE; + virtual void DidStartLoading() OVERRIDE; + virtual void DidStopLoading() OVERRIDE; + virtual void SetContentRestriction(int restrictions) OVERRIDE; + virtual void HistogramPDFPageCount(int count) OVERRIDE; + virtual void UserMetricsRecordAction(const PP_Var& action) OVERRIDE; + virtual void HasUnsupportedFeature() OVERRIDE; + virtual void Print() OVERRIDE; + virtual void SaveAs() OVERRIDE; + virtual PP_Bool IsFeatureEnabled(PP_PDFFeature feature) OVERRIDE; + virtual PP_Resource GetResourceImageForScale(PP_ResourceImage image_id, + float scale) OVERRIDE; + virtual PP_Resource GetResourceImage(PP_ResourceImage image_id) OVERRIDE; + + private: + std::string locale_; + + DISALLOW_COPY_AND_ASSIGN(PDFResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PDF_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/pdf_resource_unittest.cc b/chromium/ppapi/proxy/pdf_resource_unittest.cc new file mode 100644 index 00000000000..3ac60d6413b --- /dev/null +++ b/chromium/ppapi/proxy/pdf_resource_unittest.cc @@ -0,0 +1,206 @@ +// 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 <cstring> + +#include "base/strings/utf_string_conversions.h" +#include "ppapi/c/dev/ppb_memory_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/proxy/pdf_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/serialized_handle.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest PDFResourceTest; + +} // namespace + +TEST_F(PDFResourceTest, GetLocalizedString) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + std::string expected_string = "hello"; + PpapiPluginMsg_PDF_GetLocalizedStringReply reply_msg(expected_string); + ResourceSyncCallHandler handler( + &sink(), + PpapiHostMsg_PDF_GetLocalizedString::ID, + PP_OK, + reply_msg); + sink().AddFilter(&handler); + + PP_Var var = pdf_iface->GetLocalizedString( + pp_instance(), PP_RESOURCESTRING_PDFGETPASSWORD); + + { + ProxyAutoLock lock; + ScopedPPVar release_var(ScopedPPVar::PassRef(), var); + StringVar* string_var = StringVar::FromPPVar(var); + ASSERT_TRUE(string_var != NULL); + std::string actual_string = string_var->value(); + + ASSERT_EQ(PpapiHostMsg_PDF_GetLocalizedString::ID, + handler.last_handled_msg().type()); + ASSERT_EQ(expected_string, actual_string); + } + + // Remove the filter or it will be destroyed before the sink() is destroyed. + sink().RemoveFilter(&handler); +} + +TEST_F(PDFResourceTest, SearchString) { + ProxyAutoLock lock; + // Instantiate a resource explicitly so we can specify the locale. + scoped_refptr<PDFResource> pdf_resource( + new PDFResource(Connection(&sink(), &sink()), pp_instance())); + pdf_resource->SetLocaleForTest("en-US"); + + string16 input; + string16 term; + UTF8ToUTF16("abcdefabcdef", 12, &input); + UTF8ToUTF16("bc", 2, &term); + + PP_PrivateFindResult* results; + int count = 0; + pdf_resource->SearchString( + reinterpret_cast<const unsigned short*>(input.c_str()), + reinterpret_cast<const unsigned short*>(term.c_str()), + true, + &results, + &count); + + ASSERT_EQ(2, count); + ASSERT_EQ(1, results[0].start_index); + ASSERT_EQ(2, results[0].length); + ASSERT_EQ(7, results[1].start_index); + ASSERT_EQ(2, results[1].length); + + const PPB_Memory_Dev* memory_iface = thunk::GetPPB_Memory_Dev_0_1_Thunk(); + memory_iface->MemFree(results); +} + +TEST_F(PDFResourceTest, DidStartLoading) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + pdf_iface->DidStartLoading(pp_instance()); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_DidStartLoading::ID, ¶ms, &msg)); +} + +TEST_F(PDFResourceTest, DidStopLoading) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + pdf_iface->DidStopLoading(pp_instance()); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_DidStopLoading::ID, ¶ms, &msg)); +} + +TEST_F(PDFResourceTest, SetContentRestriction) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + int restrictions = 5; + pdf_iface->SetContentRestriction(pp_instance(), restrictions); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_SetContentRestriction::ID, ¶ms, &msg)); +} + +TEST_F(PDFResourceTest, HasUnsupportedFeature) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + pdf_iface->HasUnsupportedFeature(pp_instance()); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_HasUnsupportedFeature::ID, ¶ms, &msg)); +} + +TEST_F(PDFResourceTest, Print) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + pdf_iface->Print(pp_instance()); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_Print::ID, ¶ms, &msg)); +} + +TEST_F(PDFResourceTest, SaveAs) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + pdf_iface->SaveAs(pp_instance()); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_PDF_SaveAs::ID, ¶ms, &msg)); +} + +TEST_F(PDFResourceTest, GetResourceImageForScale) { + const PPB_PDF* pdf_iface = thunk::GetPPB_PDF_Thunk(); + + HostResource expected_resource; + expected_resource.SetHostResource(pp_instance(), 5); + PP_ImageDataDesc expected_desc = { + PP_IMAGEDATAFORMAT_BGRA_PREMUL, + { 5, 10 }, + 20, + }; + SerializedHandle serialized_handle(SerializedHandle::SHARED_MEMORY); + PpapiPluginMsg_PDF_GetResourceImageReply reply_msg(expected_resource, + expected_desc); + ResourceSyncCallHandler handler( + &sink(), + PpapiHostMsg_PDF_GetResourceImage::ID, + PP_OK, + reply_msg); + handler.set_serialized_handle(&serialized_handle); + sink().AddFilter(&handler); + + PP_Resource resource = pdf_iface->GetResourceImageForScale(pp_instance(), + PP_RESOURCEIMAGE_PDF_BUTTON_FTP, 1.0f); + { + ProxyAutoLock lock; + PluginResourceTracker* resource_tracker = + static_cast<PluginResourceTracker*>( + PluginGlobals::Get()->GetResourceTracker()); + Resource* resource_object = resource_tracker->GetResource(resource); + ImageData* image_data_object = static_cast<ImageData*>(resource_object); + PP_ImageDataDesc actual_desc = image_data_object->desc(); + ASSERT_EQ(expected_desc.format, actual_desc.format); + ASSERT_EQ(expected_desc.size.width, actual_desc.size.width); + ASSERT_EQ(expected_desc.size.height, actual_desc.size.height); + ASSERT_EQ(expected_desc.stride, actual_desc.stride); + + ASSERT_EQ(resource_tracker->PluginResourceForHostResource( + expected_resource), resource); + + resource_tracker->ReleaseResource(resource); + } + + // Remove the filter or it will be destroyed before the sink() is destroyed. + sink().RemoveFilter(&handler); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_array_buffer_var.cc b/chromium/ppapi/proxy/plugin_array_buffer_var.cc new file mode 100644 index 00000000000..7dd64d17b13 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_array_buffer_var.cc @@ -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. + +#include "ppapi/proxy/plugin_array_buffer_var.h" + +#include <stdlib.h> + +#include <limits> + +#include "base/memory/shared_memory.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_buffer_api.h" + +using base::SharedMemory; +using base::SharedMemoryHandle; +using ppapi::proxy::PluginGlobals; +using ppapi::proxy::PluginResourceTracker; + +namespace ppapi { + +PluginArrayBufferVar::PluginArrayBufferVar(uint32 size_in_bytes) + : buffer_(size_in_bytes), + plugin_handle_(base::SharedMemory::NULLHandle()), + size_in_bytes_(size_in_bytes) { +} + +PluginArrayBufferVar::PluginArrayBufferVar(uint32 size_in_bytes, + SharedMemoryHandle plugin_handle) + : plugin_handle_(plugin_handle), + size_in_bytes_(size_in_bytes) { +} + +PluginArrayBufferVar::~PluginArrayBufferVar() { + Unmap(); + + if (shmem_.get() == NULL) { + // The SharedMemory destuctor can't close the handle for us. + if (SharedMemory::IsHandleValid(plugin_handle_)) + SharedMemory::CloseHandle(plugin_handle_); + } else { + // Delete SharedMemory, if we have one. + shmem_.reset(); + } +} + +void* PluginArrayBufferVar::Map() { + if (shmem_.get()) + return shmem_->memory(); + if (SharedMemory::IsHandleValid(plugin_handle_)) { + shmem_.reset(new SharedMemory(plugin_handle_, false)); + if (!shmem_->Map(size_in_bytes_)) { + shmem_.reset(); + return NULL; + } + return shmem_->memory(); + } + if (buffer_.empty()) + return NULL; + return &(buffer_[0]); +} + +void PluginArrayBufferVar::Unmap() { + if (shmem_.get()) + shmem_->Unmap(); +} + +uint32 PluginArrayBufferVar::ByteLength() { + return size_in_bytes_; +} + +bool PluginArrayBufferVar::CopyToNewShmem( + PP_Instance instance, + int* host_handle_id, + SharedMemoryHandle* plugin_out_handle) { + ppapi::proxy::PluginDispatcher* dispatcher = + ppapi::proxy::PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return false; + + ppapi::proxy::SerializedHandle plugin_handle; + dispatcher->Send(new PpapiHostMsg_SharedMemory_CreateSharedMemory( + instance, ByteLength(), host_handle_id, &plugin_handle)); + if (!plugin_handle.IsHandleValid() || !plugin_handle.is_shmem() || + *host_handle_id == -1) + return false; + + base::SharedMemoryHandle tmp_handle = plugin_handle.shmem(); + SharedMemory s(tmp_handle, false); + if (!s.Map(ByteLength())) + return false; + memcpy(s.memory(), Map(), ByteLength()); + s.Unmap(); + + // We don't need to keep the shared memory around on the plugin side; + // we've already copied all our data into it. We'll make it invalid + // just to be safe. + *plugin_out_handle = base::SharedMemory::NULLHandle(); + + return true; +} + +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_array_buffer_var.h b/chromium/ppapi/proxy/plugin_array_buffer_var.h new file mode 100644 index 00000000000..84d9d217708 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_array_buffer_var.h @@ -0,0 +1,51 @@ +// 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_PROXY_PLUGIN_ARRAY_BUFFER_VAR_H_ +#define PPAPI_PROXY_PLUGIN_ARRAY_BUFFER_VAR_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { + +// Represents a plugin-side ArrayBufferVar. In the plugin process, it's +// owned as a vector. +class PluginArrayBufferVar : public ArrayBufferVar { + public: + explicit PluginArrayBufferVar(uint32 size_in_bytes); + PluginArrayBufferVar(uint32 size_in_bytes, + base::SharedMemoryHandle plugin_handle); + virtual ~PluginArrayBufferVar(); + + // ArrayBufferVar implementation. + virtual void* Map() OVERRIDE; + virtual void Unmap() OVERRIDE; + virtual uint32 ByteLength() OVERRIDE; + virtual bool CopyToNewShmem( + PP_Instance instance, + int* host_handle, + base::SharedMemoryHandle* plugin_handle) OVERRIDE; + + private: + // Non-shared memory + std::vector<uint8> buffer_; + + // Shared memory + base::SharedMemoryHandle plugin_handle_; + scoped_ptr<base::SharedMemory> shmem_; + uint32 size_in_bytes_; + + DISALLOW_COPY_AND_ASSIGN(PluginArrayBufferVar); +}; + +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_ARRAY_BUFFER_VAR_H_ diff --git a/chromium/ppapi/proxy/plugin_dispatcher.cc b/chromium/ppapi/proxy/plugin_dispatcher.cc new file mode 100644 index 00000000000..d6d0d909765 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_dispatcher.cc @@ -0,0 +1,369 @@ +// 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 "ppapi/proxy/plugin_dispatcher.h" + +#include <map> + +#include "base/compiler_specific.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_channel.h" +#include "ipc/ipc_sync_message_filter.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/flash_clipboard_resource.h" +#include "ppapi/proxy/flash_file_resource.h" +#include "ppapi/proxy/flash_resource.h" +#include "ppapi/proxy/gamepad_resource.h" +#include "ppapi/proxy/interface_list.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_message_filter.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_serialization_rules.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_instance_proxy.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/resource_creation_proxy.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource.h" + +#if defined(OS_POSIX) && !defined(OS_NACL) +#include "base/posix/eintr_wrapper.h" +#include "ipc/ipc_channel_posix.h" +#endif + +namespace ppapi { +namespace proxy { + +namespace { + +typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap; +InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; + +typedef std::set<PluginDispatcher*> DispatcherSet; +DispatcherSet* g_live_dispatchers = NULL; + +} // namespace + +InstanceData::InstanceData() + : is_request_surrounding_text_pending(false), + should_do_request_surrounding_text(false) { +} + +InstanceData::~InstanceData() { + // Run any pending mouse lock callback to prevent leaks. + if (mouse_lock_callback.get()) + mouse_lock_callback->Abort(); +} + +PluginDispatcher::PluginDispatcher(PP_GetInterface_Func get_interface, + const PpapiPermissions& permissions, + bool incognito) + : Dispatcher(get_interface, permissions), + plugin_delegate_(NULL), + received_preferences_(false), + plugin_dispatcher_id_(0), + incognito_(incognito) { + SetSerializationRules(new PluginVarSerializationRules(AsWeakPtr())); + + if (!g_live_dispatchers) + g_live_dispatchers = new DispatcherSet; + g_live_dispatchers->insert(this); +} + +PluginDispatcher::~PluginDispatcher() { + PluginGlobals::Get()->plugin_var_tracker()->DidDeleteDispatcher(this); + + if (plugin_delegate_) + plugin_delegate_->Unregister(plugin_dispatcher_id_); + + g_live_dispatchers->erase(this); + if (g_live_dispatchers->empty()) { + delete g_live_dispatchers; + g_live_dispatchers = NULL; + } +} + +// static +PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + return NULL; + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found == g_instance_to_dispatcher->end()) + return NULL; + return found->second; +} + +// static +PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) { + return GetForInstance(resource->pp_instance()); +} + +// static +const void* PluginDispatcher::GetBrowserInterface(const char* interface_name) { + if (!interface_name) { + DLOG(WARNING) << "|interface_name| is null. Did you forget to add " + "the |interface_name()| template function to the interface's C++ " + "wrapper?"; + return NULL; + } + + return InterfaceList::GetInstance()->GetInterfaceForPPB(interface_name); +} + +// static +void PluginDispatcher::LogWithSource(PP_Instance instance, + PP_LogLevel level, + const std::string& source, + const std::string& value) { + if (!g_live_dispatchers || !g_instance_to_dispatcher) + return; + + if (instance) { + InstanceToDispatcherMap::iterator found = + g_instance_to_dispatcher->find(instance); + if (found != g_instance_to_dispatcher->end()) { + // Send just to this specific dispatcher. + found->second->Send(new PpapiHostMsg_LogWithSource( + instance, static_cast<int>(level), source, value)); + return; + } + } + + // Instance 0 or invalid, send to all dispatchers. + for (DispatcherSet::iterator i = g_live_dispatchers->begin(); + i != g_live_dispatchers->end(); ++i) { + (*i)->Send(new PpapiHostMsg_LogWithSource( + instance, static_cast<int>(level), source, value)); + } +} + +const void* PluginDispatcher::GetPluginInterface( + const std::string& interface_name) { + InterfaceMap::iterator found = plugin_interfaces_.find(interface_name); + if (found == plugin_interfaces_.end()) { + const void* ret = local_get_interface()(interface_name.c_str()); + plugin_interfaces_.insert(std::make_pair(interface_name, ret)); + return ret; + } + return found->second; +} + +bool PluginDispatcher::InitPluginWithChannel( + PluginDelegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + if (!Dispatcher::InitWithChannel(delegate, peer_pid, channel_handle, + is_client)) + return false; + plugin_delegate_ = delegate; + plugin_dispatcher_id_ = plugin_delegate_->Register(this); + + sync_filter_ = new IPC::SyncMessageFilter(delegate->GetShutdownEvent()); + channel()->AddFilter(sync_filter_.get()); + + // The message filter will intercept and process certain messages directly + // on the I/O thread. + channel()->AddFilter( + new PluginMessageFilter(delegate->GetGloballySeenInstanceIDSet())); + return true; +} + +bool PluginDispatcher::IsPlugin() const { + return true; +} + +bool PluginDispatcher::SendMessage(IPC::Message* msg) { + // Currently we need to choose between two different mechanisms for sending. + // On the main thread we use the regular dispatch Send() method, on another + // thread we use SyncMessageFilter. + if (PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread()) + return Dispatcher::Send(msg); + return sync_filter_->Send(msg); +} + +bool PluginDispatcher::Send(IPC::Message* msg) { + TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send", + "Class", IPC_MESSAGE_ID_CLASS(msg->type()), + "Line", IPC_MESSAGE_ID_LINE(msg->type())); + // We always want plugin->renderer messages to arrive in-order. If some sync + // and some async messages are sent in response to a synchronous + // renderer->plugin call, the sync reply will be processed before the async + // reply, and everything will be confused. + // + // Allowing all async messages to unblock the renderer means more reentrancy + // there but gives correct ordering. + // + // We don't want reply messages to unblock however, as they will potentially + // end up on the wrong queue - see crbug.com/122443 + if (!msg->is_reply()) + msg->set_unblock(true); + if (msg->is_sync()) { + // Synchronous messages might be re-entrant, so we need to drop the lock. + ProxyAutoUnlock unlock; + return SendMessage(msg); + } + return SendMessage(msg); +} + +bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { + // We need to grab the proxy lock to ensure that we don't collide with the + // plugin making pepper calls on a different thread. + ProxyAutoLock lock; + TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + // Handle some plugin-specific control messages. + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply, OnMsgResourceReply) + IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) + IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) + IPC_MESSAGE_UNHANDLED(handled = false); + IPC_END_MESSAGE_MAP() + if (handled) + return true; + } + return Dispatcher::OnMessageReceived(msg); +} + +void PluginDispatcher::OnChannelError() { + Dispatcher::OnChannelError(); + + // The renderer has crashed or exited. This channel and all instances + // associated with it are no longer valid. + ForceFreeAllInstances(); + // TODO(brettw) free resources too! + delete this; +} + +void PluginDispatcher::DidCreateInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + g_instance_to_dispatcher = new InstanceToDispatcherMap; + (*g_instance_to_dispatcher)[instance] = this; + + instance_map_[instance] = InstanceData(); +} + +void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { + InstanceDataMap::iterator it = instance_map_.find(instance); + if (it != instance_map_.end()) + instance_map_.erase(it); + + if (g_instance_to_dispatcher) { + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found != g_instance_to_dispatcher->end()) { + DCHECK(found->second == this); + g_instance_to_dispatcher->erase(found); + } else { + NOTREACHED(); + } + } +} + +InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { + InstanceDataMap::iterator it = instance_map_.find(instance); + return (it == instance_map_.end()) ? NULL : &it->second; +} + +thunk::PPB_Instance_API* PluginDispatcher::GetInstanceAPI() { + return static_cast<PPB_Instance_Proxy*>( + GetInterfaceProxy(API_ID_PPB_INSTANCE)); +} + +thunk::ResourceCreationAPI* PluginDispatcher::GetResourceCreationAPI() { + return static_cast<ResourceCreationProxy*>( + GetInterfaceProxy(API_ID_RESOURCE_CREATION)); +} + +// static +void PluginDispatcher::DispatchResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg) { + // We need to grab the proxy lock to ensure that we don't collide with the + // plugin making pepper calls on a different thread. + ProxyAutoLock lock; + LockedDispatchResourceReply(reply_params, nested_msg); +} + +void PluginDispatcher::ForceFreeAllInstances() { + if (!g_instance_to_dispatcher) + return; + + // Iterating will remove each item from the map, so we need to make a copy + // to avoid things changing out from under is. + InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; + for (InstanceToDispatcherMap::iterator i = temp_map.begin(); + i != temp_map.end(); ++i) { + if (i->second == this) { + // Synthesize an "instance destroyed" message, this will notify the + // plugin and also remove it from our list of tracked plugins. + PpapiMsg_PPPInstance_DidDestroy msg(API_ID_PPP_INSTANCE, i->first); + OnMessageReceived(msg); + } + } +} + +void PluginDispatcher::OnMsgResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg) { + LockedDispatchResourceReply(reply_params, nested_msg); +} + +void PluginDispatcher::OnMsgSupportsInterface( + const std::string& interface_name, + bool* result) { + *result = !!GetPluginInterface(interface_name); + + // Do fallback for PPP_Instance. This is a hack here and if we have more + // cases like this it should be generalized. The PPP_Instance proxy always + // proxies the 1.1 interface, and then does fallback to 1.0 inside the + // plugin process (see PPP_Instance_Proxy). So here we return true for + // supporting the 1.1 interface if either 1.1 or 1.0 is supported. + if (!*result && interface_name == PPP_INSTANCE_INTERFACE) + *result = !!GetPluginInterface(PPP_INSTANCE_INTERFACE_1_0); +} + +void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) { + // The renderer may send us preferences more than once (currently this + // happens every time a new plugin instance is created). Since we don't have + // a way to signal to the plugin that the preferences have changed, changing + // the default fonts and such in the middle of a running plugin could be + // confusing to it. As a result, we never allow the preferences to be changed + // once they're set. The user will have to restart to get new font prefs + // propogated to plugins. + if (!received_preferences_) { + received_preferences_ = true; + preferences_ = prefs; + } +} + +// static +void PluginDispatcher::LockedDispatchResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg) { + Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource( + reply_params.pp_resource()); + if (!resource) { + DLOG_IF(INFO, reply_params.sequence() != 0) + << "Pepper resource reply message received but the resource doesn't " + "exist (probably has been destroyed)."; + return; + } + resource->OnReplyReceived(reply_params, nested_msg); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_dispatcher.h b/chromium/ppapi/proxy/plugin_dispatcher.h new file mode 100644 index 00000000000..3a9e7330865 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_dispatcher.h @@ -0,0 +1,226 @@ +// 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_PROXY_PLUGIN_DISPATCHER_H_ +#define PPAPI_PROXY_PLUGIN_DISPATCHER_H_ + +#include <set> +#include <string> + +#include "base/basictypes.h" +#include "base/containers/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/process/process.h" +#include "build/build_config.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/ppb_console.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/shared_impl/ppapi_preferences.h" +#include "ppapi/shared_impl/ppb_view_shared.h" +#include "ppapi/shared_impl/singleton_resource_id.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace IPC { +class SyncMessageFilter; +} + +namespace ppapi { + +struct Preferences; +class Resource; + +namespace thunk { +class PPB_Instance_API; +class ResourceCreationAPI; +} + +namespace proxy { + +class ResourceMessageReplyParams; + +// Used to keep track of per-instance data. +struct InstanceData { + InstanceData(); + ~InstanceData(); + + ViewData view; + + // When non-NULL, indicates the callback to execute when mouse lock is lost. + scoped_refptr<TrackedCallback> mouse_lock_callback; + + // A map of singleton resources which are lazily created. + typedef std::map<SingletonResourceID, scoped_refptr<Resource> > + SingletonResourceMap; + SingletonResourceMap singleton_resources; + + // Calls to |RequestSurroundingText()| are done by posted tasks. Track whether + // a) a task is pending, to avoid redundant calls, and b) whether we should + // actually call |RequestSurroundingText()|, to avoid stale calls (i.e., + // calling when we shouldn't). + bool is_request_surrounding_text_pending; + bool should_do_request_surrounding_text; +}; + +class PPAPI_PROXY_EXPORT PluginDispatcher + : public Dispatcher, + public base::SupportsWeakPtr<PluginDispatcher> { + public: + class PPAPI_PROXY_EXPORT PluginDelegate : public ProxyChannel::Delegate { + public: + // Returns the set used for globally uniquifying PP_Instances. This same + // set must be returned for all channels. + // + // DEREFERENCE ONLY ON THE I/O THREAD. + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() = 0; + + // Registers the plugin dispatcher and returns an ID. + // Plugin dispatcher IDs will be used to dispatch messages from the browser. + // Each call to Register() has to be matched with a call to Unregister(). + virtual uint32 Register(PluginDispatcher* plugin_dispatcher) = 0; + virtual void Unregister(uint32 plugin_dispatcher_id) = 0; + }; + + // Constructor for the plugin side. The init and shutdown functions will be + // will be automatically called when requested by the renderer side. The + // module ID will be set upon receipt of the InitializeModule message. + // + // Note about permissions: On the plugin side, the dispatcher and the plugin + // run in the same address space (including in nacl). This means that the + // permissions here are subject to malicious modification and bypass, and + // an exploited or malicious plugin could send any IPC messages and just + // bypass the permissions. All permissions must be checked "for realz" in the + // host process when receiving messages. We check them on the plugin side + // primarily to keep honest plugins honest, especially with respect to + // dev interfaces that they "shouldn't" be using. + // + // You must call InitPluginWithChannel after the constructor. + PluginDispatcher(PP_GetInterface_Func get_interface, + const PpapiPermissions& permissions, + bool incognito); + virtual ~PluginDispatcher(); + + // The plugin side maintains a mapping from PP_Instance to Dispatcher so + // that we can send the messages to the right channel if there are multiple + // renderers sharing the same plugin. This mapping is maintained by + // DidCreateInstance/DidDestroyInstance. + static PluginDispatcher* GetForInstance(PP_Instance instance); + + // Same as GetForInstance but retrieves the instance from the given resource + // object as a convenience. Returns NULL on failure. + static PluginDispatcher* GetForResource(const Resource* resource); + + // Implements the GetInterface function for the plugin to call to retrieve + // a browser interface. + static const void* GetBrowserInterface(const char* interface_name); + + // Logs the given log message to the given instance, or, if the instance is + // invalid, to all instances associated with all dispatchers. Used for + // global log messages. + static void LogWithSource(PP_Instance instance, + PP_LogLevel level, + const std::string& source, + const std::string& value); + + const void* GetPluginInterface(const std::string& interface_name); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + bool InitPluginWithChannel(PluginDelegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + // Dispatcher overrides. + virtual bool IsPlugin() const; + virtual bool Send(IPC::Message* msg); + + // IPC::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); + + // Keeps track of which dispatcher to use for each instance, active instances + // and tracks associated data like the current size. + void DidCreateInstance(PP_Instance instance); + void DidDestroyInstance(PP_Instance instance); + + // Gets the data for an existing instance, or NULL if the instance id doesn't + // correspond to a known instance. + InstanceData* GetInstanceData(PP_Instance instance); + + // Returns the corresponding API. These are APIs not associated with a + // resource. Guaranteed non-NULL. + thunk::PPB_Instance_API* GetInstanceAPI(); + thunk::ResourceCreationAPI* GetResourceCreationAPI(); + + // Returns the Preferences. + const Preferences& preferences() const { return preferences_; } + + uint32 plugin_dispatcher_id() const { return plugin_dispatcher_id_; } + bool incognito() const { return incognito_; } + + // Dispatches the given resource message to the appropriate resource in the + // plugin process. This should be wired to the various channels that messages + // come in from various other processes. + static void DispatchResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg); + + private: + friend class PluginDispatcherTest; + + // Notifies all live instances that they're now closed. This is used when + // a renderer crashes or some other error is received. + void ForceFreeAllInstances(); + + // IPC message handlers. + void OnMsgResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg); + void OnMsgSupportsInterface(const std::string& interface_name, bool* result); + void OnMsgSetPreferences(const Preferences& prefs); + + // Internal backed for DispatchResourceReply. + static void LockedDispatchResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg); + + virtual bool SendMessage(IPC::Message* msg); + + PluginDelegate* plugin_delegate_; + + // Contains all the plugin interfaces we've queried. The mapped value will + // be the pointer to the interface pointer supplied by the plugin if it's + // supported, or NULL if it's not supported. This allows us to cache failures + // and not req-query if a plugin doesn't support the interface. + typedef base::hash_map<std::string, const void*> InterfaceMap; + InterfaceMap plugin_interfaces_; + + typedef base::hash_map<PP_Instance, InstanceData> InstanceDataMap; + InstanceDataMap instance_map_; + + // The preferences sent from the host. We only want to set this once, which + // is what the received_preferences_ indicates. See OnMsgSetPreferences. + bool received_preferences_; + Preferences preferences_; + + uint32 plugin_dispatcher_id_; + + // Set to true when the instances associated with this dispatcher are + // incognito mode. + bool incognito_; + + // A filter for sending messages from threads other than the main thread. + scoped_refptr<IPC::SyncMessageFilter> sync_filter_; + + DISALLOW_COPY_AND_ASSIGN(PluginDispatcher); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_DISPATCHER_H_ diff --git a/chromium/ppapi/proxy/plugin_dispatcher_unittest.cc b/chromium/ppapi/proxy/plugin_dispatcher_unittest.cc new file mode 100644 index 00000000000..821ecad3799 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_dispatcher_unittest.cc @@ -0,0 +1,87 @@ +// 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 "base/memory/scoped_ptr.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" + +namespace ppapi { +namespace proxy { + +namespace { + +bool received_create = false; + +// Implement PPB_Audio since it's a relatively simple PPB interface and +// includes bidirectional communication. +PP_Resource Create(PP_Instance instance, PP_Resource config, + PPB_Audio_Callback audio_callback, void* user_data) { + received_create = true; + return 0; +} +PP_Bool IsAudio(PP_Resource resource) { + return PP_FALSE; +} +PP_Resource GetCurrentConfig(PP_Resource audio) { + return 0; +} +PP_Bool StartPlayback(PP_Resource audio) { + return PP_FALSE; +} +PP_Bool StopPlayback(PP_Resource audio) { + return PP_FALSE; +} + +PPB_Audio dummy_audio_interface = { + &Create, + &IsAudio, + &GetCurrentConfig, + &StartPlayback, + &StopPlayback +}; + +PPP_Instance dummy_ppp_instance_interface = {}; + +} // namespace + +class PluginDispatcherTest : public PluginProxyTest { + public: + PluginDispatcherTest() {} + + bool HasTargetProxy(ApiID id) { + return !!plugin_dispatcher()->proxies_[id].get(); + } +}; + +TEST_F(PluginDispatcherTest, SupportsInterface) { + RegisterTestInterface(PPB_AUDIO_INTERFACE, &dummy_audio_interface); + RegisterTestInterface(PPP_INSTANCE_INTERFACE, &dummy_ppp_instance_interface); + + // Sending a request for a random interface should fail. + EXPECT_FALSE(SupportsInterface("Random interface")); + + // Sending a request for a supported PPP interface should succeed. + EXPECT_TRUE(SupportsInterface(PPP_INSTANCE_INTERFACE)); +} + +TEST_F(PluginDispatcherTest, PPBCreation) { + // Sending a PPB message out of the blue should create a target proxy for + // that interface in the plugin. + EXPECT_FALSE(HasTargetProxy(API_ID_PPB_AUDIO)); + PpapiMsg_PPBAudio_NotifyAudioStreamCreated audio_msg( + API_ID_PPB_AUDIO, HostResource(), 0, + ppapi::proxy::SerializedHandle( + ppapi::proxy::SerializedHandle::SOCKET), + ppapi::proxy::SerializedHandle( + ppapi::proxy::SerializedHandle::SHARED_MEMORY)); + plugin_dispatcher()->OnMessageReceived(audio_msg); + EXPECT_TRUE(HasTargetProxy(API_ID_PPB_AUDIO)); +} + +} // namespace proxy +} // namespace ppapi + diff --git a/chromium/ppapi/proxy/plugin_globals.cc b/chromium/ppapi/proxy/plugin_globals.cc new file mode 100644 index 00000000000..07ac6885601 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_globals.cc @@ -0,0 +1,202 @@ +// 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 "ppapi/proxy/plugin_globals.h" + +#include "base/task_runner.h" +#include "base/threading/thread.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sender.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_proxy_delegate.h" +#include "ppapi/proxy/ppb_message_loop_proxy.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/thunk/enter.h" + +namespace ppapi { +namespace proxy { + +// It performs necessary locking/unlocking of the proxy lock, and forwards all +// messages to the underlying sender. +class PluginGlobals::BrowserSender : public IPC::Sender { + public: + // |underlying_sender| must outlive this object. + explicit BrowserSender(IPC::Sender* underlying_sender) + : underlying_sender_(underlying_sender) { + } + + virtual ~BrowserSender() {} + + // IPC::Sender implementation. + virtual bool Send(IPC::Message* msg) OVERRIDE { + if (msg->is_sync()) { + // Synchronous messages might be re-entrant, so we need to drop the lock. + ProxyAutoUnlock unlock; + return underlying_sender_->Send(msg); + } + + return underlying_sender_->Send(msg); + } + + private: + // Non-owning pointer. + IPC::Sender* underlying_sender_; + + DISALLOW_COPY_AND_ASSIGN(BrowserSender); +}; + +PluginGlobals* PluginGlobals::plugin_globals_ = NULL; + +PluginGlobals::PluginGlobals() + : ppapi::PpapiGlobals(), + plugin_proxy_delegate_(NULL), + callback_tracker_(new CallbackTracker) { + DCHECK(!plugin_globals_); + plugin_globals_ = this; + + // ResourceTracker asserts that we have the lock when we add new resources, + // so we lock when creating the MessageLoopResource even though there is no + // chance of race conditions. + ProxyAutoLock lock; + loop_for_main_thread_ = + new MessageLoopResource(MessageLoopResource::ForMainThread()); +} + +PluginGlobals::PluginGlobals(PerThreadForTest per_thread_for_test) + : ppapi::PpapiGlobals(per_thread_for_test), + plugin_proxy_delegate_(NULL), + callback_tracker_(new CallbackTracker) { + DCHECK(!plugin_globals_); +} + +PluginGlobals::~PluginGlobals() { + DCHECK(plugin_globals_ == this || !plugin_globals_); + { + ProxyAutoLock lock; + // Release the main-thread message loop. We should have the last reference + // count, so this will delete the MessageLoop resource. We do this before + // we clear plugin_globals_, because the Resource destructor tries to access + // this PluginGlobals. + DCHECK(!loop_for_main_thread_.get() || loop_for_main_thread_->HasOneRef()); + loop_for_main_thread_ = NULL; + } + plugin_globals_ = NULL; +} + +ResourceTracker* PluginGlobals::GetResourceTracker() { + return &plugin_resource_tracker_; +} + +VarTracker* PluginGlobals::GetVarTracker() { + return &plugin_var_tracker_; +} + +CallbackTracker* PluginGlobals::GetCallbackTrackerForInstance( + PP_Instance instance) { + // In the plugin process, the callback tracker is always the same, regardless + // of the instance. + return callback_tracker_.get(); +} + +thunk::PPB_Instance_API* PluginGlobals::GetInstanceAPI(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (dispatcher) + return dispatcher->GetInstanceAPI(); + return NULL; +} + +thunk::ResourceCreationAPI* PluginGlobals::GetResourceCreationAPI( + PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (dispatcher) + return dispatcher->GetResourceCreationAPI(); + return NULL; +} + +PP_Module PluginGlobals::GetModuleForInstance(PP_Instance instance) { + // Currently proxied plugins don't use the PP_Module for anything useful. + return 0; +} + +std::string PluginGlobals::GetCmdLine() { + return command_line_; +} + +void PluginGlobals::PreCacheFontForFlash(const void* logfontw) { + ProxyAutoUnlock unlock; + plugin_proxy_delegate_->PreCacheFont(logfontw); +} + +base::Lock* PluginGlobals::GetProxyLock() { + return &proxy_lock_; +} + +void PluginGlobals::LogWithSource(PP_Instance instance, + PP_LogLevel level, + const std::string& source, + const std::string& value) { + const std::string& fixed_up_source = source.empty() ? plugin_name_ : source; + PluginDispatcher::LogWithSource(instance, level, fixed_up_source, value); +} + +void PluginGlobals::BroadcastLogWithSource(PP_Module /* module */, + PP_LogLevel level, + const std::string& source, + const std::string& value) { + // Since we have only one module in a plugin process, broadcast is always + // the same as "send to everybody" which is what the dispatcher implements + // for the "instance = 0" case. + LogWithSource(0, level, source, value); +} + +MessageLoopShared* PluginGlobals::GetCurrentMessageLoop() { + return MessageLoopResource::GetCurrent(); +} + +base::TaskRunner* PluginGlobals::GetFileTaskRunner(PP_Instance instance) { + if (!file_thread_.get()) { + file_thread_.reset(new base::Thread("Plugin::File")); + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; + file_thread_->StartWithOptions(options); + } + return file_thread_->message_loop_proxy(); +} + +IPC::Sender* PluginGlobals::GetBrowserSender() { + if (!browser_sender_.get()) { + browser_sender_.reset( + new BrowserSender(plugin_proxy_delegate_->GetBrowserSender())); + } + + return browser_sender_.get(); +} + +std::string PluginGlobals::GetUILanguage() { + return plugin_proxy_delegate_->GetUILanguage(); +} + +void PluginGlobals::SetActiveURL(const std::string& url) { + plugin_proxy_delegate_->SetActiveURL(url); +} + +PP_Resource PluginGlobals::CreateBrowserFont( + Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const ppapi::Preferences& prefs) { + return plugin_proxy_delegate_->CreateBrowserFont( + connection, instance, desc, prefs); +} + +MessageLoopResource* PluginGlobals::loop_for_main_thread() { + return loop_for_main_thread_.get(); +} + +bool PluginGlobals::IsPluginGlobals() const { + return true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_globals.h b/chromium/ppapi/proxy/plugin_globals.h new file mode 100644 index 00000000000..044cac7e25c --- /dev/null +++ b/chromium/ppapi/proxy/plugin_globals.h @@ -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. + +#ifndef PPAPI_PROXY_PLUGIN_GLOBALS_H_ +#define PPAPI_PROXY_PLUGIN_GLOBALS_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_local_storage.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/callback_tracker.h" +#include "ppapi/shared_impl/ppapi_globals.h" + +namespace base { +class Thread; +} +namespace IPC { +class Sender; +} + +struct PP_BrowserFont_Trusted_Description; + +namespace ppapi { + +struct Preferences; + +namespace proxy { + +class MessageLoopResource; +class PluginProxyDelegate; + +class PPAPI_PROXY_EXPORT PluginGlobals : public PpapiGlobals { + public: + PluginGlobals(); + explicit PluginGlobals(PpapiGlobals::PerThreadForTest); + virtual ~PluginGlobals(); + + // Getter for the global singleton. Generally, you should use + // PpapiGlobals::Get() when possible. Use this only when you need some + // plugin-specific functionality. + inline static PluginGlobals* Get() { + // Explicitly crash if this is the wrong process type, we want to get + // crash reports. + CHECK(PpapiGlobals::Get()->IsPluginGlobals()); + return static_cast<PluginGlobals*>(PpapiGlobals::Get()); + } + + // PpapiGlobals implementation. + virtual ResourceTracker* GetResourceTracker() OVERRIDE; + virtual VarTracker* GetVarTracker() OVERRIDE; + virtual CallbackTracker* GetCallbackTrackerForInstance( + PP_Instance instance) OVERRIDE; + virtual thunk::PPB_Instance_API* GetInstanceAPI( + PP_Instance instance) OVERRIDE; + virtual 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 MessageLoopShared* GetCurrentMessageLoop() OVERRIDE; + base::TaskRunner* GetFileTaskRunner(PP_Instance instance) OVERRIDE; + + // Returns the channel for sending to the browser. + IPC::Sender* GetBrowserSender(); + + // Returns the language code of the current UI language. + std::string GetUILanguage(); + + // Sets the active url which is reported by breakpad. + void SetActiveURL(const std::string& url); + + PP_Resource CreateBrowserFont( + Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const Preferences& prefs); + + // Getters for the plugin-specific versions. + PluginResourceTracker* plugin_resource_tracker() { + return &plugin_resource_tracker_; + } + PluginVarTracker* plugin_var_tracker() { + return &plugin_var_tracker_; + } + + // The embedder should call set_proxy_delegate during startup. + void set_plugin_proxy_delegate(PluginProxyDelegate* d) { + plugin_proxy_delegate_ = d; + } + + // Returns the TLS slot that holds the message loop TLS. + // + // If we end up needing more TLS storage for more stuff, we should probably + // have a struct in here for the different items. + base::ThreadLocalStorage::Slot* msg_loop_slot() { + return msg_loop_slot_.get(); + } + + // Sets the message loop slot, takes ownership of the given heap-alloated + // pointer. + void set_msg_loop_slot(base::ThreadLocalStorage::Slot* slot) { + msg_loop_slot_.reset(slot); + } + + // Return the special Resource that represents the MessageLoop for the main + // thread. This Resource is not associated with any instance, and lives as + // long as the plugin. + MessageLoopResource* loop_for_main_thread(); + + // The embedder should call this function when the name of the plugin module + // is known. This will be used for error logging. + void set_plugin_name(const std::string& name) { plugin_name_ = name; } + + // The embedder should call this function when the command line is known. + void set_command_line(const std::string& c) { command_line_ = c; } + + private: + class BrowserSender; + + // PpapiGlobals overrides. + virtual bool IsPluginGlobals() const OVERRIDE; + + static PluginGlobals* plugin_globals_; + + PluginProxyDelegate* plugin_proxy_delegate_; + PluginResourceTracker plugin_resource_tracker_; + PluginVarTracker plugin_var_tracker_; + scoped_refptr<CallbackTracker> callback_tracker_; + + base::Lock proxy_lock_; + + scoped_ptr<base::ThreadLocalStorage::Slot> msg_loop_slot_; + // Note that loop_for_main_thread's constructor sets msg_loop_slot_, so it + // must be initialized after msg_loop_slot_ (hence the order here). + scoped_refptr<MessageLoopResource> loop_for_main_thread_; + + // Name of the plugin used for error logging. This will be empty until + // set_plugin_name is called. + std::string plugin_name_; + + // Command line for the plugin. This will be empty until set_command_line is + // called. + std::string command_line_; + + scoped_ptr<BrowserSender> browser_sender_; + + // Thread for performing potentially blocking file operations. It's created + // lazily, since it might not be needed. + scoped_ptr<base::Thread> file_thread_; + + DISALLOW_COPY_AND_ASSIGN(PluginGlobals); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_GLOBALS_H_ diff --git a/chromium/ppapi/proxy/plugin_main_nacl.cc b/chromium/ppapi/proxy/plugin_main_nacl.cc new file mode 100644 index 00000000000..5978233a537 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_main_nacl.cc @@ -0,0 +1,296 @@ +// 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 <map> +#include <set> + +#include "build/build_config.h" +// Need to include this before most other files because it defines +// IPC_MESSAGE_LOG_ENABLED. We need to use it to define +// IPC_MESSAGE_MACROS_LOG_ENABLED so ppapi_messages.h will generate the +// ViewMsgLog et al. functions. + +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "components/tracing/child_trace_message_filter.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_logging.h" +#include "ipc/ipc_message.h" +#include "native_client/src/shared/srpc/nacl_srpc.h" +#include "native_client/src/untrusted/irt/irt_ppapi.h" +#include "ppapi/c/ppp.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_proxy_delegate.h" +#include "ppapi/shared_impl/ppb_audio_shared.h" + +#if defined(IPC_MESSAGE_LOG_ENABLED) +#include "base/containers/hash_tables.h" + +LogFunctionMap g_log_function_mapping; + +#define IPC_MESSAGE_MACROS_LOG_ENABLED +#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \ + g_log_function_mapping[msg_id] = logger + +#endif +#include "ppapi/proxy/ppapi_messages.h" + +// This must match up with NACL_CHROME_INITIAL_IPC_DESC, +// defined in sel_main_chrome.h +#define NACL_IPC_FD 6 + +using ppapi::proxy::PluginDispatcher; +using ppapi::proxy::PluginGlobals; +using ppapi::proxy::PluginProxyDelegate; +using ppapi::proxy::ProxyChannel; +using ppapi::proxy::SerializedHandle; + +namespace { + +// This class manages communication between the plugin and the browser, and +// manages the PluginDispatcher instances for communication between the plugin +// and the renderer. +class PpapiDispatcher : public ProxyChannel, + public PluginDispatcher::PluginDelegate, + public PluginProxyDelegate { + public: + explicit PpapiDispatcher(scoped_refptr<base::MessageLoopProxy> io_loop); + + // PluginDispatcher::PluginDelegate implementation. + virtual base::MessageLoopProxy* GetIPCMessageLoop() OVERRIDE; + virtual base::WaitableEvent* GetShutdownEvent() OVERRIDE; + virtual IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId peer_pid, + bool should_close_source) OVERRIDE; + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() OVERRIDE; + virtual uint32 Register(PluginDispatcher* plugin_dispatcher) OVERRIDE; + virtual void Unregister(uint32 plugin_dispatcher_id) OVERRIDE; + + // PluginProxyDelegate implementation. + virtual IPC::Sender* GetBrowserSender() OVERRIDE; + virtual std::string GetUILanguage() OVERRIDE; + virtual void PreCacheFont(const void* logfontw) OVERRIDE; + virtual void SetActiveURL(const std::string& url) OVERRIDE; + virtual PP_Resource CreateBrowserFont( + ppapi::proxy::Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const ppapi::Preferences& prefs) OVERRIDE; + + // IPC::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + private: + void OnMsgCreateNaClChannel(int renderer_id, + const ppapi::PpapiNaClChannelArgs& args, + SerializedHandle handle); + void OnMsgResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg); + void OnPluginDispatcherMessageReceived(const IPC::Message& msg); + + std::set<PP_Instance> instances_; + std::map<uint32, PluginDispatcher*> plugin_dispatchers_; + uint32 next_plugin_dispatcher_id_; + scoped_refptr<base::MessageLoopProxy> message_loop_; + base::WaitableEvent shutdown_event_; +}; + +PpapiDispatcher::PpapiDispatcher(scoped_refptr<base::MessageLoopProxy> io_loop) + : next_plugin_dispatcher_id_(0), + message_loop_(io_loop), + shutdown_event_(true, false) { + IPC::ChannelHandle channel_handle( + "NaCl IPC", base::FileDescriptor(NACL_IPC_FD, false)); + // We don't have/need a PID since handle sharing happens outside of the + // NaCl sandbox. + InitWithChannel(this, base::kNullProcessId, channel_handle, + false); // Channel is server. + channel()->AddFilter( + new tracing::ChildTraceMessageFilter(message_loop_.get())); +} + +base::MessageLoopProxy* PpapiDispatcher::GetIPCMessageLoop() { + return message_loop_.get(); +} + +base::WaitableEvent* PpapiDispatcher::GetShutdownEvent() { + return &shutdown_event_; +} + +IPC::PlatformFileForTransit PpapiDispatcher::ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId peer_pid, + bool should_close_source) { + return IPC::InvalidPlatformFileForTransit(); +} + +std::set<PP_Instance>* PpapiDispatcher::GetGloballySeenInstanceIDSet() { + return &instances_; +} + +uint32 PpapiDispatcher::Register(PluginDispatcher* plugin_dispatcher) { + if (!plugin_dispatcher || + plugin_dispatchers_.size() >= std::numeric_limits<uint32>::max()) { + return 0; + } + + uint32 id = 0; + do { + // Although it is unlikely, make sure that we won't cause any trouble + // when the counter overflows. + id = next_plugin_dispatcher_id_++; + } while (id == 0 || + plugin_dispatchers_.find(id) != plugin_dispatchers_.end()); + plugin_dispatchers_[id] = plugin_dispatcher; + return id; +} + +void PpapiDispatcher::Unregister(uint32 plugin_dispatcher_id) { + plugin_dispatchers_.erase(plugin_dispatcher_id); +} + +IPC::Sender* PpapiDispatcher::GetBrowserSender() { + return this; +} + +std::string PpapiDispatcher::GetUILanguage() { + NOTIMPLEMENTED(); + return std::string(); +} + +void PpapiDispatcher::PreCacheFont(const void* logfontw) { + NOTIMPLEMENTED(); +} + +void PpapiDispatcher::SetActiveURL(const std::string& url) { + NOTIMPLEMENTED(); +} + +PP_Resource PpapiDispatcher::CreateBrowserFont( + ppapi::proxy::Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const ppapi::Preferences& prefs) { + NOTIMPLEMENTED(); + return 0; +} + +bool PpapiDispatcher::OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(PpapiDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_CreateNaClChannel, OnMsgCreateNaClChannel) + IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply, OnMsgResourceReply) + // All other messages are simply forwarded to a PluginDispatcher. + IPC_MESSAGE_UNHANDLED(OnPluginDispatcherMessageReceived(msg)) + IPC_END_MESSAGE_MAP() + return true; +} + +void PpapiDispatcher::OnMsgCreateNaClChannel( + int renderer_id, + const ppapi::PpapiNaClChannelArgs& args, + SerializedHandle handle) { + static bool command_line_and_logging_initialized = false; + if (!command_line_and_logging_initialized) { + CommandLine::Init(0, NULL); + for (size_t i = 0; i < args.switch_names.size(); ++i) { + DCHECK(i < args.switch_values.size()); + CommandLine::ForCurrentProcess()->AppendSwitchASCII( + args.switch_names[i], args.switch_values[i]); + } + logging::LoggingSettings settings; + settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; + logging::InitLogging(settings); + command_line_and_logging_initialized = true; + } + // Tell the process-global GetInterface which interfaces it can return to the + // plugin. + ppapi::proxy::InterfaceList::SetProcessGlobalPermissions( + args.permissions); + + PluginDispatcher* dispatcher = + new PluginDispatcher(::PPP_GetInterface, args.permissions, + args.off_the_record); + // The channel handle's true name is not revealed here. + IPC::ChannelHandle channel_handle("nacl", handle.descriptor()); + if (!dispatcher->InitPluginWithChannel(this, base::kNullProcessId, + channel_handle, false)) { + delete dispatcher; + return; + } + // From here, the dispatcher will manage its own lifetime according to the + // lifetime of the attached channel. +} + +void PpapiDispatcher::OnMsgResourceReply( + const ppapi::proxy::ResourceMessageReplyParams& reply_params, + const IPC::Message& nested_msg) { + ppapi::proxy::PluginDispatcher::DispatchResourceReply(reply_params, + nested_msg); +} + +void PpapiDispatcher::OnPluginDispatcherMessageReceived( + const IPC::Message& msg) { + // The first parameter should be a plugin dispatcher ID. + PickleIterator iter(msg); + uint32 id = 0; + if (!msg.ReadUInt32(&iter, &id)) { + NOTREACHED(); + return; + } + std::map<uint32, ppapi::proxy::PluginDispatcher*>::iterator dispatcher = + plugin_dispatchers_.find(id); + if (dispatcher != plugin_dispatchers_.end()) + dispatcher->second->OnMessageReceived(msg); +} + +} // namespace + +void PpapiPluginRegisterThreadCreator( + const struct PP_ThreadFunctions* thread_functions) { + // Initialize all classes that need to create threads that call back into + // user code. + ppapi::PPB_Audio_Shared::SetThreadFunctions(thread_functions); +} + +int PpapiPluginMain() { + // Though it isn't referenced here, we must instantiate an AtExitManager. + base::AtExitManager exit_manager; + base::MessageLoop loop; + IPC::Logging::set_log_function_map(&g_log_function_mapping); + ppapi::proxy::PluginGlobals plugin_globals; + base::Thread io_thread("Chrome_NaClIOThread"); + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; + io_thread.StartWithOptions(options); + + // Start up the SRPC server on another thread. Otherwise, when it blocks + // on an RPC, the PPAPI proxy will hang. Do this before we initialize the + // module and start the PPAPI proxy so that the NaCl plugin can continue + // loading the app. + static struct NaClSrpcHandlerDesc srpc_methods[] = { { NULL, NULL } }; + if (!NaClSrpcAcceptClientOnThread(srpc_methods)) { + return 1; + } + + int32_t error = ::PPP_InitializeModule( + 0 /* module */, + &ppapi::proxy::PluginDispatcher::GetBrowserInterface); + // TODO(dmichael): Handle other error conditions, like failure to connect? + if (error) + return error; + + PpapiDispatcher ppapi_dispatcher(io_thread.message_loop_proxy()); + plugin_globals.set_plugin_proxy_delegate(&ppapi_dispatcher); + + loop.Run(); + + return 0; +} diff --git a/chromium/ppapi/proxy/plugin_message_filter.cc b/chromium/ppapi/proxy/plugin_message_filter.cc new file mode 100644 index 00000000000..9f178f15acc --- /dev/null +++ b/chromium/ppapi/proxy/plugin_message_filter.cc @@ -0,0 +1,61 @@ +// 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 "ppapi/proxy/plugin_message_filter.h" + +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +PluginMessageFilter::PluginMessageFilter( + std::set<PP_Instance>* seen_instance_ids) + : seen_instance_ids_(seen_instance_ids), + channel_(NULL) { +} + +PluginMessageFilter::~PluginMessageFilter() { +} + +void PluginMessageFilter::OnFilterAdded(IPC::Channel* channel) { + channel_ = channel; +} + +void PluginMessageFilter::OnFilterRemoved() { + channel_ = NULL; +} + +bool PluginMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginMessageFilter, message) + IPC_MESSAGE_HANDLER(PpapiMsg_ReserveInstanceId, OnMsgReserveInstanceId) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool PluginMessageFilter::Send(IPC::Message* msg) { + if (channel_) + return channel_->Send(msg); + delete msg; + return false; +} + +void PluginMessageFilter::OnMsgReserveInstanceId(PP_Instance instance, + bool* usable) { + // See the message definition for how this works. + if (seen_instance_ids_->find(instance) != seen_instance_ids_->end()) { + // Instance ID already seen, reject it. + *usable = false; + return; + } + + // This instance ID is new so we can return that it's usable and mark it as + // used for future reference. + seen_instance_ids_->insert(instance); + *usable = true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_message_filter.h b/chromium/ppapi/proxy/plugin_message_filter.h new file mode 100644 index 00000000000..5701a96a09a --- /dev/null +++ b/chromium/ppapi/proxy/plugin_message_filter.h @@ -0,0 +1,57 @@ +// 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 PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ +#define PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ + +#include <set> + +#include "base/compiler_specific.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_sender.h" +#include "ppapi/c/pp_instance.h" + +namespace ppapi { +namespace proxy { + +// Listens for messages on the I/O thread of the plugin and handles some of +// them to avoid needing to block on the plugin. +// +// There is one instance of this class for each renderer channel (same as for +// the PluginDispatchers). +class PluginMessageFilter : public IPC::ChannelProxy::MessageFilter, + public IPC::Sender { + public: + // The input is a pointer to a set that will be used to uniquify PP_Instances + // across all renderer channels. The same pointer should be passed to each + // MessageFilter to ensure uniqueness, and the value should outlive this + // class. + PluginMessageFilter(std::set<PP_Instance>* seen_instance_ids); + virtual ~PluginMessageFilter(); + + // MessageFilter implementation. + virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE; + virtual void OnFilterRemoved() OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // IPC::Sender implementation. + virtual bool Send(IPC::Message* msg) OVERRIDE; + + private: + void OnMsgReserveInstanceId(PP_Instance instance, bool* usable); + + // All instance IDs every queried by any renderer on this plugin. This is + // used to make sure that new instance IDs are unique. This is a non-owning + // pointer, it will be managed by the later that creates this class. + std::set<PP_Instance>* seen_instance_ids_; + + // The IPC channel to the renderer. May be NULL if we're not currently + // attached as a filter. + IPC::Channel* channel_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ diff --git a/chromium/ppapi/proxy/plugin_proxy_delegate.h b/chromium/ppapi/proxy/plugin_proxy_delegate.h new file mode 100644 index 00000000000..438ac6c871e --- /dev/null +++ b/chromium/ppapi/proxy/plugin_proxy_delegate.h @@ -0,0 +1,50 @@ +// 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_PROXY_PLUGIN_PROXY_DELEGATE_H_ +#define PPAPI_PROXY_PLUGIN_PROXY_DELEGATE_H_ + +#include <string> + +namespace IPC { +class Sender; +} + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT PluginProxyDelegate { + public: + virtual ~PluginProxyDelegate() {} + + // Returns the channel for sending to the browser. + // Note: The returned sender must be thread-safe. It might be used while the + // proxy lock is not acquired. Please see the implementation of + // PluginGlobals::BrowserSender. + virtual IPC::Sender* GetBrowserSender() = 0; + + // Returns the language code of the current UI language. + virtual std::string GetUILanguage() = 0; + + // Performs Windows-specific font caching in the browser for the given + // LOGFONTW. Does nothing on non-Windows platforms. + // Note: This method must be thread-safe. + virtual void PreCacheFont(const void* logfontw) = 0; + + // Sets the active url which is reported by breakpad. + virtual void SetActiveURL(const std::string& url) = 0; + + // Validates the font description, and uses it to create a + // BrowserFontResource_Trusted resource. + virtual PP_Resource CreateBrowserFont( + Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const Preferences& prefs) = 0; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_PROXY_DELEGATE_H_ diff --git a/chromium/ppapi/proxy/plugin_resource.cc b/chromium/ppapi/proxy/plugin_resource.cc new file mode 100644 index 00000000000..c450f3c29af --- /dev/null +++ b/chromium/ppapi/proxy/plugin_resource.cc @@ -0,0 +1,160 @@ +// 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 "ppapi/proxy/plugin_resource.h" + +#include <limits> + +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +PluginResource::PluginResource(Connection connection, PP_Instance instance) + : Resource(OBJECT_IS_PROXY, instance), + connection_(connection), + next_sequence_number_(1), + sent_create_to_browser_(false), + sent_create_to_renderer_(false) { +} + +PluginResource::~PluginResource() { + if (sent_create_to_browser_) { + connection_.browser_sender->Send( + new PpapiHostMsg_ResourceDestroyed(pp_resource())); + } + if (sent_create_to_renderer_) { + connection_.renderer_sender->Send( + new PpapiHostMsg_ResourceDestroyed(pp_resource())); + } +} + +void PluginResource::OnReplyReceived( + const proxy::ResourceMessageReplyParams& params, + const IPC::Message& msg) { + TRACE_EVENT2("ppapi proxy", "PluginResource::OnReplyReceived", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + // Grab the callback for the reply sequence number and run it with |msg|. + CallbackMap::iterator it = callbacks_.find(params.sequence()); + if (it == callbacks_.end()) { + DCHECK(false) << "Callback does not exist for an expected sequence number."; + } else { + scoped_refptr<PluginResourceCallbackBase> callback = it->second; + callbacks_.erase(it); + callback->Run(params, msg); + } +} + +void PluginResource::NotifyLastPluginRefWasDeleted() { + Resource::NotifyLastPluginRefWasDeleted(); + + // The callbacks may hold referrences to this object. Normally, we will get + // reply messages from the host side and remove them. However, it is possible + // that some replies from the host never arrive, e.g., the corresponding + // renderer crashes. In that case, we have to clean up the callbacks, + // otherwise this object will live forever. + callbacks_.clear(); +} + +void PluginResource::NotifyInstanceWasDeleted() { + Resource::NotifyInstanceWasDeleted(); + + // Please see comments in NotifyLastPluginRefWasDeleted() about why we must + // clean up the callbacks. + // It is possible that NotifyLastPluginRefWasDeleted() is never called for a + // resource. For example, those singleton-style resources such as + // GamepadResource never expose references to the plugin and thus won't + // receive a NotifyLastPluginRefWasDeleted() call. For those resources, we + // need to clean up callbacks when the instance goes away. + callbacks_.clear(); +} + +void PluginResource::SendCreate(Destination dest, const IPC::Message& msg) { + TRACE_EVENT2("ppapi proxy", "PluginResource::SendCreate", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + if (dest == RENDERER) { + DCHECK(!sent_create_to_renderer_); + sent_create_to_renderer_ = true; + } else { + DCHECK(!sent_create_to_browser_); + sent_create_to_browser_ = true; + } + ResourceMessageCallParams params(pp_resource(), GetNextSequence()); + GetSender(dest)->Send( + new PpapiHostMsg_ResourceCreated(params, pp_instance(), msg)); +} + +void PluginResource::AttachToPendingHost(Destination dest, + int pending_host_id) { + // Connecting to a pending host is a replacement for "create". + if (dest == RENDERER) { + DCHECK(!sent_create_to_renderer_); + sent_create_to_renderer_ = true; + } else { + DCHECK(!sent_create_to_browser_); + sent_create_to_browser_ = true; + } + GetSender(dest)->Send( + new PpapiHostMsg_AttachToPendingHost(pp_resource(), pending_host_id)); +} + +void PluginResource::Post(Destination dest, const IPC::Message& msg) { + TRACE_EVENT2("ppapi proxy", "PluginResource::Post", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + ResourceMessageCallParams params(pp_resource(), GetNextSequence()); + SendResourceCall(dest, params, msg); +} + +bool PluginResource::SendResourceCall( + Destination dest, + const ResourceMessageCallParams& call_params, + const IPC::Message& nested_msg) { + // For in-process plugins, we need to send the routing ID with the request. + // The browser then uses that routing ID when sending the reply so it will be + // routed back to the correct RenderViewImpl. + if (dest == BROWSER && connection_.in_process) { + return GetSender(dest)->Send(new PpapiHostMsg_InProcessResourceCall( + connection_.browser_sender_routing_id, + call_params, + nested_msg)); + } else { + return GetSender(dest)->Send( + new PpapiHostMsg_ResourceCall(call_params, nested_msg)); + } +} + +int32_t PluginResource::GenericSyncCall( + Destination dest, + const IPC::Message& msg, + IPC::Message* reply, + ResourceMessageReplyParams* reply_params) { + TRACE_EVENT2("ppapi proxy", "PluginResource::GenericSyncCall", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + ResourceMessageCallParams params(pp_resource(), GetNextSequence()); + params.set_has_callback(); + bool success = GetSender(dest)->Send(new PpapiHostMsg_ResourceSyncCall( + params, msg, reply_params, reply)); + if (success) + return reply_params->result(); + return PP_ERROR_FAILED; +} + +int32_t PluginResource::GetNextSequence() { + // Return the value with wraparound, making sure we don't make a sequence + // number with a 0 ID. Note that signed wraparound is undefined in C++ so we + // manually check. + int32_t ret = next_sequence_number_; + if (next_sequence_number_ == std::numeric_limits<int32_t>::max()) + next_sequence_number_ = 1; // Skip 0 which is invalid. + else + next_sequence_number_++; + return ret; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_resource.h b/chromium/ppapi/proxy/plugin_resource.h new file mode 100644 index 00000000000..9448326d55c --- /dev/null +++ b/chromium/ppapi/proxy/plugin_resource.h @@ -0,0 +1,253 @@ +// 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_PROXY_PLUGIN_RESOURCE_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sender.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource_callback.h" +#include "ppapi/proxy/ppapi_message_utils.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/resource.h" + +namespace ppapi { +namespace proxy { + +class PluginDispatcher; + +class PPAPI_PROXY_EXPORT PluginResource : public Resource { + public: + enum Destination { + RENDERER = 0, + BROWSER = 1 + }; + + PluginResource(Connection connection, PP_Instance instance); + virtual ~PluginResource(); + + // Returns true if we've previously sent a create message to the browser + // or renderer. Generally resources will use these to tell if they should + // lazily send create messages. + bool sent_create_to_browser() const { return sent_create_to_browser_; } + bool sent_create_to_renderer() const { return sent_create_to_renderer_; } + + // This handles a reply to a resource call. It works by looking up the + // callback that was registered when CallBrowser/CallRenderer was called + // and calling it with |params| and |msg|. + virtual void OnReplyReceived(const proxy::ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + // Resource overrides. + // Note: Subclasses shouldn't override these methods directly. Instead, they + // should implement LastPluginRefWasDeleted() or InstanceWasDeleted() to get + // notified. + virtual void NotifyLastPluginRefWasDeleted() OVERRIDE; + virtual void NotifyInstanceWasDeleted() OVERRIDE; + + + // Sends a create message to the browser or renderer for the current resource. + void SendCreate(Destination dest, const IPC::Message& msg); + + // When the host returnes a resource to the plugin, it will create a pending + // ResourceHost and send an ID back to the plugin that identifies the pending + // object. The plugin uses this function to connect the plugin resource with + // the pending host resource. See also PpapiHostMsg_AttachToPendingHost. This + // is in lieu of sending a create message. + void AttachToPendingHost(Destination dest, int pending_host_id); + + // Sends the given IPC message as a resource request to the host + // corresponding to this resource object and does not expect a reply. + void Post(Destination dest, const IPC::Message& msg); + + // Like Post() but expects a response. |callback| is a |base::Callback| that + // will be run when a reply message with a sequence number matching that of + // the call is received. |ReplyMsgClass| is the type of the reply message that + // is expected. An example of usage: + // + // Call<PpapiPluginMsg_MyResourceType_MyReplyMessage>( + // BROWSER, + // PpapiHostMsg_MyResourceType_MyRequestMessage(), + // base::Bind(&MyPluginResource::ReplyHandler, base::Unretained(this))); + // + // If a reply message to this call is received whose type does not match + // |ReplyMsgClass| (for example, in the case of an error), the callback will + // still be invoked but with the default values of the message parameters. + // + // Returns the new request's sequence number which can be used to identify + // the callback. This value will never be 0, which you can use to identify + // an invalid callback. + // + // Note: 1) When all plugin references to this resource are gone or the + // corresponding plugin instance is deleted, all pending callbacks + // are abandoned. + // 2) It is *not* recommended to let |callback| hold any reference to + // |this|, in which it will be stored. Otherwise, this object will + // live forever if we fail to clean up the callback. It is safe to + // use base::Unretained(this) or a weak pointer, because this object + // will outlive the callback. + template<typename ReplyMsgClass, typename CallbackType> + int32_t Call(Destination dest, + const IPC::Message& msg, + const CallbackType& callback); + + // Calls the browser/renderer with sync messages. Returns the pepper error + // code from the call. + // |ReplyMsgClass| is the type of the reply message that is expected. If it + // carries x parameters, then the method with x out parameters should be used. + // An example of usage: + // + // // Assuming the reply message carries a string and an integer. + // std::string param_1; + // int param_2 = 0; + // int32_t result = SyncCall<PpapiPluginMsg_MyResourceType_MyReplyMessage>( + // RENDERER, PpapiHostMsg_MyResourceType_MyRequestMessage(), + // ¶m_1, ¶m_2); + template <class ReplyMsgClass> + int32_t SyncCall(Destination dest, const IPC::Message& msg); + template <class ReplyMsgClass, class A> + int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a); + template <class ReplyMsgClass, class A, class B> + int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b); + template <class ReplyMsgClass, class A, class B, class C> + int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b, C* c); + template <class ReplyMsgClass, class A, class B, class C, class D> + int32_t SyncCall( + Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d); + template <class ReplyMsgClass, class A, class B, class C, class D, class E> + int32_t SyncCall( + Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e); + + int32_t GenericSyncCall(Destination dest, + const IPC::Message& msg, + IPC::Message* reply_msg, + ResourceMessageReplyParams* reply_params); + + const Connection& connection() { return connection_; } + + private: + IPC::Sender* GetSender(Destination dest) { + return dest == RENDERER ? connection_.renderer_sender : + connection_.browser_sender; + } + + // Helper function to send a |PpapiHostMsg_ResourceCall| to the given + // destination with |nested_msg| and |call_params|. + bool SendResourceCall(Destination dest, + const ResourceMessageCallParams& call_params, + const IPC::Message& nested_msg); + + int32_t GetNextSequence(); + + Connection connection_; + + // Use GetNextSequence to retrieve the next value. + int32_t next_sequence_number_; + + bool sent_create_to_browser_; + bool sent_create_to_renderer_; + + typedef std::map<int32_t, scoped_refptr<PluginResourceCallbackBase> > + CallbackMap; + CallbackMap callbacks_; + + DISALLOW_COPY_AND_ASSIGN(PluginResource); +}; + +template<typename ReplyMsgClass, typename CallbackType> +int32_t PluginResource::Call(Destination dest, + const IPC::Message& msg, + const CallbackType& callback) { + TRACE_EVENT2("ppapi proxy", "PluginResource::Call", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + ResourceMessageCallParams params(pp_resource(), next_sequence_number_++); + // Stash the |callback| in |callbacks_| identified by the sequence number of + // the call. + scoped_refptr<PluginResourceCallbackBase> plugin_callback( + new PluginResourceCallback<ReplyMsgClass, CallbackType>(callback)); + callbacks_.insert(std::make_pair(params.sequence(), plugin_callback)); + params.set_has_callback(); + SendResourceCall(dest, params, msg); + return params.sequence(); +} + +template <class ReplyMsgClass> +int32_t PluginResource::SyncCall(Destination dest, const IPC::Message& msg) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + return GenericSyncCall(dest, msg, &reply, &reply_params); +} + +template <class ReplyMsgClass, class A> +int32_t PluginResource::SyncCall( + Destination dest, const IPC::Message& msg, A* a) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); + + if (UnpackMessage<ReplyMsgClass>(reply, a)) + return result; + return PP_ERROR_FAILED; +} + +template <class ReplyMsgClass, class A, class B> +int32_t PluginResource::SyncCall( + Destination dest, const IPC::Message& msg, A* a, B* b) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); + + if (UnpackMessage<ReplyMsgClass>(reply, a, b)) + return result; + return PP_ERROR_FAILED; +} + +template <class ReplyMsgClass, class A, class B, class C> +int32_t PluginResource::SyncCall( + Destination dest, const IPC::Message& msg, A* a, B* b, C* c) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); + + if (UnpackMessage<ReplyMsgClass>(reply, a, b, c)) + return result; + return PP_ERROR_FAILED; +} + +template <class ReplyMsgClass, class A, class B, class C, class D> +int32_t PluginResource::SyncCall( + Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); + + if (UnpackMessage<ReplyMsgClass>(reply, a, b, c, d)) + return result; + return PP_ERROR_FAILED; +} + +template <class ReplyMsgClass, class A, class B, class C, class D, class E> +int32_t PluginResource::SyncCall( + Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e) { + IPC::Message reply; + ResourceMessageReplyParams reply_params; + int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); + + if (UnpackMessage<ReplyMsgClass>(reply, a, b, c, d, e)) + return result; + return PP_ERROR_FAILED; +} + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/plugin_resource_callback.h b/chromium/ppapi/proxy/plugin_resource_callback.h new file mode 100644 index 00000000000..a306c26a1c7 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_resource_callback.h @@ -0,0 +1,52 @@ +// 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_PROXY_PLUGIN_RESOURCE_CALLBACK_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_CALLBACK_H_ + +#include "base/memory/ref_counted.h" +#include "ipc/ipc_message.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/resource_message_params.h" + +namespace ppapi { +namespace proxy { + +// |PluginResourceCallback| wraps a |base::Callback| on the plugin side which +// will be triggered in response to a particular message type being received. +// |MsgClass| is the reply message type that the callback will be called with +// and |CallbackType| is the type of the |base::Callback| that will be called. +class PluginResourceCallbackBase + : public base::RefCounted<PluginResourceCallbackBase> { + public: + virtual void Run(const ResourceMessageReplyParams& params, + const IPC::Message& msg) = 0; + protected: + friend class base::RefCounted<PluginResourceCallbackBase>; + virtual ~PluginResourceCallbackBase() {} +}; + +template<typename MsgClass, typename CallbackType> +class PluginResourceCallback : public PluginResourceCallbackBase { + public: + explicit PluginResourceCallback(const CallbackType& callback) + : callback_(callback) {} + + virtual void Run( + const ResourceMessageReplyParams& reply_params, + const IPC::Message& msg) OVERRIDE { + DispatchResourceReplyOrDefaultParams<MsgClass>( + &callback_, &CallbackType::Run, reply_params, msg); + } + + private: + virtual ~PluginResourceCallback() {} + + CallbackType callback_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_CALLBACK_H_ diff --git a/chromium/ppapi/proxy/plugin_resource_tracker.cc b/chromium/ppapi/proxy/plugin_resource_tracker.cc new file mode 100644 index 00000000000..86cbf7cee43 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_resource_tracker.cc @@ -0,0 +1,72 @@ +// 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 "ppapi/proxy/plugin_resource_tracker.h" + +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +PluginResourceTracker::PluginResourceTracker() : ResourceTracker(THREAD_SAFE) { + UseOddResourceValueInDebugMode(); +} + +PluginResourceTracker::~PluginResourceTracker() { +} + +PP_Resource PluginResourceTracker::PluginResourceForHostResource( + const HostResource& resource) const { + HostResourceMap::const_iterator found = host_resource_map_.find(resource); + if (found == host_resource_map_.end()) + return 0; + return found->second; +} + +PP_Resource PluginResourceTracker::AddResource(Resource* object) { + // If there's a HostResource, it must not be added twice. + DCHECK(!object->host_resource().host_resource() || + (host_resource_map_.find(object->host_resource()) == + host_resource_map_.end())); + + PP_Resource ret = ResourceTracker::AddResource(object); + + // Some resources are plugin-only, so they don't have a host resource. + if (object->host_resource().host_resource()) + host_resource_map_.insert(std::make_pair(object->host_resource(), ret)); + return ret; +} + +void PluginResourceTracker::RemoveResource(Resource* object) { + ResourceTracker::RemoveResource(object); + + if (!object->host_resource().is_null()) { + // The host_resource will be NULL for proxy-only resources, which we + // obviously don't need to tell the host about. + DCHECK(host_resource_map_.find(object->host_resource()) != + host_resource_map_.end()); + host_resource_map_.erase(object->host_resource()); + + PluginDispatcher* dispatcher = + PluginDispatcher::GetForInstance(object->pp_instance()); + if (dispatcher) { + // The dispatcher can be NULL if the plugin held on to a resource after + // the instance was destroyed. In that case the browser-side resource has + // already been freed correctly on the browser side. + dispatcher->Send(new PpapiHostMsg_PPBCore_ReleaseResource( + API_ID_PPB_CORE, object->host_resource())); + } + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_resource_tracker.h b/chromium/ppapi/proxy/plugin_resource_tracker.h new file mode 100644 index 00000000000..6bed72f4eff --- /dev/null +++ b/chromium/ppapi/proxy/plugin_resource_tracker.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 PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ + +#include <map> +#include <utility> + +#include "base/compiler_specific.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/resource_tracker.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace ppapi { + +namespace proxy { + +class PPAPI_PROXY_EXPORT PluginResourceTracker : public ResourceTracker { + public: + PluginResourceTracker(); + virtual ~PluginResourceTracker(); + + // Given a host resource, maps it to an existing plugin resource ID if it + // exists, or returns 0 on failure. + PP_Resource PluginResourceForHostResource( + const HostResource& resource) const; + + protected: + // ResourceTracker overrides. + virtual PP_Resource AddResource(Resource* object) OVERRIDE; + virtual void RemoveResource(Resource* object) OVERRIDE; + + private: + // Map of host instance/resource pairs to a plugin resource ID. + typedef std::map<HostResource, PP_Resource> HostResourceMap; + HostResourceMap host_resource_map_; + + DISALLOW_COPY_AND_ASSIGN(PluginResourceTracker); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ diff --git a/chromium/ppapi/proxy/plugin_resource_tracker_unittest.cc b/chromium/ppapi/proxy/plugin_resource_tracker_unittest.cc new file mode 100644 index 00000000000..8623f649de3 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_resource_tracker_unittest.cc @@ -0,0 +1,71 @@ +// 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 "base/memory/scoped_ptr.h" +#include "base/process/process.h" +#include "ppapi/proxy/mock_resource.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// Object so we know when a resource has been released. +class TrackedMockResource : public MockResource { + public: + TrackedMockResource(const HostResource& serialized) + : MockResource(serialized) { + tracked_alive_count++; + } + ~TrackedMockResource() { + tracked_alive_count--; + } + + static int tracked_alive_count; +}; + +int TrackedMockResource::tracked_alive_count = 0; + +} // namespace + +class PluginResourceTrackerTest : public PluginProxyTest { + public: + PluginResourceTrackerTest() {} + ~PluginResourceTrackerTest() {} +}; + +TEST_F(PluginResourceTrackerTest, PluginResourceForHostResource) { + ProxyAutoLock lock; + + PP_Resource host_resource = 0x5678; + + HostResource serialized; + serialized.SetHostResource(pp_instance(), host_resource); + + // When we haven't added an object, the return value should be 0. + EXPECT_EQ(0, resource_tracker().PluginResourceForHostResource(serialized)); + + EXPECT_EQ(0, TrackedMockResource::tracked_alive_count); + TrackedMockResource* object = new TrackedMockResource(serialized); + EXPECT_EQ(1, TrackedMockResource::tracked_alive_count); + PP_Resource plugin_resource = object->GetReference(); + + // Now that the object has been added, the return value should be the plugin + // resource ID we already got. + EXPECT_EQ(plugin_resource, + resource_tracker().PluginResourceForHostResource(serialized)); + + // Releasing the resource should have freed it. + resource_tracker().ReleaseResource(plugin_resource); + EXPECT_EQ(0, TrackedMockResource::tracked_alive_count); + EXPECT_EQ(0, resource_tracker().PluginResourceForHostResource(serialized)); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_var_serialization_rules.cc b/chromium/ppapi/proxy/plugin_var_serialization_rules.cc new file mode 100644 index 00000000000..f772554b4ac --- /dev/null +++ b/chromium/ppapi/proxy/plugin_var_serialization_rules.cc @@ -0,0 +1,120 @@ +// 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 "ppapi/proxy/plugin_var_serialization_rules.h" + +#include "base/logging.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +PluginVarSerializationRules::PluginVarSerializationRules( + const base::WeakPtr<PluginDispatcher>& dispatcher) + : var_tracker_(PluginGlobals::Get()->plugin_var_tracker()), + dispatcher_(dispatcher) { +} + +PluginVarSerializationRules::~PluginVarSerializationRules() { +} + +PP_Var PluginVarSerializationRules::SendCallerOwned(const PP_Var& var) { + // Objects need special translations to get the IDs valid in the host. + if (var.type == PP_VARTYPE_OBJECT) + return var_tracker_->GetHostObject(var); + return var; +} + +PP_Var PluginVarSerializationRules::BeginReceiveCallerOwned(const PP_Var& var) { + if (var.type == PP_VARTYPE_OBJECT) { + return dispatcher_.get() ? var_tracker_->TrackObjectWithNoReference( + var, dispatcher_.get()) + : PP_MakeUndefined(); + } + + return var; +} + +void PluginVarSerializationRules::EndReceiveCallerOwned(const PP_Var& var) { + if (var.type == PP_VARTYPE_OBJECT) { + var_tracker_->StopTrackingObjectWithNoReference(var); + } else if (var.type >= PP_VARTYPE_STRING) { + // Release our reference to the local Var. + var_tracker_->ReleaseVar(var); + } +} + +PP_Var PluginVarSerializationRules::ReceivePassRef(const PP_Var& var) { + // Overview of sending an object with "pass ref" from the browser to the + // plugin: + // Example 1 Example 2 + // Plugin Browser Plugin Browser + // Before send 3 2 0 1 + // Browser calls BeginSendPassRef 3 2 0 1 + // Plugin calls ReceivePassRef 4 1 1 1 + // Browser calls EndSendPassRef 4 1 1 1 + // + // In example 1 before the send, the plugin has 3 refs which are represented + // as one ref in the browser (since the plugin only tells the browser when + // it's refcount goes from 1 -> 0). The initial state is that the browser + // plugin code started to return a value, which means it gets another ref + // on behalf of the caller. This needs to be transferred to the plugin and + // folded in to its set of refs it maintains (with one ref representing all + // of them in the browser). + if (var.type == PP_VARTYPE_OBJECT) { + return dispatcher_.get() + ? var_tracker_->ReceiveObjectPassRef(var, dispatcher_.get()) + : PP_MakeUndefined(); + } + + // Other types are unchanged. + return var; +} + +PP_Var PluginVarSerializationRules::BeginSendPassRef(const PP_Var& var) { + // Overview of sending an object with "pass ref" from the plugin to the + // browser: + // Example 1 Example 2 + // Plugin Browser Plugin Browser + // Before send 3 1 1 1 + // Plugin calls BeginSendPassRef 3 1 1 1 + // Browser calls ReceivePassRef 3 2 1 2 + // Plugin calls EndSendPassRef 2 2 0 1 + // + // The plugin maintains one ref count in the browser on behalf of the + // entire ref count in the plugin. When the plugin refcount goes to 0, it + // will call the browser to deref the object. This is why in example 2 + // transferring the object ref to the browser involves no net change in the + // browser's refcount. + + // Objects need special translations to get the IDs valid in the host. + if (var.type == PP_VARTYPE_OBJECT) + return var_tracker_->GetHostObject(var); + return var; +} + +void PluginVarSerializationRules::EndSendPassRef(const PP_Var& var) { + // See BeginSendPassRef for an example of why we release our ref here. + // The var we have in our inner class has been converted to a host object + // by BeginSendPassRef. This means it's not a normal var valid in the plugin, + // so we need to use the special ReleaseHostObject. + if (var.type == PP_VARTYPE_OBJECT) { + if (dispatcher_.get()) + var_tracker_->ReleaseHostObject(dispatcher_.get(), var); + } else if (var.type >= PP_VARTYPE_STRING) { + var_tracker_->ReleaseVar(var); + } +} + +void PluginVarSerializationRules::ReleaseObjectRef(const PP_Var& var) { + var_tracker_->ReleaseVar(var); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_var_serialization_rules.h b/chromium/ppapi/proxy/plugin_var_serialization_rules.h new file mode 100644 index 00000000000..1616a755220 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_var_serialization_rules.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 PPAPI_PROXY_PLUGIN_VAR_SERIALIZATION_RULES_H_ +#define PPAPI_PROXY_PLUGIN_VAR_SERIALIZATION_RULES_H_ + +#include "base/basictypes.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace ppapi { +namespace proxy { + +class PluginDispatcher; +class PluginVarTracker; + +// Implementation of the VarSerializationRules interface for the plugin. +class PluginVarSerializationRules : public VarSerializationRules { + public: + // This class will use the given non-owning pointer to the var tracker to + // handle object refcounting and string conversion. + explicit PluginVarSerializationRules( + const base::WeakPtr<PluginDispatcher>& dispatcher); + ~PluginVarSerializationRules(); + + // VarSerialization implementation. + virtual PP_Var SendCallerOwned(const PP_Var& var); + virtual PP_Var BeginReceiveCallerOwned(const PP_Var& var); + virtual void EndReceiveCallerOwned(const PP_Var& var); + virtual PP_Var ReceivePassRef(const PP_Var& var); + virtual PP_Var BeginSendPassRef(const PP_Var& var); + virtual void EndSendPassRef(const PP_Var& var); + virtual void ReleaseObjectRef(const PP_Var& var); + + private: + PluginVarTracker* var_tracker_; + + // In most cases, |dispatcher_| won't be NULL, but you should always check + // before using it. + // One scenario that it becomes NULL: A SerializedVar holds a ref to this + // object, and a sync message is issued. While waiting for the reply to the + // sync message, some incoming message causes the dispatcher to be destroyed. + // If that happens, we may leak references to object vars. Considering that + // scripting has been deprecated, this may not be a big issue. + base::WeakPtr<PluginDispatcher> dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(PluginVarSerializationRules); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_VAR_SERIALIZATION_RULES_H_ diff --git a/chromium/ppapi/proxy/plugin_var_tracker.cc b/chromium/ppapi/proxy/plugin_var_tracker.cc new file mode 100644 index 00000000000..ee299852514 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_var_tracker.cc @@ -0,0 +1,410 @@ +// 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 "ppapi/proxy/plugin_var_tracker.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/singleton.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/plugin_array_buffer_var.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/proxy_object_var.h" +#include "ppapi/shared_impl/api_id.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, int32 i) + : dispatcher(d), + host_object_id(i) { +} + +bool PluginVarTracker::HostVar::operator<(const HostVar& other) const { + if (dispatcher < other.dispatcher) + return true; + if (other.dispatcher < dispatcher) + return false; + return host_object_id < other.host_object_id; +} + +PluginVarTracker::PluginVarTracker() : VarTracker(THREAD_SAFE) { +} + +PluginVarTracker::~PluginVarTracker() { +} + +PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& host_var, + PluginDispatcher* dispatcher) { + CheckThreadingPreconditions(); + DCHECK(host_var.type == PP_VARTYPE_OBJECT); + + // Get the object. + scoped_refptr<ProxyObjectVar> object( + FindOrMakePluginVarFromHostVar(host_var, dispatcher)); + + // Actually create the PP_Var, this will add all the tracking info but not + // adjust any refcounts. + PP_Var ret = GetOrCreateObjectVarID(object.get()); + + VarInfo& info = GetLiveVar(ret)->second; + if (info.ref_count > 0) { + // We already had a reference to it before. That means the renderer now has + // two references on our behalf. We want to transfer that extra reference + // to our list. This means we addref in the plugin, and release the extra + // one in the renderer. + SendReleaseObjectMsg(*object.get()); + } + info.ref_count++; + return ret; +} + +PP_Var PluginVarTracker::TrackObjectWithNoReference( + const PP_Var& host_var, + PluginDispatcher* dispatcher) { + CheckThreadingPreconditions(); + DCHECK(host_var.type == PP_VARTYPE_OBJECT); + + // Get the object. + scoped_refptr<ProxyObjectVar> object( + FindOrMakePluginVarFromHostVar(host_var, dispatcher)); + + // Actually create the PP_Var, this will add all the tracking info but not + // adjust any refcounts. + PP_Var ret = GetOrCreateObjectVarID(object.get()); + + VarInfo& info = GetLiveVar(ret)->second; + info.track_with_no_reference_count++; + return ret; +} + +void PluginVarTracker::StopTrackingObjectWithNoReference( + const PP_Var& plugin_var) { + CheckThreadingPreconditions(); + DCHECK(plugin_var.type == PP_VARTYPE_OBJECT); + + VarMap::iterator found = GetLiveVar(plugin_var); + if (found == live_vars_.end()) { + NOTREACHED(); + return; + } + + DCHECK(found->second.track_with_no_reference_count > 0); + found->second.track_with_no_reference_count--; + DeleteObjectInfoIfNecessary(found); +} + +PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const { + CheckThreadingPreconditions(); + if (plugin_object.type != PP_VARTYPE_OBJECT) { + NOTREACHED(); + return PP_MakeUndefined(); + } + + Var* var = GetVar(plugin_object); + ProxyObjectVar* object = var->AsProxyObjectVar(); + if (!object) { + NOTREACHED(); + return PP_MakeUndefined(); + } + + // Make a var with the host ID. + PP_Var ret = { PP_VARTYPE_OBJECT }; + ret.value.as_id = object->host_var_id(); + return ret; +} + +PluginDispatcher* PluginVarTracker::DispatcherForPluginObject( + const PP_Var& plugin_object) const { + CheckThreadingPreconditions(); + if (plugin_object.type != PP_VARTYPE_OBJECT) + return NULL; + + VarMap::const_iterator found = GetLiveVar(plugin_object); + if (found == live_vars_.end()) + return NULL; + + ProxyObjectVar* object = found->second.var->AsProxyObjectVar(); + if (!object) + return NULL; + return object->dispatcher(); +} + +void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher, + const PP_Var& host_object) { + CheckThreadingPreconditions(); + DCHECK(host_object.type == PP_VARTYPE_OBJECT); + + // Convert the host object to a normal var valid in the plugin. + HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find( + HostVar(dispatcher, static_cast<int32>(host_object.value.as_id))); + if (found == host_var_to_plugin_var_.end()) { + NOTREACHED(); + return; + } + + // Now just release the object given the plugin var ID. + ReleaseVar(found->second); +} + +void PluginVarTracker::DidDeleteInstance(PP_Instance instance) { + // Calling the destructors on plugin objects may in turn release other + // objects which will mutate the map out from under us. So do a two-step + // process of identifying the ones to delete, and then delete them. + // + // See the comment above user_data_to_plugin_ in the header file. We assume + // there aren't that many objects so a brute-force search is reasonable. + std::vector<void*> user_data_to_delete; + for (UserDataToPluginImplementedVarMap::const_iterator i = + user_data_to_plugin_.begin(); + i != user_data_to_plugin_.end(); + ++i) { + if (i->second.instance == instance) + user_data_to_delete.push_back(i->first); + } + + for (size_t i = 0; i < user_data_to_delete.size(); i++) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data_to_delete[i]); + if (found == user_data_to_plugin_.end()) + continue; // Object removed from list while we were iterating. + + if (!found->second.plugin_object_id) { + // This object is for the freed instance and the plugin is not holding + // any references to it. Deallocate immediately. + CallWhileUnlocked(found->second.ppp_class->Deallocate, found->first); + user_data_to_plugin_.erase(found); + } else { + // The plugin is holding refs to this object. We don't want to call + // Deallocate since the plugin may be depending on those refs to keep + // its data alive. To avoid crashes in this case, just clear out the + // instance to mark it and continue. When the plugin refs go to 0, + // we'll notice there is no instance and call Deallocate. + found->second.instance = 0; + } + } +} + +void PluginVarTracker::DidDeleteDispatcher(PluginDispatcher* dispatcher) { + for (VarMap::iterator it = live_vars_.begin(); + it != live_vars_.end(); + ++it) { + if (it->second.var.get() == NULL) + continue; + ProxyObjectVar* object = it->second.var->AsProxyObjectVar(); + if (object && object->dispatcher() == dispatcher) + object->clear_dispatcher(); + } +} + +ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) { + return new PluginArrayBufferVar(size_in_bytes); +} + +ArrayBufferVar* PluginVarTracker::CreateShmArrayBuffer( + uint32 size_in_bytes, + base::SharedMemoryHandle handle) { + return new PluginArrayBufferVar(size_in_bytes, handle); +} + +void PluginVarTracker::PluginImplementedObjectCreated( + PP_Instance instance, + const PP_Var& created_var, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + PluginImplementedVar p; + p.ppp_class = ppp_class; + p.instance = instance; + p.plugin_object_id = created_var.value.as_id; + user_data_to_plugin_[ppp_class_data] = p; + + // Link the user data to the object. + ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar(); + object->set_user_data(ppp_class_data); +} + +void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data); + if (found == user_data_to_plugin_.end()) { + NOTREACHED(); + return; + } + user_data_to_plugin_.erase(found); +} + +bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) { + return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end(); +} + +bool PluginVarTracker::ValidatePluginObjectCall( + const PPP_Class_Deprecated* ppp_class, + void* user_data) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data); + if (found == user_data_to_plugin_.end()) + return false; + return found->second.ppp_class == ppp_class; +} + +int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) { + // Normal adding. + int32 new_id = VarTracker::AddVarInternal(var, mode); + + // Need to add proxy objects to the host var map. + ProxyObjectVar* proxy_object = var->AsProxyObjectVar(); + if (proxy_object) { + HostVar host_var(proxy_object->dispatcher(), proxy_object->host_var_id()); + DCHECK(host_var_to_plugin_var_.find(host_var) == + host_var_to_plugin_var_.end()); // Adding an object twice, use + // FindOrMakePluginVarFromHostVar. + host_var_to_plugin_var_[host_var] = new_id; + } + return new_id; +} + +void PluginVarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator iter) { + ProxyObjectVar* object = iter->second.var->AsProxyObjectVar(); + if (!object) { + NOTREACHED(); + return; + } + + DCHECK(iter->second.ref_count == 0); + + // Got an AddRef for an object we have no existing reference for. + // We need to tell the browser we've taken a ref. This comes up when the + // browser passes an object as an input param and holds a ref for us. + // This must be a sync message since otherwise the "addref" will actually + // occur after the return to the browser of the sync function that + // presumably sent the object. + SendAddRefObjectMsg(*object); +} + +void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) { + ProxyObjectVar* object = iter->second.var->AsProxyObjectVar(); + if (!object) { + NOTREACHED(); + return; + } + + // Notify the host we're no longer holding our ref. + DCHECK(iter->second.ref_count == 0); + SendReleaseObjectMsg(*object); + + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(object->user_data()); + if (found != user_data_to_plugin_.end()) { + // This object is implemented in the plugin. + if (found->second.instance == 0) { + // Instance is destroyed. This means that we'll never get a Deallocate + // call from the renderer and we should do so now. + found->second.ppp_class->Deallocate(found->first); + user_data_to_plugin_.erase(found); + } else { + // The plugin is releasing its last reference to an object it implements. + // Clear the tracking data that links our "plugin implemented object" to + // the var. If the instance is destroyed and there is no ID, we know that + // we should just call Deallocate on the object data. + // + // See the plugin_object_id declaration for more info. + found->second.plugin_object_id = 0; + } + } + + // This will optionally delete the info from live_vars_. + VarTracker::ObjectGettingZeroRef(iter); +} + +bool PluginVarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) { + // Get the info before calling the base class's version of this function, + // which may delete the object. + ProxyObjectVar* object = iter->second.var->AsProxyObjectVar(); + HostVar host_var(object->dispatcher(), object->host_var_id()); + + if (!VarTracker::DeleteObjectInfoIfNecessary(iter)) + return false; + + // Clean up the host var mapping. + DCHECK(host_var_to_plugin_var_.find(host_var) != + host_var_to_plugin_var_.end()); + host_var_to_plugin_var_.erase(host_var); + return true; +} + +PP_Var PluginVarTracker::GetOrCreateObjectVarID(ProxyObjectVar* object) { + // We can't use object->GetPPVar() because we don't want to affect the + // refcount, so we have to add everything manually here. + int32 var_id = object->GetExistingVarID(); + if (!var_id) { + var_id = AddVarInternal(object, ADD_VAR_CREATE_WITH_NO_REFERENCE); + object->AssignVarID(var_id); + } + + PP_Var ret = { PP_VARTYPE_OBJECT }; + ret.value.as_id = var_id; + return ret; +} + +void PluginVarTracker::SendAddRefObjectMsg( + const ProxyObjectVar& proxy_object) { + int unused; + if (proxy_object.dispatcher()) { + proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_AddRefObject( + API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id(), &unused)); + } +} + +void PluginVarTracker::SendReleaseObjectMsg( + const ProxyObjectVar& proxy_object) { + if (proxy_object.dispatcher()) { + proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_ReleaseObject( + API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id())); + } +} + +scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar( + const PP_Var& var, + PluginDispatcher* dispatcher) { + DCHECK(var.type == PP_VARTYPE_OBJECT); + HostVar host_var(dispatcher, var.value.as_id); + + HostVarToPluginVarMap::iterator found = + host_var_to_plugin_var_.find(host_var); + if (found == host_var_to_plugin_var_.end()) { + // Create a new object. + return scoped_refptr<ProxyObjectVar>( + new ProxyObjectVar(dispatcher, static_cast<int32>(var.value.as_id))); + } + + // Have this host var, look up the object. + VarMap::iterator ret = live_vars_.find(found->second); + DCHECK(ret != live_vars_.end()); + + // All objects should be proxy objects. + DCHECK(ret->second.var->AsProxyObjectVar()); + return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar()); +} + +int PluginVarTracker::TrackSharedMemoryHandle(PP_Instance instance, + base::SharedMemoryHandle handle, + uint32 size_in_bytes) { + NOTREACHED(); + return -1; +} + +bool PluginVarTracker::StopTrackingSharedMemoryHandle( + int id, + PP_Instance instance, + base::SharedMemoryHandle* handle, + uint32* size_in_bytes) { + NOTREACHED(); + return false; +} + +} // namesace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/plugin_var_tracker.h b/chromium/ppapi/proxy/plugin_var_tracker.h new file mode 100644 index 00000000000..670457f9c05 --- /dev/null +++ b/chromium/ppapi/proxy/plugin_var_tracker.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 PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ +#define PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/shared_memory.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/var_tracker.h" + +template<typename T> struct DefaultSingletonTraits; +struct PPP_Class_Deprecated; + +namespace ppapi { + +class ProxyObjectVar; + +namespace proxy { + +class PluginDispatcher; + +// Tracks live strings and objects in the plugin process. +class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { + public: + PluginVarTracker(); + ~PluginVarTracker(); + + // Manages tracking for receiving a VARTYPE_OBJECT from the remote side + // (either the plugin or the renderer) that has already had its reference + // count incremented on behalf of the caller. + PP_Var ReceiveObjectPassRef(const PP_Var& var, PluginDispatcher* dispatcher); + + // See the comment in var_tracker.h for more about what a tracked object is. + // This adds and releases the "track_with_no_reference_count" for a given + // object. + PP_Var TrackObjectWithNoReference(const PP_Var& host_var, + PluginDispatcher* dispatcher); + void StopTrackingObjectWithNoReference(const PP_Var& plugin_var); + + // Returns the host var for the corresponding plugin object var. The object + // should be a VARTYPE_OBJECT. The reference count is not affeceted. + PP_Var GetHostObject(const PP_Var& plugin_object) const; + + PluginDispatcher* DispatcherForPluginObject( + const PP_Var& plugin_object) const; + + // Like Release() but the var is identified by its host object ID (as + // returned by GetHostObject). + void ReleaseHostObject(PluginDispatcher* dispatcher, + const PP_Var& host_object); + + // VarTracker public overrides. + 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; + + // Notification that a plugin-implemented object (PPP_Class) was created by + // the plugin or deallocated by WebKit over IPC. + void PluginImplementedObjectCreated(PP_Instance instance, + const PP_Var& created_var, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data); + void PluginImplementedObjectDestroyed(void* ppp_class_data); + + // Returns true if there is an object implemented by the plugin with the + // given user_data that has not been deallocated yet. Call this when + // receiving a scripting call to the plugin to validate that the object + // receiving the call is still alive (see user_data_to_plugin_ below). + bool IsPluginImplementedObjectAlive(void* user_data); + + // Validates that the given class/user_data pair corresponds to a currently + // living plugin object. + bool ValidatePluginObjectCall(const PPP_Class_Deprecated* ppp_class, + void* user_data); + + void DidDeleteDispatcher(PluginDispatcher* dispatcher); + + private: + // VarTracker protected overrides. + virtual int32 AddVarInternal(Var* var, AddVarRefMode mode) OVERRIDE; + virtual void TrackedObjectGettingOneRef(VarMap::const_iterator iter) OVERRIDE; + virtual void ObjectGettingZeroRef(VarMap::iterator iter) OVERRIDE; + virtual bool DeleteObjectInfoIfNecessary(VarMap::iterator iter) OVERRIDE; + virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) OVERRIDE; + virtual ArrayBufferVar* CreateShmArrayBuffer( + uint32 size_in_bytes, + base::SharedMemoryHandle handle) OVERRIDE; + + private: + friend struct DefaultSingletonTraits<PluginVarTracker>; + friend class PluginProxyTestHarness; + + // Represents a var as received from the host. + struct HostVar { + HostVar(PluginDispatcher* d, int32 i); + + bool operator<(const HostVar& other) const; + + // The dispatcher that sent us this object. This is used so we know how to + // send back requests on this object. + PluginDispatcher* dispatcher; + + // The object ID that the host generated to identify the object. This is + // unique only within that host: different hosts could give us different + // objects with the same ID. + int32 host_object_id; + }; + + struct PluginImplementedVar { + const PPP_Class_Deprecated* ppp_class; + + // The instance that created this Var. This will be 0 if the instance has + // been destroyed but the object is still alive. + PP_Instance instance; + + // Represents the plugin var ID for the var corresponding to this object. + // If the plugin does not have a ref to the object but it's still alive + // (the DOM could be holding a ref keeping it alive) this will be 0. + // + // There is an obscure corner case. If the plugin returns an object to the + // renderer and releases all of its refs, the object will still be alive + // but there will be no plugin refs. It's possible for the plugin to get + // this same object again through the DOM, and we'll lose the correlation + // between plugin implemented object and car. This means we won't know when + // the plugin releases its last refs and may call Deallocate when the + // plugin is still holding a ref. + // + // However, for the plugin to be depending on holding a ref to an object + // that it implements that it previously released but got again through + // indirect means would be extremely rare, and we only allow var scripting + // in limited cases anyway. + int32 plugin_object_id; + }; + + // Returns the existing var ID for the given object var, creating and + // assigning an ID to it if necessary. This does not affect the reference + // count, so in the creation case the refcount will be 0. It's assumed in + // this case the caller will either adjust the refcount or the + // track_with_no_reference_count. + PP_Var GetOrCreateObjectVarID(ProxyObjectVar* object); + + // Sends an addref or release message to the browser for the given object ID. + void SendAddRefObjectMsg(const ProxyObjectVar& proxy_object); + void SendReleaseObjectMsg(const ProxyObjectVar& proxy_object); + + // Looks up the given host var. If we already know about it, returns a + // reference to the already-tracked object. If it doesn't creates a new one + // and returns it. If it's created, it's not added to the map. + scoped_refptr<ProxyObjectVar> FindOrMakePluginVarFromHostVar( + const PP_Var& var, + PluginDispatcher* dispatcher); + + // Maps host vars in the host to IDs in the plugin process. + typedef std::map<HostVar, int32> HostVarToPluginVarMap; + HostVarToPluginVarMap host_var_to_plugin_var_; + + // Maps "user data" for plugin implemented objects (PPP_Class) that are + // alive to various tracking info. + // + // This is tricky because there may not actually be any vars in the plugin + // associated with a plugin-implemented object, so they won't all have + // entries in our HostVarToPluginVarMap or the base class VarTracker's map. + // + // All objects that the plugin has created using CreateObject that have not + // yet been Deallocate()-ed by WebKit will be in this map. When the instance + // that created the object goes away, we know to call Deallocate on all + // remaining objects for that instance so that the data backing the object + // that the plugin owns is not leaked. We may not receive normal Deallocate + // calls from WebKit because the object could be leaked (attached to the DOM + // and outliving the plugin instance) or WebKit could send the deallocate + // after the out-of-process routing for that instance was torn down. + // + // There is an additional complexity. In WebKit, objects created by the + // plugin aren't actually bound to the plugin instance (for example, you + // could attach it to the DOM or send it to another plugin instance). It's + // possible that we could force deallocate an object when an instance id + // destroyed, but then another instance could get to that object somehow + // (like by reading it out of the DOM). We will then have deallocated the + // object and can't complete the call. We do not care about this case, and + // the calls will just fail. + typedef std::map<void*, PluginImplementedVar> + UserDataToPluginImplementedVarMap; + UserDataToPluginImplementedVarMap user_data_to_plugin_; + + DISALLOW_COPY_AND_ASSIGN(PluginVarTracker); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ diff --git a/chromium/ppapi/proxy/plugin_var_tracker_unittest.cc b/chromium/ppapi/proxy/plugin_var_tracker_unittest.cc new file mode 100644 index 00000000000..f43d7a8d4da --- /dev/null +++ b/chromium/ppapi/proxy/plugin_var_tracker_unittest.cc @@ -0,0 +1,248 @@ +// 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 "ipc/ipc_test_sink.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/proxy_object_var.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +PP_Var MakeObject(int32 object_id) { + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = object_id; + return ret; +} + +// A Deallocate() function for PPP_Class that just increments the integer +// referenced by the pointer so we know how often Deallocate was called. +void MarkOnDeallocate(void* object) { + (*static_cast<int*>(object))++; +} + +// A class that just implements MarkOnDeallocate on destruction. +PPP_Class_Deprecated mark_on_deallocate_class = { + NULL, // HasProperty, + NULL, // HasMethod, + NULL, // GetProperty, + NULL, // GetAllPropertyNames, + NULL, // SetProperty, + NULL, // RemoveProperty, + NULL, // Call, + NULL, // Construct, + &MarkOnDeallocate +}; + +} // namespace + +class PluginVarTrackerTest : public PluginProxyTest { + public: + PluginVarTrackerTest() {} + + protected: + // Asserts that there is a unique "release object" IPC message in the test + // sink. This will return the var ID from the message or -1 if none found. + int32 GetObjectIDForUniqueReleaseObject() { + const IPC::Message* release_msg = sink().GetUniqueMessageMatching( + PpapiHostMsg_PPBVar_ReleaseObject::ID); + if (!release_msg) + return -1; + + Tuple1<int64> id; + PpapiHostMsg_PPBVar_ReleaseObject::Read(release_msg, &id); + return id.a; + } +}; + +TEST_F(PluginVarTrackerTest, GetHostObject) { + ProxyAutoLock lock; + PP_Var host_object = MakeObject(12345); + + // Round-trip through the tracker to make sure the host object comes out the + // other end. + PP_Var plugin_object = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + PP_Var host_object2 = var_tracker().GetHostObject(plugin_object); + EXPECT_EQ(PP_VARTYPE_OBJECT, host_object2.type); + EXPECT_EQ(host_object.value.as_id, host_object2.value.as_id); + + var_tracker().ReleaseVar(plugin_object); +} + +TEST_F(PluginVarTrackerTest, ReceiveObjectPassRef) { + ProxyAutoLock lock; + PP_Var host_object = MakeObject(12345); + + // Receive the object, we should have one ref and no messages. + PP_Var plugin_object = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(0u, sink().message_count()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object)); + + // Receive the same object again, we should get the same plugin ID out. + PP_Var plugin_object2 = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object)); + + // It should have sent one message to decerment the refcount in the host. + // This is because it only maintains one host refcount for all references + // in the plugin, but the host just sent the second one. + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); + sink().ClearMessages(); + + // Release the object, one ref at a time. The second release should free + // the tracking data and send a release message to the browser. + var_tracker().ReleaseVar(plugin_object); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + var_tracker().ReleaseVar(plugin_object); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); +} + +// Tests freeing objects that have both refcounts and "tracked with no ref". +TEST_F(PluginVarTrackerTest, FreeTrackedAndReferencedObject) { + ProxyAutoLock lock; + PP_Var host_object = MakeObject(12345); + + // Phase one: First receive via a "pass ref", then a tracked with no ref. + PP_Var plugin_var = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Free via the refcount, this should release the object to the browser but + // maintain the tracked object. + var_tracker().ReleaseVar(plugin_var); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(1u, sink().message_count()); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); + + // Now free via the tracked object, this should free it. + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var)); + + // Phase two: Receive via a tracked, then get an addref. + sink().ClearMessages(); + plugin_var = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + plugin_var2 = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Free via the tracked object, this should have no effect. + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(0, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + EXPECT_EQ(0u, sink().message_count()); + + // Now free via the refcount, this should delete it. + var_tracker().ReleaseVar(plugin_var); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); +} + +TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) { + ProxyAutoLock lock; + PP_Var host_object = MakeObject(12345); + + // Receive a tracked object twice. + PP_Var plugin_var = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(2, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Now release those tracked items, the reference should be freed. + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(-1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); +} + +// Tests that objects implemented by the plugin that have no references by +// the plugin get their Deallocate function called on destruction. +TEST_F(PluginVarTrackerTest, PluginObjectInstanceDeleted) { + ProxyAutoLock lock; + PP_Var host_object = MakeObject(12345); + PP_Instance pp_instance = 0x12345; + + int deallocate_called = 0; + void* user_data = &deallocate_called; + + // Make a var with one reference. + scoped_refptr<ProxyObjectVar> object( + new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id)); + PP_Var plugin_var = MakeObject(var_tracker().AddVar(object.get())); + var_tracker().PluginImplementedObjectCreated( + pp_instance, plugin_var, &mark_on_deallocate_class, user_data); + + // Release the plugin ref to the var. WebKit hasn't called destroy so + // we won't get a destroy call. + object = NULL; + var_tracker().ReleaseVar(plugin_var); + EXPECT_EQ(0, deallocate_called); + + // Synthesize an instance destuction, this should call Deallocate. + var_tracker().DidDeleteInstance(pp_instance); + EXPECT_EQ(1, deallocate_called); +} + +// Tests what happens when a plugin keeps a ref to a plugin-implemented +// object var longer than the instance. We should not call the destructor until +// the plugin releases its last ref. +TEST_F(PluginVarTrackerTest, PluginObjectLeaked) { + ProxyAutoLock lock; + PP_Var host_object = MakeObject(12345); + PP_Instance pp_instance = 0x12345; + + int deallocate_called = 0; + void* user_data = &deallocate_called; + + // Make a var with one reference. + scoped_refptr<ProxyObjectVar> object( + new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id)); + PP_Var plugin_var = MakeObject(var_tracker().AddVar(object.get())); + var_tracker().PluginImplementedObjectCreated( + pp_instance, plugin_var, &mark_on_deallocate_class, user_data); + + // Destroy the instance. This should not call deallocate since the plugin + // still has a ref. + var_tracker().DidDeleteInstance(pp_instance); + EXPECT_EQ(0, deallocate_called); + + // Release the plugin ref to the var. Since the instance is gone this should + // call deallocate. + object = NULL; + var_tracker().ReleaseVar(plugin_var); + EXPECT_EQ(1, deallocate_called); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppapi_command_buffer_proxy.cc b/chromium/ppapi/proxy/ppapi_command_buffer_proxy.cc new file mode 100644 index 00000000000..8ca17e442d1 --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_command_buffer_proxy.cc @@ -0,0 +1,259 @@ +// 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 "ppapi/proxy/ppapi_command_buffer_proxy.h" + +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/proxy_channel.h" +#include "ppapi/shared_impl/api_id.h" +#include "ppapi/shared_impl/host_resource.h" + +namespace ppapi { +namespace proxy { + +PpapiCommandBufferProxy::PpapiCommandBufferProxy( + const ppapi::HostResource& resource, + ProxyChannel* channel) + : resource_(resource), + channel_(channel) { +} + +PpapiCommandBufferProxy::~PpapiCommandBufferProxy() { + // Delete all the locally cached shared memory objects, closing the handle + // in this process. + for (TransferBufferMap::iterator it = transfer_buffers_.begin(); + it != transfer_buffers_.end(); ++it) { + delete it->second.shared_memory; + it->second.shared_memory = NULL; + } +} + +void PpapiCommandBufferProxy::ReportChannelError() { + if (!channel_error_callback_.is_null()) { + channel_error_callback_.Run(); + channel_error_callback_.Reset(); + } +} + +int PpapiCommandBufferProxy::GetRouteID() const { + NOTIMPLEMENTED(); + return 0; +} + +bool PpapiCommandBufferProxy::Echo(const base::Closure& callback) { + return false; +} + +bool PpapiCommandBufferProxy::ProduceFrontBuffer(const gpu::Mailbox& mailbox) { + NOTIMPLEMENTED(); + return false; +} + +void PpapiCommandBufferProxy::SetChannelErrorCallback( + const base::Closure& callback) { + channel_error_callback_ = callback; +} + +bool PpapiCommandBufferProxy::Initialize() { + return true; +} + +gpu::CommandBuffer::State PpapiCommandBufferProxy::GetState() { + // Send will flag state with lost context if IPC fails. + if (last_state_.error == gpu::error::kNoError) { + gpu::CommandBuffer::State state; + bool success = false; + if (Send(new PpapiHostMsg_PPBGraphics3D_GetState( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &state, &success))) { + UpdateState(state, success); + } + } + + return last_state_; +} + +gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() { + // Note: The locking command buffer wrapper does not take a global lock before + // calling this function. + return last_state_; +} + +int32 PpapiCommandBufferProxy::GetLastToken() { + // Note: The locking command buffer wrapper does not take a global lock before + // calling this function. + return last_state_.token; +} + +void PpapiCommandBufferProxy::Flush(int32 put_offset) { + if (last_state_.error != gpu::error::kNoError) + return; + + IPC::Message* message = new PpapiHostMsg_PPBGraphics3D_AsyncFlush( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset); + + // Do not let a synchronous flush hold up this message. If this handler is + // deferred until after the synchronous flush completes, it will overwrite the + // cached last_state_ with out-of-date data. + message->set_unblock(true); + Send(message); +} + +gpu::CommandBuffer::State PpapiCommandBufferProxy::FlushSync(int32 put_offset, + int32 last_known_get) { + if (last_known_get == last_state_.get_offset) { + // Send will flag state with lost context if IPC fails. + if (last_state_.error == gpu::error::kNoError) { + gpu::CommandBuffer::State state; + bool success = false; + if (Send(new PpapiHostMsg_PPBGraphics3D_Flush( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, put_offset, + last_known_get, &state, &success))) { + UpdateState(state, success); + } + } + } else { + Flush(put_offset); + } + return last_state_; +} + +void PpapiCommandBufferProxy::SetGetBuffer(int32 transfer_buffer_id) { + if (last_state_.error == gpu::error::kNoError) { + Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id)); + } +} + +void PpapiCommandBufferProxy::SetGetOffset(int32 get_offset) { + // Not implemented in proxy. + NOTREACHED(); +} + +gpu::Buffer PpapiCommandBufferProxy::CreateTransferBuffer(size_t size, + int32* id) { + *id = -1; + + if (last_state_.error != gpu::error::kNoError) + return gpu::Buffer(); + + if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, size, id))) { + return gpu::Buffer(); + } + + if ((*id) <= 0) + return gpu::Buffer(); + + return GetTransferBuffer(*id); +} + +void PpapiCommandBufferProxy::DestroyTransferBuffer(int32 id) { + if (last_state_.error != gpu::error::kNoError) + return; + + // Remove the transfer buffer from the client side4 cache. + TransferBufferMap::iterator it = transfer_buffers_.find(id); + + if (it != transfer_buffers_.end()) { + // Delete the shared memory object, closing the handle in this process. + delete it->second.shared_memory; + + transfer_buffers_.erase(it); + } + + Send(new PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id)); +} + +gpu::Buffer PpapiCommandBufferProxy::GetTransferBuffer(int32 id) { + if (last_state_.error != gpu::error::kNoError) + return gpu::Buffer(); + + // Check local cache to see if there is already a client side shared memory + // object for this id. + TransferBufferMap::iterator it = transfer_buffers_.find(id); + if (it != transfer_buffers_.end()) { + return it->second; + } + + // Assuming we are in the renderer process, the service is responsible for + // duplicating the handle. This might not be true for NaCl. + ppapi::proxy::SerializedHandle handle( + ppapi::proxy::SerializedHandle::SHARED_MEMORY); + if (!Send(new PpapiHostMsg_PPBGraphics3D_GetTransferBuffer( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id, &handle))) { + return gpu::Buffer(); + } + if (!handle.is_shmem()) + return gpu::Buffer(); + + // Cache the transfer buffer shared memory object client side. + scoped_ptr<base::SharedMemory> shared_memory( + new base::SharedMemory(handle.shmem(), false)); + + // Map the shared memory on demand. + if (!shared_memory->memory()) { + if (!shared_memory->Map(handle.size())) { + return gpu::Buffer(); + } + } + + gpu::Buffer buffer; + buffer.ptr = shared_memory->memory(); + buffer.size = handle.size(); + buffer.shared_memory = shared_memory.release(); + transfer_buffers_[id] = buffer; + + return buffer; +} + +void PpapiCommandBufferProxy::SetToken(int32 token) { + NOTREACHED(); +} + +void PpapiCommandBufferProxy::SetParseError(gpu::error::Error error) { + NOTREACHED(); +} + +void PpapiCommandBufferProxy::SetContextLostReason( + gpu::error::ContextLostReason reason) { + NOTREACHED(); +} + +uint32 PpapiCommandBufferProxy::InsertSyncPoint() { + uint32 sync_point = 0; + if (last_state_.error == gpu::error::kNoError) { + Send(new PpapiHostMsg_PPBGraphics3D_InsertSyncPoint( + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, &sync_point)); + } + return sync_point; +} + +bool PpapiCommandBufferProxy::Send(IPC::Message* msg) { + DCHECK(last_state_.error == gpu::error::kNoError); + + if (channel_->Send(msg)) + return true; + + last_state_.error = gpu::error::kLostContext; + return false; +} + +void PpapiCommandBufferProxy::UpdateState( + const gpu::CommandBuffer::State& state, + bool success) { + // Handle wraparound. It works as long as we don't have more than 2B state + // updates in flight across which reordering occurs. + if (success) { + if (state.generation - last_state_.generation < 0x80000000U) { + last_state_ = state; + } + } else { + last_state_.error = gpu::error::kLostContext; + ++last_state_.generation; + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppapi_command_buffer_proxy.h b/chromium/ppapi/proxy/ppapi_command_buffer_proxy.h new file mode 100644 index 00000000000..b5c2c93081c --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_command_buffer_proxy.h @@ -0,0 +1,75 @@ +// 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_PROXY_COMMAND_BUFFER_PROXY_H_ +#define PPAPI_PROXY_COMMAND_BUFFER_PROXY_H_ + +#include "base/callback.h" +#include "base/containers/hash_tables.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/ipc/command_buffer_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/host_resource.h" + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace proxy { + +class ProxyChannel; + +class PPAPI_PROXY_EXPORT PpapiCommandBufferProxy : public CommandBufferProxy { + public: + PpapiCommandBufferProxy(const HostResource& resource, + ProxyChannel* channel); + virtual ~PpapiCommandBufferProxy(); + + void ReportChannelError(); + + // CommandBufferProxy implementation: + virtual int GetRouteID() const OVERRIDE; + virtual bool Echo(const base::Closure& callback) OVERRIDE; + virtual bool ProduceFrontBuffer(const gpu::Mailbox& mailbox) OVERRIDE; + virtual void SetChannelErrorCallback(const base::Closure& callback) OVERRIDE; + + // gpu::CommandBuffer implementation: + virtual bool Initialize(); + virtual State GetState(); + virtual State GetLastState(); + virtual int32 GetLastToken(); + virtual void Flush(int32 put_offset); + virtual State FlushSync(int32 put_offset, int32 last_known_get); + virtual void SetGetBuffer(int32 transfer_buffer_id); + virtual void SetGetOffset(int32 get_offset); + virtual gpu::Buffer CreateTransferBuffer(size_t size, int32* id); + virtual void DestroyTransferBuffer(int32 id); + virtual gpu::Buffer GetTransferBuffer(int32 id); + virtual void SetToken(int32 token); + virtual void SetParseError(gpu::error::Error error); + virtual void SetContextLostReason(gpu::error::ContextLostReason reason); + virtual uint32 InsertSyncPoint(); + + private: + bool Send(IPC::Message* msg); + void UpdateState(const gpu::CommandBuffer::State& state, bool success); + + typedef base::hash_map<int32, gpu::Buffer> TransferBufferMap; + TransferBufferMap transfer_buffers_; + + State last_state_; + + HostResource resource_; + ProxyChannel* channel_; + + base::Closure channel_error_callback_; + + DISALLOW_COPY_AND_ASSIGN(PpapiCommandBufferProxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_COMMAND_BUFFER_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppapi_message_utils.h b/chromium/ppapi/proxy/ppapi_message_utils.h new file mode 100644 index 00000000000..68667ddebd5 --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_message_utils.h @@ -0,0 +1,131 @@ +// 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_PROXY_PPAPI_MESSAGE_UTILS_H_ +#define PPAPI_PROXY_PPAPI_MESSAGE_UTILS_H_ + +#include "base/basictypes.h" +#include "base/pickle.h" +#include "base/tuple.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_utils.h" + +namespace ppapi { + +namespace internal { + +// TupleTypeMatch* check whether a tuple type contains elements of the specified +// types. They are used to make sure the output parameters of UnpackMessage() +// match the corresponding message type. +template <class TupleType, class A> +struct TupleTypeMatch1 { + static const bool kValue = false; +}; +template <class A> +struct TupleTypeMatch1<Tuple1<A>, A> { + static const bool kValue = true; +}; + +template <class TupleType, class A, class B> +struct TupleTypeMatch2 { + static const bool kValue = false; +}; +template <class A, class B> +struct TupleTypeMatch2<Tuple2<A, B>, A, B> { + static const bool kValue = true; +}; + +template <class TupleType, class A, class B, class C> +struct TupleTypeMatch3 { + static const bool kValue = false; +}; +template <class A, class B, class C> +struct TupleTypeMatch3<Tuple3<A, B, C>, A, B, C> { + static const bool kValue = true; +}; + +template <class TupleType, class A, class B, class C, class D> +struct TupleTypeMatch4 { + static const bool kValue = false; +}; +template <class A, class B, class C, class D> +struct TupleTypeMatch4<Tuple4<A, B, C, D>, A, B, C, D> { + static const bool kValue = true; +}; + +template <class TupleType, class A, class B, class C, class D, class E> +struct TupleTypeMatch5 { + static const bool kValue = false; +}; +template <class A, class B, class C, class D, class E> +struct TupleTypeMatch5<Tuple5<A, B, C, D, E>, A, B, C, D, E> { + static const bool kValue = true; +}; + +} // namespace internal + +template <class MsgClass, class A> +bool UnpackMessage(const IPC::Message& msg, A* a) { + COMPILE_ASSERT( + (internal::TupleTypeMatch1<typename MsgClass::Param, A>::kValue), + tuple_types_dont_match); + + PickleIterator iter(msg); + return IPC::ReadParam(&msg, &iter, a); +} + +template <class MsgClass, class A, class B> +bool UnpackMessage(const IPC::Message& msg, A* a, B* b) { + COMPILE_ASSERT( + (internal::TupleTypeMatch2<typename MsgClass::Param, A, B>::kValue), + tuple_types_dont_match); + + PickleIterator iter(msg); + return IPC::ReadParam(&msg, &iter, a) && IPC::ReadParam(&msg, &iter, b); +} + +template <class MsgClass, class A, class B, class C> +bool UnpackMessage(const IPC::Message& msg, A* a, B* b, C* c) { + COMPILE_ASSERT( + (internal::TupleTypeMatch3<typename MsgClass::Param, A, B, C>::kValue), + tuple_types_dont_match); + + PickleIterator iter(msg); + return IPC::ReadParam(&msg, &iter, a) && + IPC::ReadParam(&msg, &iter, b) && + IPC::ReadParam(&msg, &iter, c); +} + +template <class MsgClass, class A, class B, class C, class D> +bool UnpackMessage(const IPC::Message& msg, A* a, B* b, C* c, D* d) { + COMPILE_ASSERT( + (internal::TupleTypeMatch4<typename MsgClass::Param, A, B, C, D>::kValue), + tuple_types_dont_match); + + PickleIterator iter(msg); + return IPC::ReadParam(&msg, &iter, a) && + IPC::ReadParam(&msg, &iter, b) && + IPC::ReadParam(&msg, &iter, c) && + IPC::ReadParam(&msg, &iter, d); +} + +template <class MsgClass, class A, class B, class C, class D, class E> +bool UnpackMessage(const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e) { + COMPILE_ASSERT( + (internal::TupleTypeMatch5< + typename MsgClass::Param, A, B, C, D, E>::kValue), + tuple_types_dont_match); + + PickleIterator iter(msg); + return IPC::ReadParam(&msg, &iter, a) && + IPC::ReadParam(&msg, &iter, b) && + IPC::ReadParam(&msg, &iter, c) && + IPC::ReadParam(&msg, &iter, d) && + IPC::ReadParam(&msg, &iter, e); +} + +} // namespace ppapi + +#endif // PPAPI_PROXY_PPAPI_MESSAGE_UTILS_H_ + diff --git a/chromium/ppapi/proxy/ppapi_messages.cc b/chromium/ppapi/proxy/ppapi_messages.cc new file mode 100644 index 00000000000..5cee1c78254 --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_messages.cc @@ -0,0 +1,34 @@ +// 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. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "ppapi/proxy/ppapi_messages.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "ppapi/proxy/ppapi_messages.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "ppapi/proxy/ppapi_messages.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "ppapi/proxy/ppapi_messages.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "ppapi/proxy/ppapi_messages.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "ppapi/proxy/ppapi_messages.h" +} // namespace IPC + diff --git a/chromium/ppapi/proxy/ppapi_messages.h b/chromium/ppapi/proxy/ppapi_messages.h new file mode 100644 index 00000000000..3767f8f4c1c --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_messages.h @@ -0,0 +1,2060 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included message header, no traditional include guard. +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/files/file_path.h" +#include "base/memory/shared_memory.h" +#include "base/process/process.h" +#include "base/strings/string16.h" +#include "base/sync_socket.h" +#include "base/values.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/ipc/gpu_command_buffer_traits.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/dev/pp_video_capture_dev.h" +#include "ppapi/c/dev/pp_video_dev.h" +#include "ppapi/c/dev/ppb_truetype_font_dev.h" +#include "ppapi/c/dev/ppb_url_util_dev.h" +#include "ppapi/c/dev/ppp_printing_dev.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/c/ppb_tcp_socket.h" +#include "ppapi/c/ppb_text_input_controller.h" +#include "ppapi/c/ppb_udp_socket.h" +#include "ppapi/c/private/pp_content_decryptor.h" +#include "ppapi/c/private/pp_private_font_charset.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/c/private/ppb_host_resolver_private.h" +#include "ppapi/c/private/ppb_net_address_private.h" +#include "ppapi/c/private/ppb_pdf.h" +#include "ppapi/c/private/ppb_talk_private.h" +#include "ppapi/c/private/ppp_flash_browser_operations.h" +#include "ppapi/proxy/host_resolver_private_resource.h" +#include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/serialized_flash_menu.h" +#include "ppapi/proxy/serialized_handle.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/dir_contents.h" +#include "ppapi/shared_impl/file_path.h" +#include "ppapi/shared_impl/file_ref_create_info.h" +#include "ppapi/shared_impl/ppapi_nacl_channel_args.h" +#include "ppapi/shared_impl/ppapi_preferences.h" +#include "ppapi/shared_impl/ppb_device_ref_shared.h" +#include "ppapi/shared_impl/ppb_input_event_shared.h" +#include "ppapi/shared_impl/ppb_network_list_private_shared.h" +#include "ppapi/shared_impl/ppb_view_shared.h" +#include "ppapi/shared_impl/ppp_flash_browser_operations_shared.h" +#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" +#include "ppapi/shared_impl/socket_option_data.h" +#include "ppapi/shared_impl/url_request_info_data.h" +#include "ppapi/shared_impl/url_response_info_data.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT PPAPI_PROXY_EXPORT + +#define IPC_MESSAGE_START PpapiMsgStart + +IPC_ENUM_TRAITS(PP_AudioSampleRate) +IPC_ENUM_TRAITS(PP_DeviceType_Dev) +IPC_ENUM_TRAITS(PP_DecryptorStreamType) +IPC_ENUM_TRAITS(PP_FileSystemType) +IPC_ENUM_TRAITS(PP_FileType) +IPC_ENUM_TRAITS(PP_Flash_BrowserOperations_Permission) +IPC_ENUM_TRAITS(PP_Flash_BrowserOperations_SettingType) +IPC_ENUM_TRAITS(PP_FlashSetting) +IPC_ENUM_TRAITS(PP_ImageDataFormat) +IPC_ENUM_TRAITS(PP_InputEvent_MouseButton) +IPC_ENUM_TRAITS(PP_InputEvent_Type) +IPC_ENUM_TRAITS_MAX_VALUE(PP_NetAddressFamily_Private, + PP_NETADDRESSFAMILY_PRIVATE_IPV6) +IPC_ENUM_TRAITS(PP_NetworkListState_Private) +IPC_ENUM_TRAITS(PP_NetworkListType_Private) +IPC_ENUM_TRAITS(PP_PrintOrientation_Dev) +IPC_ENUM_TRAITS(PP_PrintOutputFormat_Dev) +IPC_ENUM_TRAITS(PP_PrintScalingOption_Dev) +IPC_ENUM_TRAITS(PP_PrivateFontCharset) +IPC_ENUM_TRAITS(PP_ResourceImage) +IPC_ENUM_TRAITS(PP_ResourceString) +IPC_ENUM_TRAITS_MAX_VALUE(PP_TalkEvent, PP_TALKEVENT_NUM_EVENTS - 1) +IPC_ENUM_TRAITS_MAX_VALUE(PP_TalkPermission, + PP_TALKPERMISSION_NUM_PERMISSIONS - 1) +IPC_ENUM_TRAITS_MAX_VALUE(PP_TCPSocket_Option, + PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE) +IPC_ENUM_TRAITS(PP_TextInput_Type) +IPC_ENUM_TRAITS(PP_TrueTypeFontFamily_Dev) +IPC_ENUM_TRAITS(PP_TrueTypeFontStyle_Dev) +IPC_ENUM_TRAITS(PP_TrueTypeFontWeight_Dev) +IPC_ENUM_TRAITS(PP_TrueTypeFontWidth_Dev) +IPC_ENUM_TRAITS(PP_TrueTypeFontCharset_Dev) +IPC_ENUM_TRAITS_MAX_VALUE(PP_UDPSocket_Option, + PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE) +IPC_ENUM_TRAITS(PP_VideoDecodeError_Dev) +IPC_ENUM_TRAITS(PP_VideoDecoder_Profile) + +IPC_STRUCT_TRAITS_BEGIN(PP_Point) + IPC_STRUCT_TRAITS_MEMBER(x) + IPC_STRUCT_TRAITS_MEMBER(y) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_FloatPoint) + IPC_STRUCT_TRAITS_MEMBER(x) + IPC_STRUCT_TRAITS_MEMBER(y) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_Size) + IPC_STRUCT_TRAITS_MEMBER(height) + IPC_STRUCT_TRAITS_MEMBER(width) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_Rect) + IPC_STRUCT_TRAITS_MEMBER(point) + IPC_STRUCT_TRAITS_MEMBER(size) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_ImageDataDesc) + IPC_STRUCT_TRAITS_MEMBER(format) + IPC_STRUCT_TRAITS_MEMBER(size) + IPC_STRUCT_TRAITS_MEMBER(stride) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_PictureBuffer_Dev) + IPC_STRUCT_TRAITS_MEMBER(id) + IPC_STRUCT_TRAITS_MEMBER(size) + IPC_STRUCT_TRAITS_MEMBER(texture_id) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_Picture_Dev) + IPC_STRUCT_TRAITS_MEMBER(picture_buffer_id) + IPC_STRUCT_TRAITS_MEMBER(bitstream_buffer_id) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_PrintPageNumberRange_Dev) + IPC_STRUCT_TRAITS_MEMBER(first_page_number) + IPC_STRUCT_TRAITS_MEMBER(last_page_number) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_VideoCaptureDeviceInfo_Dev) + IPC_STRUCT_TRAITS_MEMBER(width) + IPC_STRUCT_TRAITS_MEMBER(height) + IPC_STRUCT_TRAITS_MEMBER(frames_per_second) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_HostResolver_Private_Hint) + IPC_STRUCT_TRAITS_MEMBER(family) + IPC_STRUCT_TRAITS_MEMBER(flags) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_PrintSettings_Dev) + IPC_STRUCT_TRAITS_MEMBER(printable_area) + IPC_STRUCT_TRAITS_MEMBER(content_area) + IPC_STRUCT_TRAITS_MEMBER(paper_size) + IPC_STRUCT_TRAITS_MEMBER(dpi) + IPC_STRUCT_TRAITS_MEMBER(orientation) + IPC_STRUCT_TRAITS_MEMBER(print_scaling_option) + IPC_STRUCT_TRAITS_MEMBER(grayscale) + IPC_STRUCT_TRAITS_MEMBER(format) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_URLComponent_Dev) + IPC_STRUCT_TRAITS_MEMBER(begin) + IPC_STRUCT_TRAITS_MEMBER(len) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_URLComponents_Dev) + IPC_STRUCT_TRAITS_MEMBER(scheme) + IPC_STRUCT_TRAITS_MEMBER(username) + IPC_STRUCT_TRAITS_MEMBER(password) + IPC_STRUCT_TRAITS_MEMBER(host) + IPC_STRUCT_TRAITS_MEMBER(port) + IPC_STRUCT_TRAITS_MEMBER(path) + IPC_STRUCT_TRAITS_MEMBER(query) + IPC_STRUCT_TRAITS_MEMBER(ref) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::DeviceRefData) + IPC_STRUCT_TRAITS_MEMBER(type) + IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(id) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::DirEntry) + IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(is_dir) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::FileRef_CreateInfo) + IPC_STRUCT_TRAITS_MEMBER(file_system_type) + IPC_STRUCT_TRAITS_MEMBER(internal_path) + IPC_STRUCT_TRAITS_MEMBER(display_name) + IPC_STRUCT_TRAITS_MEMBER(pending_host_resource_id) + IPC_STRUCT_TRAITS_MEMBER(file_system_plugin_resource) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::FlashSiteSetting) + IPC_STRUCT_TRAITS_MEMBER(site) + IPC_STRUCT_TRAITS_MEMBER(permission) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::ViewData) + IPC_STRUCT_TRAITS_MEMBER(rect) + IPC_STRUCT_TRAITS_MEMBER(is_fullscreen) + IPC_STRUCT_TRAITS_MEMBER(is_page_visible) + IPC_STRUCT_TRAITS_MEMBER(clip_rect) + IPC_STRUCT_TRAITS_MEMBER(device_scale) + IPC_STRUCT_TRAITS_MEMBER(css_scale) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_TouchPoint) + IPC_STRUCT_TRAITS_MEMBER(id) + IPC_STRUCT_TRAITS_MEMBER(position) + IPC_STRUCT_TRAITS_MEMBER(radius) + IPC_STRUCT_TRAITS_MEMBER(rotation_angle) + IPC_STRUCT_TRAITS_MEMBER(pressure) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::Preferences) + IPC_STRUCT_TRAITS_MEMBER(standard_font_family_map) + IPC_STRUCT_TRAITS_MEMBER(fixed_font_family_map) + IPC_STRUCT_TRAITS_MEMBER(serif_font_family_map) + IPC_STRUCT_TRAITS_MEMBER(sans_serif_font_family_map) + IPC_STRUCT_TRAITS_MEMBER(default_font_size) + IPC_STRUCT_TRAITS_MEMBER(default_fixed_font_size) + IPC_STRUCT_TRAITS_MEMBER(number_of_cpu_cores) + IPC_STRUCT_TRAITS_MEMBER(is_3d_supported) + IPC_STRUCT_TRAITS_MEMBER(is_stage3d_supported) + IPC_STRUCT_TRAITS_MEMBER(is_stage3d_baseline_supported) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::InputEventData) + IPC_STRUCT_TRAITS_MEMBER(is_filtered) + IPC_STRUCT_TRAITS_MEMBER(event_type) + IPC_STRUCT_TRAITS_MEMBER(event_time_stamp) + IPC_STRUCT_TRAITS_MEMBER(event_modifiers) + IPC_STRUCT_TRAITS_MEMBER(mouse_button) + IPC_STRUCT_TRAITS_MEMBER(mouse_position) + IPC_STRUCT_TRAITS_MEMBER(mouse_click_count) + IPC_STRUCT_TRAITS_MEMBER(mouse_movement) + IPC_STRUCT_TRAITS_MEMBER(wheel_delta) + IPC_STRUCT_TRAITS_MEMBER(wheel_ticks) + IPC_STRUCT_TRAITS_MEMBER(wheel_scroll_by_page) + IPC_STRUCT_TRAITS_MEMBER(key_code) + IPC_STRUCT_TRAITS_MEMBER(usb_key_code) + IPC_STRUCT_TRAITS_MEMBER(character_text) + IPC_STRUCT_TRAITS_MEMBER(composition_segment_offsets) + IPC_STRUCT_TRAITS_MEMBER(composition_target_segment) + IPC_STRUCT_TRAITS_MEMBER(composition_selection_start) + IPC_STRUCT_TRAITS_MEMBER(composition_selection_end) + IPC_STRUCT_TRAITS_MEMBER(touches) + IPC_STRUCT_TRAITS_MEMBER(changed_touches) + IPC_STRUCT_TRAITS_MEMBER(target_touches) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::HostPortPair) + IPC_STRUCT_TRAITS_MEMBER(host) + IPC_STRUCT_TRAITS_MEMBER(port) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::URLRequestInfoData) + IPC_STRUCT_TRAITS_MEMBER(url) + IPC_STRUCT_TRAITS_MEMBER(method) + IPC_STRUCT_TRAITS_MEMBER(headers) + IPC_STRUCT_TRAITS_MEMBER(stream_to_file) + IPC_STRUCT_TRAITS_MEMBER(follow_redirects) + IPC_STRUCT_TRAITS_MEMBER(record_download_progress) + IPC_STRUCT_TRAITS_MEMBER(record_upload_progress) + IPC_STRUCT_TRAITS_MEMBER(has_custom_referrer_url) + IPC_STRUCT_TRAITS_MEMBER(custom_referrer_url) + IPC_STRUCT_TRAITS_MEMBER(allow_cross_origin_requests) + IPC_STRUCT_TRAITS_MEMBER(allow_credentials) + IPC_STRUCT_TRAITS_MEMBER(has_custom_content_transfer_encoding) + IPC_STRUCT_TRAITS_MEMBER(custom_content_transfer_encoding) + IPC_STRUCT_TRAITS_MEMBER(prefetch_buffer_upper_threshold) + IPC_STRUCT_TRAITS_MEMBER(prefetch_buffer_lower_threshold) + IPC_STRUCT_TRAITS_MEMBER(has_custom_user_agent) + IPC_STRUCT_TRAITS_MEMBER(custom_user_agent) + IPC_STRUCT_TRAITS_MEMBER(body) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::URLRequestInfoData::BodyItem) + IPC_STRUCT_TRAITS_MEMBER(is_file) + IPC_STRUCT_TRAITS_MEMBER(data) + // Note: we don't serialize file_ref. + IPC_STRUCT_TRAITS_MEMBER(file_ref_host_resource) + IPC_STRUCT_TRAITS_MEMBER(start_offset) + IPC_STRUCT_TRAITS_MEMBER(number_of_bytes) + IPC_STRUCT_TRAITS_MEMBER(expected_last_modified_time) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::URLResponseInfoData) + IPC_STRUCT_TRAITS_MEMBER(url) + IPC_STRUCT_TRAITS_MEMBER(headers) + IPC_STRUCT_TRAITS_MEMBER(status_code) + IPC_STRUCT_TRAITS_MEMBER(status_text) + IPC_STRUCT_TRAITS_MEMBER(redirect_url) + IPC_STRUCT_TRAITS_MEMBER(body_as_file_ref) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ppapi::NetworkInfo) + IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(type) + IPC_STRUCT_TRAITS_MEMBER(state) + IPC_STRUCT_TRAITS_MEMBER(addresses) + IPC_STRUCT_TRAITS_MEMBER(display_name) + IPC_STRUCT_TRAITS_MEMBER(mtu) +IPC_STRUCT_TRAITS_END() + +// Only whitelisted switches passed through NaClChannelArgs. +// The list of switches can be found in: +// chrome/browser/nacl_host/nacl_process_host.cc +IPC_STRUCT_TRAITS_BEGIN(ppapi::PpapiNaClChannelArgs) + IPC_STRUCT_TRAITS_MEMBER(off_the_record) + IPC_STRUCT_TRAITS_MEMBER(permissions) + IPC_STRUCT_TRAITS_MEMBER(switch_names) + IPC_STRUCT_TRAITS_MEMBER(switch_values) +IPC_STRUCT_TRAITS_END() + +#if !defined(OS_NACL) && !defined(NACL_WIN64) + +IPC_STRUCT_TRAITS_BEGIN(ppapi::proxy::PPPDecryptor_Buffer) + IPC_STRUCT_TRAITS_MEMBER(resource) + IPC_STRUCT_TRAITS_MEMBER(handle) + IPC_STRUCT_TRAITS_MEMBER(size) +IPC_STRUCT_TRAITS_END() + +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// These are from the browser to the plugin. +// Loads the given plugin. +IPC_MESSAGE_CONTROL2(PpapiMsg_LoadPlugin, + base::FilePath /* path */, + ppapi::PpapiPermissions /* permissions */) + +// Creates a channel to talk to a renderer. The plugin will respond with +// PpapiHostMsg_ChannelCreated. +IPC_MESSAGE_CONTROL3(PpapiMsg_CreateChannel, + base::ProcessId /* renderer_pid */, + int /* renderer_child_id */, + bool /* incognito */) + +// Creates a channel to talk to a renderer. This message is only used by the +// NaCl IPC proxy. It is intercepted by NaClIPCAdapter, which creates the +// actual channel and rewrites the message for the untrusted side. +IPC_MESSAGE_CONTROL3(PpapiMsg_CreateNaClChannel, + int /* renderer_id */, + ppapi::PpapiNaClChannelArgs /* args */, + ppapi::proxy::SerializedHandle /* channel_handle */) + +// Instructs the plugin process to crash. +IPC_MESSAGE_CONTROL0(PpapiMsg_Crash) + +// Instructs the plugin process to hang. +IPC_MESSAGE_CONTROL0(PpapiMsg_Hang) + +// Each plugin may be referenced by multiple renderers. We need the instance +// IDs to be unique within a plugin, despite coming from different renderers, +// and unique within a renderer, despite going to different plugins. This means +// that neither the renderer nor the plugin can generate instance IDs without +// consulting the other. +// +// We resolve this by having the renderer generate a unique instance ID inside +// its process. It then asks the plugin to reserve that ID by sending this sync +// message. If the plugin has not yet seen this ID, it will remember it as used +// (to prevent a race condition if another renderer tries to then use the same +// instance), and set usable as true. +// +// If the plugin has already seen the instance ID, it will set usable as false +// and the renderer must retry a new instance ID. +IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_ReserveInstanceId, + PP_Instance /* instance */, + bool /* usable */) + +// Passes the WebKit preferences to the plugin. +IPC_MESSAGE_CONTROL1(PpapiMsg_SetPreferences, + ppapi::Preferences) + +// Sent in both directions to see if the other side supports the given +// interface. +IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_SupportsInterface, + std::string /* interface_name */, + bool /* result */) + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +// Network state notification from the browser for implementing +// PPP_NetworkState_Dev. +IPC_MESSAGE_CONTROL1(PpapiMsg_SetNetworkState, + bool /* online */) + +// Requests a list of sites that have data stored from the plugin. The plugin +// process will respond with PpapiHostMsg_GetSitesWithDataResult. This is used +// for Flash. +IPC_MESSAGE_CONTROL2(PpapiMsg_GetSitesWithData, + uint32 /* request_id */, + base::FilePath /* plugin_data_path */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_GetSitesWithDataResult, + uint32 /* request_id */, + std::vector<std::string> /* sites */) + +// Instructs the plugin to clear data for the given site & time. The plugin +// process will respond with PpapiHostMsg_ClearSiteDataResult. This is used +// for Flash. +IPC_MESSAGE_CONTROL5(PpapiMsg_ClearSiteData, + uint32 /* request_id */, + base::FilePath /* plugin_data_path */, + std::string /* site */, + uint64 /* flags */, + uint64 /* max_age */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_ClearSiteDataResult, + uint32 /* request_id */, + bool /* success */) + +IPC_MESSAGE_CONTROL2(PpapiMsg_DeauthorizeContentLicenses, + uint32 /* request_id */, + base::FilePath /* plugin_data_path */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_DeauthorizeContentLicensesResult, + uint32 /* request_id */, + bool /* success */) + +IPC_MESSAGE_CONTROL3(PpapiMsg_GetPermissionSettings, + uint32 /* request_id */, + base::FilePath /* plugin_data_path */, + PP_Flash_BrowserOperations_SettingType /* setting_type */) +IPC_MESSAGE_CONTROL4( + PpapiHostMsg_GetPermissionSettingsResult, + uint32 /* request_id */, + bool /* success */, + PP_Flash_BrowserOperations_Permission /* default_permission */, + ppapi::FlashSiteSettings /* sites */) + +IPC_MESSAGE_CONTROL5(PpapiMsg_SetDefaultPermission, + uint32 /* request_id */, + base::FilePath /* plugin_data_path */, + PP_Flash_BrowserOperations_SettingType /* setting_type */, + PP_Flash_BrowserOperations_Permission /* permission */, + bool /* clear_site_specific */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_SetDefaultPermissionResult, + uint32 /* request_id */, + bool /* success */) + +IPC_MESSAGE_CONTROL4(PpapiMsg_SetSitePermission, + uint32 /* request_id */, + base::FilePath /* plugin_data_path */, + PP_Flash_BrowserOperations_SettingType /* setting_type */, + ppapi::FlashSiteSettings /* sites */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_SetSitePermissionResult, + uint32 /* request_id */, + bool /* success */) + +// Broker Process. +IPC_SYNC_MESSAGE_CONTROL2_1(PpapiMsg_ConnectToPlugin, + PP_Instance /* instance */, + IPC::PlatformFileForTransit /* handle */, + int32_t /* result */) +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// PPB_Audio. + +// Notifies the result of the audio stream create call. This is called in +// both error cases and in the normal success case. These cases are +// differentiated by the result code, which is one of the standard PPAPI +// result codes. +// +// The handler of this message should always close all of the handles passed +// in, since some could be valid even in the error case. +IPC_MESSAGE_ROUTED4(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, + ppapi::HostResource /* audio_id */, + int32_t /* result_code (will be != PP_OK on failure) */, + ppapi::proxy::SerializedHandle /* socket_handle */, + ppapi::proxy::SerializedHandle /* handle */) + +// PPB_FileRef. +// TODO(teravest): Remove these messages when we've switched over to the "new" +// proxy. +IPC_MESSAGE_ROUTED3( + PpapiMsg_PPBFileRef_CallbackComplete, + ppapi::HostResource /* resource */, + uint32_t /* callback_id */, + int32_t /* result */) + +IPC_MESSAGE_ROUTED4( + PpapiMsg_PPBFileRef_QueryCallbackComplete, + ppapi::HostResource /* resource */, + PP_FileInfo /* file_info */, + uint32_t /* callback_id */, + int32_t /* result */) + +IPC_MESSAGE_ROUTED5( + PpapiMsg_PPBFileRef_ReadDirectoryEntriesCallbackComplete, + ppapi::HostResource /* resource */, + std::vector<ppapi::PPB_FileRef_CreateInfo> /* files */, + std::vector<PP_FileType> /* file_types */, + uint32_t /* callback_id */, + int32_t /* result */) + +// PPB_FileSystem. +IPC_MESSAGE_ROUTED2( + PpapiMsg_PPBFileSystem_OpenComplete, + ppapi::HostResource /* filesystem */, + int32_t /* result */) + +// PPB_Graphics3D. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBGraphics3D_SwapBuffersACK, + ppapi::HostResource /* graphics_3d */, + int32_t /* pp_error */) + +// PPB_ImageData. +IPC_MESSAGE_ROUTED1(PpapiMsg_PPBImageData_NotifyUnusedImageData, + ppapi::HostResource /* old_image_data */) + +// PPB_Instance. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBInstance_MouseLockComplete, + PP_Instance /* instance */, + int32_t /* result */) + +// PPP_Class. +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_HasProperty, + int64 /* ppp_class */, + int64 /* object */, + ppapi::proxy::SerializedVar /* property */, + ppapi::proxy::SerializedVar /* out_exception */, + bool /* result */) +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_HasMethod, + int64 /* ppp_class */, + int64 /* object */, + ppapi::proxy::SerializedVar /* method */, + ppapi::proxy::SerializedVar /* out_exception */, + bool /* result */) +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_GetProperty, + int64 /* ppp_class */, + int64 /* object */, + ppapi::proxy::SerializedVar /* property */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiMsg_PPPClass_EnumerateProperties, + int64 /* ppp_class */, + int64 /* object */, + std::vector<ppapi::proxy::SerializedVar> /* props */, + ppapi::proxy::SerializedVar /* out_exception */) +IPC_SYNC_MESSAGE_ROUTED4_1(PpapiMsg_PPPClass_SetProperty, + int64 /* ppp_class */, + int64 /* object */, + ppapi::proxy::SerializedVar /* name */, + ppapi::proxy::SerializedVar /* value */, + ppapi::proxy::SerializedVar /* out_exception */) +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiMsg_PPPClass_RemoveProperty, + int64 /* ppp_class */, + int64 /* object */, + ppapi::proxy::SerializedVar /* property */, + ppapi::proxy::SerializedVar /* out_exception */) +IPC_SYNC_MESSAGE_ROUTED4_2(PpapiMsg_PPPClass_Call, + int64 /* ppp_class */, + int64 /* object */, + ppapi::proxy::SerializedVar /* method_name */, + std::vector<ppapi::proxy::SerializedVar> /* args */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_Construct, + int64 /* ppp_class */, + int64 /* object */, + std::vector<ppapi::proxy::SerializedVar> /* args */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPClass_Deallocate, + int64 /* ppp_class */, + int64 /* object */) + +// PPP_Graphics3D_Dev. +IPC_MESSAGE_ROUTED1(PpapiMsg_PPPGraphics3D_ContextLost, + PP_Instance /* instance */) + +// PPP_InputEvent. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInputEvent_HandleInputEvent, + PP_Instance /* instance */, + ppapi::InputEventData /* data */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInputEvent_HandleFilteredInputEvent, + PP_Instance /* instance */, + ppapi::InputEventData /* data */, + PP_Bool /* result */) + +// PPP_Instance. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiMsg_PPPInstance_DidCreate, + PP_Instance /* instance */, + std::vector<std::string> /* argn */, + std::vector<std::string> /* argv */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiMsg_PPPInstance_DidDestroy, + PP_Instance /* instance */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPInstance_DidChangeView, + PP_Instance /* instance */, + ppapi::ViewData /* new_data */, + PP_Bool /* flash_fullscreen */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInstance_DidChangeFocus, + PP_Instance /* instance */, + PP_Bool /* has_focus */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPInstance_HandleDocumentLoad, + PP_Instance /* instance */, + int /* pending_loader_host_id */, + ppapi::URLResponseInfoData /* response */) + +// PPP_Messaging. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPMessaging_HandleMessage, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* message */) + +// PPP_MouseLock. +IPC_MESSAGE_ROUTED1(PpapiMsg_PPPMouseLock_MouseLockLost, + PP_Instance /* instance */) + +// PPB_NetworkMonitor_Private. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBNetworkMonitor_NetworkList, + uint32 /* plugin_dispatcher_id */, + ppapi::NetworkList /* network_list */) + +// PPP_Printing +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiMsg_PPPPrinting_QuerySupportedFormats, + PP_Instance /* instance */, + uint32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPPrinting_Begin, + PP_Instance /* instance */, + std::string /* settings_string */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPPrinting_PrintPages, + PP_Instance /* instance */, + std::vector<PP_PrintPageNumberRange_Dev> /* pages */, + ppapi::HostResource /* result */) +IPC_MESSAGE_ROUTED1(PpapiMsg_PPPPrinting_End, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiMsg_PPPPrinting_IsScalingDisabled, + PP_Instance /* instance */, + bool /* result */) + +// PPP_TextInput. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPTextInput_RequestSurroundingText, + PP_Instance /* instance */, + uint32_t /* desired_number_of_characters */) + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +// PPB_Broker. +IPC_MESSAGE_ROUTED3( + PpapiMsg_PPBBroker_ConnectComplete, + ppapi::HostResource /* broker */, + IPC::PlatformFileForTransit /* handle */, + int32_t /* result */) + +// PPP_ContentDecryptor_Dev +IPC_MESSAGE_ROUTED4(PpapiMsg_PPPContentDecryptor_GenerateKeyRequest, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* key_system, String */, + ppapi::proxy::SerializedVar /* type, String */, + ppapi::proxy::SerializedVar /* init_data, ArrayBuffer */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPPContentDecryptor_AddKey, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* session_id, String */, + ppapi::proxy::SerializedVar /* key, ArrayBuffer */, + ppapi::proxy::SerializedVar /* init_data, ArrayBuffer */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPContentDecryptor_CancelKeyRequest, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* session_id, String */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPContentDecryptor_Decrypt, + PP_Instance /* instance */, + ppapi::proxy::PPPDecryptor_Buffer /* buffer */, + std::string /* serialized_block_info */) +IPC_MESSAGE_ROUTED3( + PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder, + PP_Instance /* instance */, + std::string /* serialized_decoder_config */, + ppapi::proxy::PPPDecryptor_Buffer /* extra_data_buffer */) +IPC_MESSAGE_ROUTED3( + PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder, + PP_Instance /* instance */, + std::string /* serialized_decoder_config */, + ppapi::proxy::PPPDecryptor_Buffer /* extra_data_buffer. */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPContentDecryptor_DeinitializeDecoder, + PP_Instance /* instance */, + PP_DecryptorStreamType /* decoder_type */, + uint32_t /* request_id */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPContentDecryptor_ResetDecoder, + PP_Instance /* instance */, + PP_DecryptorStreamType /* decoder_type */, + uint32_t /* request_id */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPPContentDecryptor_DecryptAndDecode, + PP_Instance /* instance */, + PP_DecryptorStreamType /* decoder_type */, + ppapi::proxy::PPPDecryptor_Buffer /* buffer */, + std::string /* serialized_block_info */) +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// PPB_TCPSocket and PPB_TCPSocket_Private. +IPC_MESSAGE_ROUTED5(PpapiMsg_PPBTCPSocket_ConnectACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + int32_t /* result */, + PP_NetAddress_Private /* local_addr */, + PP_NetAddress_Private /* remote_addr */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPBTCPSocket_SSLHandshakeACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + bool /* succeeded */, + ppapi::PPB_X509Certificate_Fields /* certificate_fields */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPBTCPSocket_ReadACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + int32_t /* result */, + std::string /* data */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPBTCPSocket_WriteACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + int32_t /* result */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPBTCPSocket_SetOptionACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + int32_t /* result */) + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +// PPP_Instance_Private. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiMsg_PPPInstancePrivate_GetInstanceObject, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* result */) + +// PPB_VideoDecoder_Dev. +// (Messages from renderer to plugin to notify it to run callbacks.) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPBVideoDecoder_EndOfBitstreamACK, + ppapi::HostResource /* video_decoder */, + int32_t /* bitstream buffer id */, + int32_t /* PP_CompletionCallback result */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBVideoDecoder_FlushACK, + ppapi::HostResource /* video_decoder */, + int32_t /* PP_CompletionCallback result */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBVideoDecoder_ResetACK, + ppapi::HostResource /* video_decoder */, + int32_t /* PP_CompletionCallback result */) + +// PPP_VideoDecoder_Dev. +IPC_MESSAGE_ROUTED4(PpapiMsg_PPPVideoDecoder_ProvidePictureBuffers, + ppapi::HostResource /* video_decoder */, + uint32_t /* requested number of buffers */, + PP_Size /* dimensions of buffers */, + uint32_t /* texture_target */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPVideoDecoder_DismissPictureBuffer, + ppapi::HostResource /* video_decoder */, + int32_t /* picture buffer id */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPVideoDecoder_PictureReady, + ppapi::HostResource /* video_decoder */, + PP_Picture_Dev /* output picture */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPVideoDecoder_NotifyError, + ppapi::HostResource /* video_decoder */, + PP_VideoDecodeError_Dev /* error */) +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// ----------------------------------------------------------------------------- +// These are from the plugin to the renderer. + +// Reply to PpapiMsg_CreateChannel. The handle will be NULL if the channel +// could not be established. This could be because the IPC could not be created +// for some weird reason, but more likely that the plugin failed to load or +// initialize properly. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_ChannelCreated, + IPC::ChannelHandle /* handle */) + +// Logs the given message to the console of all instances. +IPC_MESSAGE_CONTROL4(PpapiHostMsg_LogWithSource, + PP_Instance /* instance */, + int /* log_level */, + std::string /* source */, + std::string /* value */) + +// PPB_Audio. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBAudio_Create, + PP_Instance /* instance_id */, + int32_t /* sample_rate */, + uint32_t /* sample_frame_count */, + ppapi::HostResource /* result */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBAudio_StartOrStop, + ppapi::HostResource /* audio_id */, + bool /* play */) + +// PPB_Core. +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBCore_AddRefResource, + ppapi::HostResource) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBCore_ReleaseResource, + ppapi::HostResource) + +// PPB_FileRef. +// TODO(teravest): Remove these messages when we've switched over to the "new" +// proxy. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFileRef_Create, + PP_Instance /* instance */, + PP_Resource /* file_system */, + std::string /* path */, + ppapi::PPB_FileRef_CreateInfo /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFileRef_GetParent, + ppapi::HostResource /* file_ref */, + ppapi::PPB_FileRef_CreateInfo /* result */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBFileRef_MakeDirectory, + ppapi::HostResource /* file_ref */, + PP_Bool /* make_ancestors */, + uint32_t /* callback_id */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBFileRef_Touch, + ppapi::HostResource /* file_ref */, + PP_Time /* last_access */, + PP_Time /* last_modified */, + uint32_t /* callback_id */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFileRef_Delete, + ppapi::HostResource /* file_ref */, + uint32_t /* callback_id */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBFileRef_Rename, + ppapi::HostResource /* file_ref */, + ppapi::HostResource /* new_file_ref */, + uint32_t /* callback_id */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFileRef_Query, + ppapi::HostResource /* file_ref */, + uint32_t /* callback_id */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFileRef_GetAbsolutePath, + ppapi::HostResource /* file_ref */, + ppapi::proxy::SerializedVar /* result */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFileRef_ReadDirectoryEntries, + ppapi::HostResource /* file_ref */, + uint32_t /* callback_id */) + +// PPB_Graphics3D. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBGraphics3D_Create, + PP_Instance /* instance */, + ppapi::HostResource /* share_context */, + std::vector<int32_t> /* attrib_list */, + ppapi::HostResource /* result */) +IPC_SYNC_MESSAGE_ROUTED2_0(PpapiHostMsg_PPBGraphics3D_SetGetBuffer, + ppapi::HostResource /* context */, + int32 /* transfer_buffer_id */) +IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBGraphics3D_GetState, + ppapi::HostResource /* context */, + gpu::CommandBuffer::State /* state */, + bool /* success */) +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiHostMsg_PPBGraphics3D_Flush, + ppapi::HostResource /* context */, + int32 /* put_offset */, + int32 /* last_known_get */, + gpu::CommandBuffer::State /* state */, + bool /* success */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBGraphics3D_AsyncFlush, + ppapi::HostResource /* context */, + int32 /* put_offset */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer, + ppapi::HostResource /* context */, + uint32 /* size */, + int32 /* id */) +IPC_SYNC_MESSAGE_ROUTED2_0(PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer, + ppapi::HostResource /* context */, + int32 /* id */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer, + ppapi::HostResource /* context */, + int32 /* id */, + ppapi::proxy::SerializedHandle /* transfer_buffer */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBGraphics3D_SwapBuffers, + ppapi::HostResource /* graphics_3d */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBGraphics3D_InsertSyncPoint, + ppapi::HostResource /* context */, + uint32 /* sync_point */) + +// PPB_ImageData. +IPC_SYNC_MESSAGE_ROUTED4_3(PpapiHostMsg_PPBImageData_CreatePlatform, + PP_Instance /* instance */, + int32 /* format */, + PP_Size /* size */, + PP_Bool /* init_to_zero */, + ppapi::HostResource /* result_resource */, + PP_ImageDataDesc /* image_data_desc */, + ppapi::proxy::ImageHandle /* result */) +IPC_SYNC_MESSAGE_ROUTED4_3(PpapiHostMsg_PPBImageData_CreateSimple, + PP_Instance /* instance */, + int32 /* format */, + PP_Size /* size */, + PP_Bool /* init_to_zero */, + ppapi::HostResource /* result_resource */, + PP_ImageDataDesc /* image_data_desc */, + ppapi::proxy::SerializedHandle /* result */) + +// PPB_Instance. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetWindowObject, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetOwnerElementObject, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* result */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBInstance_BindGraphics, + PP_Instance /* instance */, + PP_Resource /* device */) +IPC_SYNC_MESSAGE_ROUTED1_1( + PpapiHostMsg_PPBInstance_GetAudioHardwareOutputSampleRate, + PP_Instance /* instance */, + uint32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1( + PpapiHostMsg_PPBInstance_GetAudioHardwareOutputBufferSize, + PP_Instance /* instance */, + uint32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_IsFullFrame, + PP_Instance /* instance */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBInstance_ExecuteScript, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* script */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetDefaultCharSet, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBInstance_SetFullscreen, + PP_Instance /* instance */, + PP_Bool /* fullscreen */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBInstance_GetScreenSize, + PP_Instance /* instance */, + PP_Bool /* result */, + PP_Size /* size */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_RequestInputEvents, + PP_Instance /* instance */, + bool /* is_filtering */, + uint32_t /* event_classes */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBInstance_ClearInputEvents, + PP_Instance /* instance */, + uint32_t /* event_classes */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBInstance_PostMessage, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* message */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBInstance_LockMouse, + PP_Instance /* instance */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBInstance_UnlockMouse, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBInstance_ResolveRelativeToDocument, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* relative */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBInstance_DocumentCanRequest, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* relative */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBInstance_DocumentCanAccessDocument, + PP_Instance /* active */, + PP_Instance /* target */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBInstance_GetDocumentURL, + PP_Instance /* active */, + PP_URLComponents_Dev /* components */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetPluginInstanceURL, + PP_Instance /* active */, + ppapi::proxy::SerializedVar /* result */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBInstance_SetCursor, + PP_Instance /* instance */, + int32_t /* type */, + ppapi::HostResource /* custom_image */, + PP_Point /* hot_spot */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBInstance_SetTextInputType, + PP_Instance /* instance */, + PP_TextInput_Type /* type */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_UpdateCaretPosition, + PP_Instance /* instance */, + PP_Rect /* caret */, + PP_Rect /* bounding_box */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBInstance_CancelCompositionText, + PP_Instance /* instance */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBInstance_UpdateSurroundingText, + PP_Instance /* instance */, + std::string /* text */, + uint32_t /* caret */, + uint32_t /* anchor */) + +// PPB_Var. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBVar_AddRefObject, + int64 /* object_id */, + int /* unused - need a return value for sync msgs */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBVar_ReleaseObject, + int64 /* object_id */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_HasProperty, + ppapi::proxy::SerializedVar /* object */, + ppapi::proxy::SerializedVar /* property */, + ppapi::proxy::SerializedVar /* out_exception */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_HasMethodDeprecated, + ppapi::proxy::SerializedVar /* object */, + ppapi::proxy::SerializedVar /* method */, + ppapi::proxy::SerializedVar /* out_exception */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_GetProperty, + ppapi::proxy::SerializedVar /* object */, + ppapi::proxy::SerializedVar /* property */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_DeleteProperty, + ppapi::proxy::SerializedVar /* object */, + ppapi::proxy::SerializedVar /* property */, + ppapi::proxy::SerializedVar /* out_exception */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBVar_EnumerateProperties, + ppapi::proxy::SerializedVar /* object */, + std::vector<ppapi::proxy::SerializedVar> /* props */, + ppapi::proxy::SerializedVar /* out_exception */) +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBVar_SetPropertyDeprecated, + ppapi::proxy::SerializedVar /* object */, + ppapi::proxy::SerializedVar /* name */, + ppapi::proxy::SerializedVar /* value */, + ppapi::proxy::SerializedVar /* out_exception */) +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiHostMsg_PPBVar_CallDeprecated, + ppapi::proxy::SerializedVar /* object */, + ppapi::proxy::SerializedVar /* method_name */, + std::vector<ppapi::proxy::SerializedVar> /* args */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_Construct, + ppapi::proxy::SerializedVar /* object */, + std::vector<ppapi::proxy::SerializedVar> /* args */, + ppapi::proxy::SerializedVar /* out_exception */, + ppapi::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated, + ppapi::proxy::SerializedVar /* var */, + int64 /* object_class */, + int64 /* object-data */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBVar_CreateObjectDeprecated, + PP_Instance /* instance */, + int64 /* object_class */, + int64 /* object_data */, + ppapi::proxy::SerializedVar /* result */) + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +// PPB_Broker. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBBroker_Create, + PP_Instance /* instance */, + ppapi::HostResource /* result_resource */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBBroker_Connect, + ppapi::HostResource /* broker */) + +// PPB_Buffer. +IPC_SYNC_MESSAGE_ROUTED2_2( + PpapiHostMsg_PPBBuffer_Create, + PP_Instance /* instance */, + uint32_t /* size */, + ppapi::HostResource /* result_resource */, + ppapi::proxy::SerializedHandle /* result_shm_handle */) + +// PPB_ContentDecryptor_Dev messages handled in PPB_Instance_Proxy. +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBInstance_NeedKey, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* key_system, String */, + ppapi::proxy::SerializedVar /* session_id, String */, + ppapi::proxy::SerializedVar /* init_data, ArrayBuffer */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_KeyAdded, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* key_system, String */, + ppapi::proxy::SerializedVar /* session_id, String */) +IPC_MESSAGE_ROUTED5(PpapiHostMsg_PPBInstance_KeyMessage, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* key_system, String */, + ppapi::proxy::SerializedVar /* session_id, String */, + ppapi::proxy::SerializedVar /* message, ArrayBuffer */, + ppapi::proxy::SerializedVar /* default_url, String */) +IPC_MESSAGE_ROUTED5(PpapiHostMsg_PPBInstance_KeyError, + PP_Instance /* instance */, + ppapi::proxy::SerializedVar /* key_system, String */, + ppapi::proxy::SerializedVar /* session_id, String */, + int32_t /* media_error */, + int32_t /* system_code */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_DeliverBlock, + PP_Instance /* instance */, + PP_Resource /* decrypted_block, PPB_Buffer_Dev */, + std::string /* serialized_block_info */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBInstance_DecoderInitializeDone, + PP_Instance /* instance */, + PP_DecryptorStreamType /* decoder_type */, + uint32_t /* request_id */, + PP_Bool /* success */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_DecoderDeinitializeDone, + PP_Instance /* instance */, + PP_DecryptorStreamType /* decoder_type */, + uint32_t /* request_id */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_DecoderResetDone, + PP_Instance /* instance */, + PP_DecryptorStreamType /* decoder_type */, + uint32_t /* request_id */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_DeliverFrame, + PP_Instance /* instance */, + PP_Resource /* decrypted_frame, PPB_Buffer_Dev */, + std::string /* serialized_block_info */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_DeliverSamples, + PP_Instance /* instance */, + PP_Resource /* audio_frames, PPB_Buffer_Dev */, + std::string /* serialized_block_info */) +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// PPB_NetworkMonitor_Private. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBNetworkMonitor_Start, + uint32 /* plugin_dispatcher_id */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBNetworkMonitor_Stop, + uint32 /* plugin_dispatcher_id */) + +// PPB_Testing. +IPC_SYNC_MESSAGE_ROUTED3_1( + PpapiHostMsg_PPBTesting_ReadImageData, + ppapi::HostResource /* device_context_2d */, + ppapi::HostResource /* image */, + PP_Point /* top_left */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, + PP_Instance /* instance */, + uint32 /* result */) +IPC_SYNC_MESSAGE_ROUTED2_0(PpapiHostMsg_PPBTesting_SimulateInputEvent, + PP_Instance /* instance */, + ppapi::InputEventData /* input_event */) +IPC_SYNC_MESSAGE_ROUTED1_0( + PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem, + uint32_t /* threshold */) + +#if !defined(OS_NACL) && !defined(NACL_WIN64) + +// PPB_VideoDecoder. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBVideoDecoder_Create, + PP_Instance /* instance */, + ppapi::HostResource /* context */, + PP_VideoDecoder_Profile /* profile */, + ppapi::HostResource /* result */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBVideoDecoder_Decode, + ppapi::HostResource /* video_decoder */, + ppapi::HostResource /* bitstream buffer */, + int32 /* bitstream buffer id */, + uint32 /* size of buffer */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBVideoDecoder_AssignPictureBuffers, + ppapi::HostResource /* video_decoder */, + std::vector<PP_PictureBuffer_Dev> /* picture buffers */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBVideoDecoder_ReusePictureBuffer, + ppapi::HostResource /* video_decoder */, + int32_t /* picture buffer id */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBVideoDecoder_Flush, + ppapi::HostResource /* video_decoder */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBVideoDecoder_Reset, + ppapi::HostResource /* video_decoder */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBVideoDecoder_Destroy, + ppapi::HostResource /* video_decoder */) + +// PPB_Flash_MessageLoop. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFlashMessageLoop_Create, + PP_Instance /* instance */, + ppapi::HostResource /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFlashMessageLoop_Run, + ppapi::HostResource /* flash_message_loop */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBFlashMessageLoop_Quit, + ppapi::HostResource /* flash_message_loop */) +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// PPB_TCPSocket and PPB_TCPSocket_Private. +// Creates a PPB_TCPSocket resource. +IPC_SYNC_MESSAGE_CONTROL2_1(PpapiHostMsg_PPBTCPSocket_Create, + int32 /* routing_id */, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */) +// Creates a PPB_TCPSocket_Private resource. +IPC_SYNC_MESSAGE_CONTROL2_1(PpapiHostMsg_PPBTCPSocket_CreatePrivate, + int32 /* routing_id */, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */) +IPC_MESSAGE_CONTROL4(PpapiHostMsg_PPBTCPSocket_Connect, + int32 /* routing_id */, + uint32 /* socket_id */, + std::string /* host */, + uint16_t /* port */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress, + int32 /* routing_id */, + uint32 /* socket_id */, + PP_NetAddress_Private /* net_addr */) +IPC_MESSAGE_CONTROL5(PpapiHostMsg_PPBTCPSocket_SSLHandshake, + uint32 /* socket_id */, + std::string /* server_name */, + uint16_t /* server_port */, + std::vector<std::vector<char> > /* trusted_certs */, + std::vector<std::vector<char> > /* untrusted_certs */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBTCPSocket_Read, + uint32 /* socket_id */, + int32_t /* bytes_to_read */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBTCPSocket_Write, + uint32 /* socket_id */, + std::string /* data */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBTCPSocket_Disconnect, + uint32 /* socket_id */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_PPBTCPSocket_SetOption, + uint32 /* socket_id */, + PP_TCPSocket_Option /* name */, + ppapi::SocketOptionData /* value */) + +// PPB_X509Certificate_Private +IPC_SYNC_MESSAGE_CONTROL1_2(PpapiHostMsg_PPBX509Certificate_ParseDER, + std::vector<char> /* der */, + bool /* succeeded */, + ppapi::PPB_X509Certificate_Fields /* result */) + +//----------------------------------------------------------------------------- +// Resource call/reply messages. +// +// These are the new-style resource implementations where the resource is only +// implemented in the proxy and "resource messages" are sent between this and a +// host object. Resource messages are a wrapper around some general routing +// information and a separate message of a type defined by the specific resource +// sending/receiving it. The extra paremeters allow the nested message to be +// routed automatically to the correct resource. + +// Notification that a resource has been created in the plugin. The nested +// message will be resource-type-specific. +IPC_MESSAGE_CONTROL3(PpapiHostMsg_ResourceCreated, + ppapi::proxy::ResourceMessageCallParams /* call_params */, + PP_Instance /* instance */, + IPC::Message /* nested_msg */) + +// Notification that a resource has been destroyed in the plugin. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_ResourceDestroyed, + PP_Resource /* resource */) + +// Most resources are created by the plugin, which then sends a ResourceCreated +// message to create a corresponding ResourceHost in the renderer or browser +// host process. However, some resources are first created in the host and +// "pushed" or returned to the plugin. +// +// In this case, the host will create a "pending" ResourceHost object which +// is identified by an ID. The ID is sent to the plugin process and the +// PluginResource object is created. This message is sent from the plugin to +// the host process to connect the PluginResource and the pending ResourceHost +// (at which point, it's no longer pending). +IPC_MESSAGE_CONTROL2(PpapiHostMsg_AttachToPendingHost, + PP_Resource /* resource */, + int /* pending_host_id */) + +// A resource call is a request from the plugin to the host. It may or may not +// require a reply, depending on the params. The nested message will be +// resource-type-specific. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_ResourceCall, + ppapi::proxy::ResourceMessageCallParams /* call_params */, + IPC::Message /* nested_msg */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_InProcessResourceCall, + int /* routing_id */, + ppapi::proxy::ResourceMessageCallParams /* call_params */, + IPC::Message /* nested_msg */) + +// A resource reply is a response to a ResourceCall from a host to the +// plugin. The resource ID + sequence number in the params will correspond to +// that of the previous ResourceCall. +IPC_MESSAGE_CONTROL2( + PpapiPluginMsg_ResourceReply, + ppapi::proxy::ResourceMessageReplyParams /* reply_params */, + IPC::Message /* nested_msg */) +IPC_MESSAGE_ROUTED2( + PpapiHostMsg_InProcessResourceReply, + ppapi::proxy::ResourceMessageReplyParams /* reply_params */, + IPC::Message /* nested_msg */) + + +IPC_SYNC_MESSAGE_CONTROL2_2(PpapiHostMsg_ResourceSyncCall, + ppapi::proxy::ResourceMessageCallParams /* call_params */, + IPC::Message /* nested_msg */, + ppapi::proxy::ResourceMessageReplyParams /* reply_params */, + IPC::Message /* reply_msg */) + +// This message is sent from the renderer to the browser when it wants to create +// a ResourceHost in the browser. It contains the process ID of the plugin and +// the instance of the plugin for which to create the resource for. params +// contains the sequence number for the message to track the response. +// The nested message is a ResourceHost creation message. +IPC_MESSAGE_CONTROL5( + PpapiHostMsg_CreateResourceHostFromHost, + int /* routing_id */, + int /* child_process_id */, + ppapi::proxy::ResourceMessageCallParams /* params */, + PP_Instance /* instance */, + IPC::Message /* nested_msg */) + +// This message is sent from the browser to the renderer when it has created a +// ResourceHost for the renderer. It contains the sequence number that was sent +// in the request and the ID of the pending ResourceHost which was created in +// the browser. This ID is only useful for the plugin which can attach to the +// ResourceHost in the browser. +IPC_MESSAGE_ROUTED2( + PpapiHostMsg_CreateResourceHostFromHostReply, + int32_t /* sequence */, + int /* pending_host_id */) + +//----------------------------------------------------------------------------- +// Messages for resources using call/reply above. + +// Broker ---------------------------------------------------------------------- +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Broker_Create) + +// Queries whether the plugin has permission to connect to the Pepper broker. +// The response is contained in the error value of the +// ResourceMessageReplyParams in the reply message. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Broker_IsAllowed) + +// Extensions common ----------------------------------------------------------- +IPC_MESSAGE_CONTROL0(PpapiHostMsg_ExtensionsCommon_Create) + +// Starts an extension API request which doesn't expect a response. +// |request_name| is an API function name. |args| is a list of input arguments. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_ExtensionsCommon_Post, + std::string /* request_name */, + base::ListValue /* args */) + +// Starts an extension API request which expects a response sent back using a +// PpapiPluginMsg_ExtensionsCommon_CallReply message. +// |request_name| is an API function name. |args| is a list of input arguments. +// |output| is a list of output results. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_ExtensionsCommon_Call, + std::string /* request_name */, + base::ListValue /* args */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_ExtensionsCommon_CallReply, + base::ListValue /* output */) + +// Ext_CrxFileSystem +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Ext_CrxFileSystem_Create) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Ext_CrxFileSystem_BrowserOpen) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Ext_CrxFileSystem_BrowserOpenReply, + std::string /* fsid */) + +// File chooser. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileChooser_Create) +IPC_MESSAGE_CONTROL4(PpapiHostMsg_FileChooser_Show, + bool /* save_as */, + bool /* open_multiple */, + std::string /* suggested_file_name */, + std::vector<std::string> /* accept_mime_types */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FileChooser_ShowReply, + std::vector<ppapi::PPB_FileRef_CreateInfo> /* files */) + +// FileIO +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileIO_Create) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FileIO_Open, + PP_Resource /* file_ref_resource */, + int32_t /* open_flags */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileIO_OpenReply) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileIO_Close) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FileIO_Touch, + PP_Time /* last_access_time */, + PP_Time /* last_modified_time */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FileIO_Write, + int64_t /* offset */, + std::string /* data */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileIO_SetLength, + int64_t /* length */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileIO_Flush) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FileIO_WillWrite, + int64_t /* offset */, + int32_t /* bytes_to_write */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileIO_WillSetLength, + int64_t /* length */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileIO_GetOSFileDescriptor) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FileIO_GetOSFileDescriptorReply, + int32_t /* file descriptor */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileIO_RequestOSFileHandle) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileIO_RequestOSFileHandleReply) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileIO_GeneralReply) + +// FileRef +// Creates a FileRef to a path on an external file system. This message may +// only be sent from the renderer. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileRef_CreateExternal, + base::FilePath /* external_path */) + +// Creates a FileRef to a path on an internal file system. This message may +// be sent from the renderer or the plugin. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FileRef_CreateInternal, + PP_Resource /* file_system */, + std::string /* internal_path */) + +// Requests that the browser create a directory at the location indicated by +// the FileRef. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileRef_MakeDirectory, + bool /* make_ancestors */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileRef_MakeDirectoryReply) + +// Requests that the browser update the last accessed and last modified times +// at the location indicated by the FileRef. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FileRef_Touch, + PP_Time /* last_accessed */, + PP_Time /* last_modified */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileRef_TouchReply) + +// Requests that the browser delete a file or directory at the location +// indicated by the FileRef. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileRef_Delete) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileRef_DeleteReply) + +// Requests that the browser rename a file or directory at the location +// indicated by the FileRef. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileRef_Rename, + PP_Resource /* new_file_ref */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileRef_RenameReply) + +// Requests that the browser retrieve metadata information for a file or +// directory at the location indicated by the FileRef. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileRef_Query) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FileRef_QueryReply, + PP_FileInfo /* file_info */) + +// Requests that the browser retrieve then entries in a directory at the +// location indicated by the FileRef. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileRef_ReadDirectoryEntries) + +// FileRef_CreateInfo does not provide file type information, so two +// corresponding vectors are returned. +IPC_MESSAGE_CONTROL2(PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply, + std::vector<ppapi::FileRef_CreateInfo> /* files */, + std::vector<PP_FileType> /* file_types */) + +// Requests that the browser reply with the absolute path to the indicated +// file. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FileRef_GetAbsolutePath) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FileRef_GetAbsolutePathReply, + std::string /* absolute_path */) + +// FileSystem +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileSystem_Create, + PP_FileSystemType /* type */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileSystem_Open, + int64_t /* expected_size */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_FileSystem_OpenReply) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FileSystem_InitIsolatedFileSystem, + std::string /* fsid */) + +// Flash DRM ------------------------------------------------------------------ +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDRM_Create) + +// Requests the device ID. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDRM_GetDeviceID) +// Reply for GetDeviceID which includes the device ID as a string. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashDRM_GetDeviceIDReply, + std::string /* id */) + +// Requests the HMONITOR corresponding to the monitor on which the instance is +// displayed. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDRM_GetHmonitor) +// Reply message for GetHmonitor which contains the HMONITOR as an int64_t. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashDRM_GetHmonitorReply, + int64_t /* hmonitor */) + +// Requests the voucher file which is used to verify the integrity of the Flash +// module. A PPB_FileRef resource will be created. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashDRM_GetVoucherFile) +// Reply message for GetVoucherFile which contains the CreateInfo for a +// PPB_FileRef which points to the voucher file. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashDRM_GetVoucherFileReply, + ppapi::PPB_FileRef_CreateInfo /* file_info */) + +// Gamepad. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Gamepad_Create) + +// Requests that the gamepad host send the shared memory handle to the plugin +// process. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Gamepad_RequestMemory) + +// Reply to a RequestMemory call. This supplies the shared memory handle. The +// actual handle is passed in the ReplyParams struct. +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Gamepad_SendMemory) + + +// Graphics2D, plugin -> host +IPC_MESSAGE_CONTROL2(PpapiHostMsg_Graphics2D_Create, + PP_Size /* size */, + PP_Bool /* is_always_opaque */) +IPC_MESSAGE_CONTROL4(PpapiHostMsg_Graphics2D_PaintImageData, + ppapi::HostResource /* image_data */, + PP_Point /* top_left */, + bool /* src_rect_specified */, + PP_Rect /* src_rect */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_Graphics2D_Scroll, + bool /* clip_specified */, + PP_Rect /* clip */, + PP_Point /* amount */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Graphics2D_ReplaceContents, + ppapi::HostResource /* image_data */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Graphics2D_Dev_SetScale, + float /* scale */) + +// Graphics2D, plugin -> host -> plugin +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Graphics2D_Flush) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Graphics2D_FlushAck) + +IPC_MESSAGE_CONTROL2(PpapiHostMsg_Graphics2D_ReadImageData, + PP_Resource /* image */, + PP_Point /* top_left */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Graphics2D_ReadImageDataAck) + +// NetworkProxy ---------------------------------------------------------------- +IPC_MESSAGE_CONTROL0(PpapiHostMsg_NetworkProxy_Create) + +// Query the browser for the proxy server to use for the given URL. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_NetworkProxy_GetProxyForURL, + std::string /* url */) + +// Reply message for GetProxyForURL containing the proxy server. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_NetworkProxy_GetProxyForURLReply, + std::string /* proxy */) + +// TrueTypeFont. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_TrueTypeFontSingleton_Create) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_TrueTypeFontSingleton_GetFontFamilies) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TrueTypeFontSingleton_GetFontFamiliesReply, + std::vector<std::string> /* font_families */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_TrueTypeFontSingleton_GetFontsInFamily, + std::string /* family */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TrueTypeFontSingleton_GetFontsInFamilyReply, + std::vector<ppapi::proxy::SerializedTrueTypeFontDesc> + /* fonts */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_TrueTypeFont_Create, + ppapi::proxy::SerializedTrueTypeFontDesc /* desc */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_TrueTypeFont_Describe) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TrueTypeFont_DescribeReply, + ppapi::proxy::SerializedTrueTypeFontDesc /* desc */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_TrueTypeFont_GetTableTags) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TrueTypeFont_GetTableTagsReply, + std::vector<uint32_t> /* tags */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_TrueTypeFont_GetTable, + uint32_t /* table */, + int32_t /* offset */, + int32_t /* max_data_length */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TrueTypeFont_GetTableReply, + std::string /* data */) + +// Host Resolver --------------------------------------------------------------- +// Creates a PPB_HostResolver resource. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_HostResolver_Create) + +// Creates a PPB_HostResolver_Private resource. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_HostResolver_CreatePrivate) + +// Resolves the given hostname. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_HostResolver_Resolve, + ppapi::HostPortPair /* host_port */, + PP_HostResolver_Private_Hint /* hint */) + +// This message is a reply to HostResolver_Resolve. On success, +// |canonical_name| contains the canonical name of the host; |net_address_list| +// is a list of network addresses. On failure, both fields are set to empty. +IPC_MESSAGE_CONTROL2(PpapiPluginMsg_HostResolver_ResolveReply, + std::string /* canonical_name */, + std::vector<PP_NetAddress_Private> /* net_address_list */) + +// Printing. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_Create) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_GetDefaultPrintSettings) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply, + PP_PrintSettings_Dev /* print_settings */) + +// TCP Server Socket ----------------------------------------------------------- +// Creates a PPB_TCPServerSocket_Private resource. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPServerSocket_CreatePrivate) + +IPC_MESSAGE_CONTROL2(PpapiHostMsg_TCPServerSocket_Listen, + PP_NetAddress_Private /* addr */, + int32_t /* backlog */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TCPServerSocket_ListenReply, + PP_NetAddress_Private /* local_addr */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_TCPServerSocket_Accept, + uint32 /* plugin_dispatcher_id */) +IPC_MESSAGE_CONTROL3(PpapiPluginMsg_TCPServerSocket_AcceptReply, + uint32 /* accepted_socket_id */, + PP_NetAddress_Private /* local_addr */, + PP_NetAddress_Private /* remote_addr */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPServerSocket_StopListening) + +// UDP Socket ------------------------------------------------------------------ +// Creates a PPB_UDPSocket resource. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_UDPSocket_Create) + +// Creates a PPB_UDPSocket_Private resource. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_UDPSocket_CreatePrivate) + +IPC_MESSAGE_CONTROL2(PpapiHostMsg_UDPSocket_SetOption, + PP_UDPSocket_Option /* name */, + ppapi::SocketOptionData /* value */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_UDPSocket_SetOptionReply) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_UDPSocket_Bind, + PP_NetAddress_Private /* net_addr */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_UDPSocket_BindReply, + PP_NetAddress_Private /* bound_addr */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_UDPSocket_RecvFrom, + int32_t /* num_bytes */) +IPC_MESSAGE_CONTROL2(PpapiPluginMsg_UDPSocket_RecvFromReply, + std::string /* data */, + PP_NetAddress_Private /* remote_addr */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_UDPSocket_SendTo, + std::string /* data */, + PP_NetAddress_Private /* net_addr */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_UDPSocket_SendToReply, + int32_t /* bytes_written */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_UDPSocket_Close) + +// URLLoader ------------------------------------------------------------------ + +IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_Create) + +// These messages correspond to PPAPI calls and all should get a +// CallbackComplete message. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_URLLoader_Open, + ppapi::URLRequestInfoData /* request_data */) + +// The plugin can tell the host to defer a load to hold off on sending more +// data because the buffer in the plugin is full. When defers_loading is set to +// false, data streaming will resume. +// +// When auditing redirects (no auto follow) the load will be automatically +// deferred each time we get a redirect. The plugin will reset this to false +// by sending this message when it wants to continue following the redirect. +// +// When streaming data, the host may still send more data after this call (for +// example, it could already be in-flight at the time of this request). +IPC_MESSAGE_CONTROL1(PpapiHostMsg_URLLoader_SetDeferLoading, + bool /* defers_loading */) + +// Closes the URLLoader. There is no reply. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_Close) + +// Requests that cross-site restrictions be ignored. The plugin must have +// the private permission set. Otherwise this message will be ignored by the +// renderer. There is no reply. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_GrantUniversalAccess) + +// Push notification that a response is available. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_URLLoader_ReceivedResponse, + ppapi::URLResponseInfoData /* response */) + +// Push notification with load data from the renderer. It is a custom generated +// message with the response data (array of bytes stored via WriteData) +// appended. +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_URLLoader_SendData) + +// Push notification indicating that all data has been sent, either via +// SendData or by streaming it to a file. Note that since this is a push +// notification, we don't use the result field of the ResourceMessageReply. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_URLLoader_FinishedLoading, + int32_t /* result */) + +// Push notification from the renderer to the plugin to tell it about download +// and upload progress. This will only be sent if the plugin has requested +// progress updates, and only the fields requested by the plugin will be +// valid. +IPC_MESSAGE_CONTROL4(PpapiPluginMsg_URLLoader_UpdateProgress, + int64_t /* bytes_sent */, + int64_t /* total_bytes_to_be_sent */, + int64_t /* bytes_received */, + int64_t /* total_bytes_to_be_received */) + +// Shared memory --------------------------------------------------------------- + +// Creates shared memory on the host side, returning a handle to the shared +// memory on the plugin and keeping the memory mapped in on the host. +// We return a "host handle_id" that can be mapped back to the +// handle on the host side by PpapiGlobals::UntrackSharedMemoryHandle(). +IPC_SYNC_MESSAGE_CONTROL2_2(PpapiHostMsg_SharedMemory_CreateSharedMemory, + PP_Instance /* instance */, + uint32_t /* size */, + int /* host_handle_id */, + ppapi::proxy::SerializedHandle /* plugin_handle */) + +// MediaStream ----------------------------------------------------------------- + +// VideoDestination Private. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoDestination_Create) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_VideoDestination_Open, + std::string /* stream_url */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_VideoDestination_OpenReply) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_VideoDestination_PutFrame, + ppapi::HostResource /* image_data */, + PP_TimeTicks /* timestamp */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoDestination_Close) + +// VideoSource Private. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoSource_Create) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_VideoSource_Open, + std::string /* stream_url */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_VideoSource_OpenReply) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoSource_GetFrame) +IPC_MESSAGE_CONTROL3(PpapiPluginMsg_VideoSource_GetFrameReply, + ppapi::HostResource /* resource_id */, + PP_ImageDataDesc /* image_data_desc */, + PP_TimeTicks /* timestamp */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoSource_Close) + +// WebSocket ------------------------------------------------------------------- + +IPC_MESSAGE_CONTROL0(PpapiHostMsg_WebSocket_Create) + +// Establishes the connection to a server. This message requires +// WebSocket_ConnectReply as a reply message. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_WebSocket_Connect, + std::string /* url */, + std::vector<std::string> /* protocols */) + +// Closes established connection with graceful closing handshake. This message +// requires WebSocket_CloseReply as a reply message. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_WebSocket_Close, + int32_t /* code */, + std::string /* reason */) + +// Sends a text frame to the server. No reply is defined. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_WebSocket_SendText, + std::string /* message */) + +// Sends a binary frame to the server. No reply is defined. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_WebSocket_SendBinary, + std::vector<uint8_t> /* message */) + +// Fails the connection. This message invokes RFC6455 defined +// _Fail the WebSocket Connection_ operation. No reply is defined. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_WebSocket_Fail, + std::string /* message */) + +// This message is a reply to WebSocket_Connect. If the |url| and |protocols| +// are invalid, WebSocket_ConnectReply is issued immediately and it contains +// proper error code in its result. Otherwise, WebSocket_ConnectReply is sent +// with valid |url|, |protocol|, and result PP_OK. |protocol| is not a passed +// |protocols|, but a result of opening handshake negotiation. If the +// connection can not be established successfully, WebSocket_ConnectReply is +// not issued, but WebSocket_ClosedReply is sent instead. +IPC_MESSAGE_CONTROL2(PpapiPluginMsg_WebSocket_ConnectReply, + std::string /* url */, + std::string /* protocol */) + +// This message is a reply to WebSocket_Close. If the operation fails, +// WebSocket_CloseReply is issued immediately and it contains PP_ERROR_FAILED. +// Otherwise, CloseReply will be issued after the closing handshake is +// finished. All arguments will be valid iff the result is PP_OK and it means +// that the client initiated closing handshake is finished gracefully. +IPC_MESSAGE_CONTROL4(PpapiPluginMsg_WebSocket_CloseReply, + uint64_t /* buffered_amount */, + bool /* was_clean */, + uint16_t /* code */, + std::string /* reason */) + +// Unsolicited reply message to transmit a receiving text frame. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_ReceiveTextReply, + std::string /* message */) + +// Unsolicited reply message to transmit a receiving binary frame. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_ReceiveBinaryReply, + std::vector<uint8_t> /* message */) + +// Unsolicited reply message to notify a error on underlying network connetion. +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_WebSocket_ErrorReply) + +// Unsolicited reply message to update the buffered amount value. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_BufferedAmountReply, + uint64_t /* buffered_amount */) + +// Unsolicited reply message to update |state| because of incoming external +// events, e.g., protocol error, or unexpected network closure. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_StateReply, + int32_t /* state */) + +// Unsolicited reply message to notify that the connection is closed without +// any WebSocket_Close request. Server initiated closing handshake or +// unexpected network errors will invoke this message. +IPC_MESSAGE_CONTROL4(PpapiPluginMsg_WebSocket_ClosedReply, + uint64_t /* buffered_amount */, + bool /* was_clean */, + uint16_t /* code */, + std::string /* reason */) + +#if !defined(OS_NACL) && !defined(NACL_WIN64) + +// Audio input. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_AudioInput_Create) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_AudioInput_Open, + std::string /* device_id */, + PP_AudioSampleRate /* sample_rate */, + uint32_t /* sample_frame_count */) +// Reply to an Open call. This supplies a socket handle and a shared memory +// handle. Both handles are passed in the ReplyParams struct. +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_AudioInput_OpenReply) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_AudioInput_StartOrStop, bool /* capture */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_AudioInput_Close) + +// BrowserFont ----------------------------------------------------------------- + +IPC_MESSAGE_CONTROL0(PpapiHostMsg_BrowserFontSingleton_Create) + +// Requests that the browser reply with the list of font families via +// PpapiPluginMsg_BrowserFontSingleton_GetFontFamiliesReply. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_BrowserFontSingleton_GetFontFamilies) + +// Reply to PpapiHostMsg_BrowserFontSingleton_GetFontFamilies with the font +// family list. The |families| result is encoded by separating each family name +// by a null character. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_BrowserFontSingleton_GetFontFamiliesReply, + std::string /* families */) + +// FileRef. +// Requests that the browser reply with file system and path information about +// the resource indicated in |params| which exists in the given +// |child_process_id|. |routing_id| is sent so that the reply can be routed +// properly in the renderer. +// Only sent from the renderer to the browser. +IPC_MESSAGE_CONTROL4(PpapiHostMsg_FileRef_GetInfoForRenderer, + int /* routing_id */, + int /* child_process_id */, + int32_t /* sequence */, + std::vector<PP_Resource> /* resources */) + +// Reply to PpapiHostMsg_FileRef_GetInfoForRenderer with a sequence number for +// invoking the right callback, |fs_type| which indicates the file system, and +// path information in either |file_system_url_spec| (for internal file systems) +// or |external_path| (for external file systems). +// Only sent from the browser to the renderer. +IPC_MESSAGE_ROUTED5(PpapiHostMsg_FileRef_GetInfoForRendererReply, + int32_t /* sequence */, + std::vector<PP_Resource> /* resources */, + std::vector<PP_FileSystemType> /* fs_type */, + std::vector<std::string> /* file_system_url_spec */, + std::vector<base::FilePath> /* external_path */) + +// Flash ----------------------------------------------------------------------- + +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Flash_Create) + +// Message to notify the browser to register an update in system activity. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Flash_UpdateActivity) + +// Query the browser for the proxy server to use for the given URL. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Flash_GetProxyForURL, std::string /* url */) +// Reply message for GetProxyForURL containing the proxy server. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Flash_GetProxyForURLReply, + std::string /* proxy */) + +// Queries the browser for the local time zone offset for a given time. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Flash_GetLocalTimeZoneOffset, + base::Time /* time */) +// Reply to GetLocalTimeZoneOffset containing the time zone offset as a double. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply, + double /* offset */) + +// Query the browser for the restrictions on storing Flash LSOs. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Flash_GetLocalDataRestrictions) +// Reply message for GetLocalDataRestrictions containing the restrictions to +// use. These are PP_FlashLSORestrictions cast to an int32_t. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Flash_GetLocalDataRestrictionsReply, + int32_t /* restrictions */) + +// Notifies the renderer whether the Flash instance is in windowed mode. No +// reply is sent. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Flash_SetInstanceAlwaysOnTop, + bool /* on_top */) + +// Notifies the renderer to draw text to the given PP_ImageData resource. All +// parmeters for drawing (including the resource to draw to) are contianed in +// the PPBFlash_DrawGlyphs_Params structure. An error code is sent in a reply +// message indicating success. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Flash_DrawGlyphs, + ppapi::proxy::PPBFlash_DrawGlyphs_Params /* params */) + +// Notifies the renderer to navigate to the given URL contained in the +// URLRequestInfoData. An error code is sent in a reply message indicating +// success. +IPC_MESSAGE_CONTROL3(PpapiHostMsg_Flash_Navigate, + ppapi::URLRequestInfoData /* data */, + std::string /* target */, + bool /* from_user_action */) + +// Queries the renderer on whether the plugin instance is the topmost element +// in the area of the instance specified by the given PP_Rect. PP_OK is sent as +// the error code in a reply message if the rect is topmost otherwise +// PP_ERROR_FAILED is sent. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Flash_IsRectTopmost, + PP_Rect /* rect */) + +// Notifies the renderer to invoke printing for the given plugin instance. No +// reply is sent. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Flash_InvokePrinting) + +// DeviceEnumeration ----------------------------------------------------------- +// Device enumeration messages used by audio input and video capture. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_DeviceEnumeration_EnumerateDevices) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_DeviceEnumeration_EnumerateDevicesReply, + std::vector<ppapi::DeviceRefData> /* devices */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_DeviceEnumeration_MonitorDeviceChange, + uint32_t /* callback_id */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_DeviceEnumeration_StopMonitoringDeviceChange) +IPC_MESSAGE_CONTROL2(PpapiPluginMsg_DeviceEnumeration_NotifyDeviceChange, + uint32_t /* callback_id */, + std::vector<ppapi::DeviceRefData> /* devices */) + +// Flash clipboard. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashClipboard_Create) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashClipboard_RegisterCustomFormat, + std::string /* format_name */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply, + uint32_t /* format */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FlashClipboard_IsFormatAvailable, + uint32_t /* clipboard_type */, + uint32_t /* format */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FlashClipboard_ReadData, + uint32_t /* clipboard_type */, + uint32_t /* format */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashClipboard_ReadDataReply, + std::string /* result */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_FlashClipboard_WriteData, + uint32_t /* clipboard_type */, + std::vector<uint32_t> /* formats */, + std::vector<std::string> /* data */) + +// Flash file. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashFile_Create) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FlashFile_OpenFile, + ppapi::PepperFilePath /* path */, + int /* pp_open_flags */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FlashFile_RenameFile, + ppapi::PepperFilePath /* from_path */, + ppapi::PepperFilePath /* to_path */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FlashFile_DeleteFileOrDir, + ppapi::PepperFilePath /* path */, + bool /* recursive */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashFile_CreateDir, + ppapi::PepperFilePath /* path */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashFile_QueryFile, + ppapi::PepperFilePath /* path */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashFile_QueryFileReply, + base::PlatformFileInfo /* file_info */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashFile_GetDirContents, + ppapi::PepperFilePath /* path */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashFile_GetDirContentsReply, + ppapi::DirContents /* entries */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashFile_CreateTemporaryFile) + +// Flash font file. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_FlashFontFile_Create, + ppapi::proxy::SerializedFontDescription /* description */, + PP_PrivateFontCharset /* charset */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashFontFile_GetFontTable, + uint32_t /* table */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashFontFile_GetFontTableReply, + std::string /* output */) + +// Flash fullscreen. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_FlashFullscreen_Create) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashFullscreen_SetFullscreen, + bool /* fullscreen */) + +// FlashMenu ------------------------------------------------------------------ + +// Creates the flash menu with the given data. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashMenu_Create, + ppapi::proxy::SerializedFlashMenu /* menu_data */) + +// Shows the menu at the given location relative to the plugin instance. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_FlashMenu_Show, + PP_Point /* location */) + +// Reply to a show command. If the resource reply is PP_OK, the selected_id +// will be the menu item ID chosen by the user. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashMenu_ShowReply, + int32_t /* selected_id */) + +// PDF ------------------------------------------------------------------------ + +// Creates the PDF resource. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_PDF_Create) + +// Requests the localized string for the given ID. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PDF_GetLocalizedString, + PP_ResourceString /* string_id */) +// Reply for PpapiHostMsg_PDF_GetLocalizedString containing the localized +// string. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_PDF_GetLocalizedStringReply, + std::string /* localized_string*/) + +// Notifies the renderer that the PDF started loading. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_PDF_DidStartLoading) + +// Notifies the renderer that the PDF stopped loading. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_PDF_DidStopLoading) + +// Sets any restrictions on the PDF content. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PDF_SetContentRestriction, + int /* restrictions */) + +// Requests that the specified action be recorded with UMA. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PDF_UserMetricsRecordAction, + std::string /* action */) + +// Notifies the renderer that the current PDF uses an unsupported feature. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_PDF_HasUnsupportedFeature) + +// Notifies the renderer to print the current PDF. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_PDF_Print) + +// Notifies the renderer to save the current PDF. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_PDF_SaveAs) + +// Requests a resource image for the plugin at a particular scale. +IPC_MESSAGE_CONTROL2(PpapiHostMsg_PDF_GetResourceImage, + PP_ResourceImage /* image_id */, + float /* scale */) + +// Reply for PpapiHostMsg_PDF_GetResourceImage containing the host resource id +// of the image and a PP_ImageDataDesc which describes the image. Also carries +// a shared memory handle pointing to the memory containg the image. +IPC_MESSAGE_CONTROL2(PpapiPluginMsg_PDF_GetResourceImageReply, + ppapi::HostResource /* resource_id */, + PP_ImageDataDesc /* image_data_desc */) + +// VideoCapture_Dev, plugin -> host +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoCapture_Create) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoCapture_StartCapture) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_VideoCapture_ReuseBuffer, + uint32_t /* buffer */) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoCapture_StopCapture) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_VideoCapture_Close) + +// VideoCapture_Dev, plugin -> host -> plugin +IPC_MESSAGE_CONTROL3(PpapiHostMsg_VideoCapture_Open, + std::string /* device_id */, + PP_VideoCaptureDeviceInfo_Dev /* requested_info */, + uint32_t /* buffer_count */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_VideoCapture_OpenReply) + +// VideoCapture_Dev, host -> plugin +IPC_MESSAGE_CONTROL3(PpapiPluginMsg_VideoCapture_OnDeviceInfo, + PP_VideoCaptureDeviceInfo_Dev /* info */, + std::vector<ppapi::HostResource> /* buffers */, + uint32_t /* buffer_size */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_VideoCapture_OnStatus, + uint32_t /* status */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_VideoCapture_OnError, + uint32_t /* error */) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_VideoCapture_OnBufferReady, + uint32_t /* buffer */) + +// Talk ------------------------------------------------------------------------ + +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Talk_Create) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_Talk_RequestPermission, + PP_TalkPermission /* permission */) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Talk_RequestPermissionReply) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Talk_StartRemoting) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Talk_StartRemotingReply) +IPC_MESSAGE_CONTROL0(PpapiHostMsg_Talk_StopRemoting) +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Talk_StopRemotingReply) +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Talk_NotifyEvent, PP_TalkEvent /* event */) + +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) diff --git a/chromium/ppapi/proxy/ppapi_param_traits.cc b/chromium/ppapi/proxy/ppapi_param_traits.cc new file mode 100644 index 00000000000..ca25f82f257 --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_param_traits.cc @@ -0,0 +1,740 @@ +// 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 "ppapi/proxy/ppapi_param_traits.h" + +#include <string.h> // For memcpy + +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/proxy/serialized_flash_menu.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" + +namespace IPC { + +namespace { + +// Deserializes a vector from IPC. This special version must be used instead +// of the default IPC version when the vector contains a SerializedVar, either +// directly or indirectly (i.e. a vector of objects that have a SerializedVar +// inside them). +// +// The default vector deserializer does resize and then we deserialize into +// those allocated slots. However, the implementation of vector (at least in +// GCC's implementation), creates a new empty object using the default +// constructor, and then sets the rest of the items to that empty one using the +// copy constructor. +// +// Since we allocate the inner class when you call the default constructor and +// transfer the inner class when you do operator=, the entire vector will end +// up referring to the same inner class. Deserializing into this will just end +// up overwriting the same item over and over, since all the SerializedVars +// will refer to the same thing. +// +// The solution is to make a new object for each deserialized item, and then +// add it to the vector one at a time. +template<typename T> +bool ReadVectorWithoutCopy(const Message* m, + PickleIterator* iter, + std::vector<T>* output) { + // This part is just a copy of the the default ParamTraits vector Read(). + int size; + // ReadLength() checks for < 0 itself. + if (!m->ReadLength(iter, &size)) + return false; + // Resizing beforehand is not safe, see BUG 1006367 for details. + if (INT_MAX / sizeof(T) <= static_cast<size_t>(size)) + return false; + + output->reserve(size); + for (int i = 0; i < size; i++) { + T cur; + if (!ReadParam(m, iter, &cur)) + return false; + output->push_back(cur); + } + return true; +} + +// This serializes the vector of items to the IPC message in exactly the same +// way as the "regular" IPC vector serializer does. But having the code here +// saves us from having to copy this code into all ParamTraits that use the +// ReadVectorWithoutCopy function for deserializing. +template<typename T> +void WriteVectorWithoutCopy(Message* m, const std::vector<T>& p) { + WriteParam(m, static_cast<int>(p.size())); + for (size_t i = 0; i < p.size(); i++) + WriteParam(m, p[i]); +} + +} // namespace + +// PP_Bool --------------------------------------------------------------------- + +// static +void ParamTraits<PP_Bool>::Write(Message* m, const param_type& p) { + ParamTraits<bool>::Write(m, PP_ToBool(p)); +} + +// static +bool ParamTraits<PP_Bool>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + // We specifically want to be strict here about what types of input we accept, + // which ParamTraits<bool> does for us. We don't want to deserialize "2" into + // a PP_Bool, for example. + bool result = false; + if (!ParamTraits<bool>::Read(m, iter, &result)) + return false; + *r = PP_FromBool(result); + return true; +} + +// static +void ParamTraits<PP_Bool>::Log(const param_type& p, std::string* l) { +} + +// PP_FileInfo ------------------------------------------------------------- + +// static +void ParamTraits<PP_FileInfo>::Write(Message* m, const param_type& p) { + ParamTraits<int64_t>::Write(m, p.size); + ParamTraits<int>::Write(m, static_cast<int>(p.type)); + ParamTraits<int>::Write(m, static_cast<int>(p.system_type)); + ParamTraits<double>::Write(m, p.creation_time); + ParamTraits<double>::Write(m, p.last_access_time); + ParamTraits<double>::Write(m, p.last_modified_time); +} + +// static +bool ParamTraits<PP_FileInfo>::Read(const Message* m, PickleIterator* iter, + param_type* r) { + int type, system_type; + if (!ParamTraits<int64_t>::Read(m, iter, &r->size) || + !ParamTraits<int>::Read(m, iter, &type) || + !ParamTraits<int>::Read(m, iter, &system_type) || + !ParamTraits<double>::Read(m, iter, &r->creation_time) || + !ParamTraits<double>::Read(m, iter, &r->last_access_time) || + !ParamTraits<double>::Read(m, iter, &r->last_modified_time)) + return false; + if (type != PP_FILETYPE_REGULAR && + type != PP_FILETYPE_DIRECTORY && + type != PP_FILETYPE_OTHER) + return false; + r->type = static_cast<PP_FileType>(type); + if (system_type != PP_FILESYSTEMTYPE_INVALID && + system_type != PP_FILESYSTEMTYPE_EXTERNAL && + system_type != PP_FILESYSTEMTYPE_LOCALPERSISTENT && + system_type != PP_FILESYSTEMTYPE_LOCALTEMPORARY && + system_type != PP_FILESYSTEMTYPE_ISOLATED) + return false; + r->system_type = static_cast<PP_FileSystemType>(system_type); + return true; +} + +// static +void ParamTraits<PP_FileInfo>::Log(const param_type& p, std::string* l) { +} + +// PP_NetAddress_Private ------------------------------------------------------- + +// static +void ParamTraits<PP_NetAddress_Private>::Write(Message* m, + const param_type& p) { + WriteParam(m, p.size); + m->WriteBytes(p.data, static_cast<int>(p.size)); +} + +// static +bool ParamTraits<PP_NetAddress_Private>::Read(const Message* m, + PickleIterator* iter, + param_type* p) { + uint16 size; + if (!ReadParam(m, iter, &size)) + return false; + if (size > sizeof(p->data)) + return false; + p->size = size; + + const char* data; + if (!m->ReadBytes(iter, &data, size)) + return false; + memcpy(p->data, data, size); + return true; +} + +// static +void ParamTraits<PP_NetAddress_Private>::Log(const param_type& p, + std::string* l) { + l->append("<PP_NetAddress_Private ("); + LogParam(p.size, l); + l->append(" bytes)>"); +} + +// TODO(teravest): Remove this when FileRef is moved to the "new" proxy. +// PPB_FileRef_CreateInfo ------------------------------------------------------ + +// static +void ParamTraits<ppapi::PPB_FileRef_CreateInfo>::Write(Message* m, + const param_type& p) { + ParamTraits<ppapi::HostResource>::Write(m, p.resource); + ParamTraits<int>::Write(m, p.file_system_type); + ParamTraits<std::string>::Write(m, p.path); + ParamTraits<std::string>::Write(m, p.name); + ParamTraits<PP_Resource>::Write(m, p.file_system_plugin_resource); +} + +// static +bool ParamTraits<ppapi::PPB_FileRef_CreateInfo>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + return + ParamTraits<ppapi::HostResource>::Read(m, iter, &r->resource) && + ParamTraits<int>::Read(m, iter, &r->file_system_type) && + ParamTraits<std::string>::Read(m, iter, &r->path) && + ParamTraits<std::string>::Read(m, iter, &r->name) && + ParamTraits<PP_Resource>::Read(m, iter, &r->file_system_plugin_resource); +} + +// static +void ParamTraits<ppapi::PPB_FileRef_CreateInfo>::Log(const param_type& p, + std::string* l) { +} + +// HostResource ---------------------------------------------------------------- + +// static +void ParamTraits<ppapi::HostResource>::Write(Message* m, + const param_type& p) { + ParamTraits<PP_Instance>::Write(m, p.instance()); + ParamTraits<PP_Resource>::Write(m, p.host_resource()); +} + +// static +bool ParamTraits<ppapi::HostResource>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + PP_Instance instance; + PP_Resource resource; + if (!ParamTraits<PP_Instance>::Read(m, iter, &instance) || + !ParamTraits<PP_Resource>::Read(m, iter, &resource)) + return false; + r->SetHostResource(instance, resource); + return true; +} + +// static +void ParamTraits<ppapi::HostResource>::Log(const param_type& p, + std::string* l) { +} + +// SerializedVar --------------------------------------------------------------- + +// static +void ParamTraits<ppapi::proxy::SerializedVar>::Write(Message* m, + const param_type& p) { + p.WriteToMessage(m); +} + +// static +bool ParamTraits<ppapi::proxy::SerializedVar>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + return r->ReadFromMessage(m, iter); +} + +// static +void ParamTraits<ppapi::proxy::SerializedVar>::Log(const param_type& p, + std::string* l) { +} + +// std::vector<SerializedVar> -------------------------------------------------- + +void ParamTraits< std::vector<ppapi::proxy::SerializedVar> >::Write( + Message* m, + const param_type& p) { + WriteVectorWithoutCopy(m, p); +} + +// static +bool ParamTraits< std::vector<ppapi::proxy::SerializedVar> >::Read( + const Message* m, + PickleIterator* iter, + param_type* r) { + return ReadVectorWithoutCopy(m, iter, r); +} + +// static +void ParamTraits< std::vector<ppapi::proxy::SerializedVar> >::Log( + const param_type& p, + std::string* l) { +} + +// std::vector<PPB_FileRef_CreateInfo> ----------------------------------------- + +void ParamTraits< std::vector<ppapi::PPB_FileRef_CreateInfo> >::Write( + Message* m, + const param_type& p) { + WriteVectorWithoutCopy(m, p); +} + +// static +bool ParamTraits< std::vector<ppapi::PPB_FileRef_CreateInfo> >::Read( + const Message* m, + PickleIterator* iter, + param_type* r) { + return ReadVectorWithoutCopy(m, iter, r); +} + +// static +void ParamTraits< std::vector<ppapi::PPB_FileRef_CreateInfo> >::Log( + const param_type& p, + std::string* l) { +} + +// ppapi::PpapiPermissions ----------------------------------------------------- + +void ParamTraits<ppapi::PpapiPermissions>::Write(Message* m, + const param_type& p) { + ParamTraits<uint32_t>::Write(m, p.GetBits()); +} + +// static +bool ParamTraits<ppapi::PpapiPermissions>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + uint32_t bits; + if (!ParamTraits<uint32_t>::Read(m, iter, &bits)) + return false; + *r = ppapi::PpapiPermissions(bits); + return true; +} + +// static +void ParamTraits<ppapi::PpapiPermissions>::Log(const param_type& p, + std::string* l) { +} + +// SerializedHandle ------------------------------------------------------------ + +// static +void ParamTraits<ppapi::proxy::SerializedHandle>::Write(Message* m, + const param_type& p) { + ppapi::proxy::SerializedHandle::WriteHeader(p.header(), m); + switch (p.type()) { + case ppapi::proxy::SerializedHandle::SHARED_MEMORY: + ParamTraits<base::SharedMemoryHandle>::Write(m, p.shmem()); + break; + case ppapi::proxy::SerializedHandle::SOCKET: + case ppapi::proxy::SerializedHandle::CHANNEL_HANDLE: + case ppapi::proxy::SerializedHandle::FILE: + ParamTraits<IPC::PlatformFileForTransit>::Write(m, p.descriptor()); + break; + case ppapi::proxy::SerializedHandle::INVALID: + break; + // No default so the compiler will warn on new types. + } +} + +// static +bool ParamTraits<ppapi::proxy::SerializedHandle>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + ppapi::proxy::SerializedHandle::Header header; + if (!ppapi::proxy::SerializedHandle::ReadHeader(iter, &header)) + return false; + switch (header.type) { + case ppapi::proxy::SerializedHandle::SHARED_MEMORY: { + base::SharedMemoryHandle handle; + if (ParamTraits<base::SharedMemoryHandle>::Read(m, iter, &handle)) { + r->set_shmem(handle, header.size); + return true; + } + break; + } + case ppapi::proxy::SerializedHandle::SOCKET: { + IPC::PlatformFileForTransit socket; + if (ParamTraits<IPC::PlatformFileForTransit>::Read(m, iter, &socket)) { + r->set_socket(socket); + return true; + } + break; + } + case ppapi::proxy::SerializedHandle::CHANNEL_HANDLE: { + IPC::PlatformFileForTransit desc; + if (ParamTraits<IPC::PlatformFileForTransit>::Read(m, iter, &desc)) { + r->set_channel_handle(desc); + return true; + } + break; + } + case ppapi::proxy::SerializedHandle::FILE: { + IPC::PlatformFileForTransit desc; + if (ParamTraits<IPC::PlatformFileForTransit>::Read(m, iter, &desc)) { + r->set_file_handle(desc, header.open_flag); + return true; + } + break; + } + case ppapi::proxy::SerializedHandle::INVALID: + return true; + // No default so the compiler will warn us if a new type is added. + } + return false; +} + +// static +void ParamTraits<ppapi::proxy::SerializedHandle>::Log(const param_type& p, + std::string* l) { +} + +// PPBURLLoader_UpdateProgress_Params ------------------------------------------ + +// static +void ParamTraits<ppapi::proxy::PPBURLLoader_UpdateProgress_Params>::Write( + Message* m, + const param_type& p) { + ParamTraits<PP_Instance>::Write(m, p.instance); + ParamTraits<ppapi::HostResource>::Write(m, p.resource); + ParamTraits<int64_t>::Write(m, p.bytes_sent); + ParamTraits<int64_t>::Write(m, p.total_bytes_to_be_sent); + ParamTraits<int64_t>::Write(m, p.bytes_received); + ParamTraits<int64_t>::Write(m, p.total_bytes_to_be_received); +} + +// static +bool ParamTraits<ppapi::proxy::PPBURLLoader_UpdateProgress_Params>::Read( + const Message* m, + PickleIterator* iter, + param_type* r) { + return + ParamTraits<PP_Instance>::Read(m, iter, &r->instance) && + ParamTraits<ppapi::HostResource>::Read(m, iter, &r->resource) && + ParamTraits<int64_t>::Read(m, iter, &r->bytes_sent) && + ParamTraits<int64_t>::Read(m, iter, &r->total_bytes_to_be_sent) && + ParamTraits<int64_t>::Read(m, iter, &r->bytes_received) && + ParamTraits<int64_t>::Read(m, iter, &r->total_bytes_to_be_received); +} + +// static +void ParamTraits<ppapi::proxy::PPBURLLoader_UpdateProgress_Params>::Log( + const param_type& p, + std::string* l) { +} + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +// PPBFlash_DrawGlyphs_Params -------------------------------------------------- +// static +void ParamTraits<ppapi::proxy::PPBFlash_DrawGlyphs_Params>::Write( + Message* m, + const param_type& p) { + ParamTraits<PP_Instance>::Write(m, p.instance); + ParamTraits<ppapi::HostResource>::Write(m, p.image_data); + ParamTraits<ppapi::proxy::SerializedFontDescription>::Write(m, p.font_desc); + ParamTraits<uint32_t>::Write(m, p.color); + ParamTraits<PP_Point>::Write(m, p.position); + ParamTraits<PP_Rect>::Write(m, p.clip); + ParamTraits<float>::Write(m, p.transformation[0][0]); + ParamTraits<float>::Write(m, p.transformation[0][1]); + ParamTraits<float>::Write(m, p.transformation[0][2]); + ParamTraits<float>::Write(m, p.transformation[1][0]); + ParamTraits<float>::Write(m, p.transformation[1][1]); + ParamTraits<float>::Write(m, p.transformation[1][2]); + ParamTraits<float>::Write(m, p.transformation[2][0]); + ParamTraits<float>::Write(m, p.transformation[2][1]); + ParamTraits<float>::Write(m, p.transformation[2][2]); + ParamTraits<PP_Bool>::Write(m, p.allow_subpixel_aa); + ParamTraits<std::vector<uint16_t> >::Write(m, p.glyph_indices); + ParamTraits<std::vector<PP_Point> >::Write(m, p.glyph_advances); +} + +// static +bool ParamTraits<ppapi::proxy::PPBFlash_DrawGlyphs_Params>::Read( + const Message* m, + PickleIterator* iter, + param_type* r) { + return + ParamTraits<PP_Instance>::Read(m, iter, &r->instance) && + ParamTraits<ppapi::HostResource>::Read(m, iter, &r->image_data) && + ParamTraits<ppapi::proxy::SerializedFontDescription>::Read(m, iter, + &r->font_desc) && + ParamTraits<uint32_t>::Read(m, iter, &r->color) && + ParamTraits<PP_Point>::Read(m, iter, &r->position) && + ParamTraits<PP_Rect>::Read(m, iter, &r->clip) && + ParamTraits<float>::Read(m, iter, &r->transformation[0][0]) && + ParamTraits<float>::Read(m, iter, &r->transformation[0][1]) && + ParamTraits<float>::Read(m, iter, &r->transformation[0][2]) && + ParamTraits<float>::Read(m, iter, &r->transformation[1][0]) && + ParamTraits<float>::Read(m, iter, &r->transformation[1][1]) && + ParamTraits<float>::Read(m, iter, &r->transformation[1][2]) && + ParamTraits<float>::Read(m, iter, &r->transformation[2][0]) && + ParamTraits<float>::Read(m, iter, &r->transformation[2][1]) && + ParamTraits<float>::Read(m, iter, &r->transformation[2][2]) && + ParamTraits<PP_Bool>::Read(m, iter, &r->allow_subpixel_aa) && + ParamTraits<std::vector<uint16_t> >::Read(m, iter, &r->glyph_indices) && + ParamTraits<std::vector<PP_Point> >::Read(m, iter, &r->glyph_advances) && + r->glyph_indices.size() == r->glyph_advances.size(); +} + +// static +void ParamTraits<ppapi::proxy::PPBFlash_DrawGlyphs_Params>::Log( + const param_type& p, + std::string* l) { +} + +// SerializedDirEntry ---------------------------------------------------------- + +// static +void ParamTraits<ppapi::proxy::SerializedDirEntry>::Write(Message* m, + const param_type& p) { + ParamTraits<std::string>::Write(m, p.name); + ParamTraits<bool>::Write(m, p.is_dir); +} + +// static +bool ParamTraits<ppapi::proxy::SerializedDirEntry>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + return ParamTraits<std::string>::Read(m, iter, &r->name) && + ParamTraits<bool>::Read(m, iter, &r->is_dir); +} + +// static +void ParamTraits<ppapi::proxy::SerializedDirEntry>::Log(const param_type& p, + std::string* l) { +} + +// ppapi::proxy::SerializedFontDescription ------------------------------------- + +// static +void ParamTraits<ppapi::proxy::SerializedFontDescription>::Write( + Message* m, + const param_type& p) { + ParamTraits<std::string>::Write(m, p.face); + ParamTraits<int32_t>::Write(m, p.family); + ParamTraits<uint32_t>::Write(m, p.size); + ParamTraits<int32_t>::Write(m, p.weight); + ParamTraits<PP_Bool>::Write(m, p.italic); + ParamTraits<PP_Bool>::Write(m, p.small_caps); + ParamTraits<int32_t>::Write(m, p.letter_spacing); + ParamTraits<int32_t>::Write(m, p.word_spacing); +} + +// static +bool ParamTraits<ppapi::proxy::SerializedFontDescription>::Read( + const Message* m, + PickleIterator* iter, + param_type* r) { + return + ParamTraits<std::string>::Read(m, iter, &r->face) && + ParamTraits<int32_t>::Read(m, iter, &r->family) && + ParamTraits<uint32_t>::Read(m, iter, &r->size) && + ParamTraits<int32_t>::Read(m, iter, &r->weight) && + ParamTraits<PP_Bool>::Read(m, iter, &r->italic) && + ParamTraits<PP_Bool>::Read(m, iter, &r->small_caps) && + ParamTraits<int32_t>::Read(m, iter, &r->letter_spacing) && + ParamTraits<int32_t>::Read(m, iter, &r->word_spacing); +} + +// static +void ParamTraits<ppapi::proxy::SerializedFontDescription>::Log( + const param_type& p, + std::string* l) { +} +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// ppapi::proxy::SerializedTrueTypeFontDesc ------------------------------------ + +// static +void ParamTraits<ppapi::proxy::SerializedTrueTypeFontDesc>::Write( + Message* m, + const param_type& p) { + ParamTraits<std::string>::Write(m, p.family); + ParamTraits<PP_TrueTypeFontFamily_Dev>::Write(m, p.generic_family); + ParamTraits<PP_TrueTypeFontStyle_Dev>::Write(m, p.style); + ParamTraits<PP_TrueTypeFontWeight_Dev>::Write(m, p.weight); + ParamTraits<PP_TrueTypeFontWidth_Dev>::Write(m, p.width); + ParamTraits<PP_TrueTypeFontCharset_Dev>::Write(m, p.charset); +} + +// static +bool ParamTraits<ppapi::proxy::SerializedTrueTypeFontDesc>::Read( + const Message* m, + PickleIterator* iter, + param_type* r) { + return + ParamTraits<std::string>::Read(m, iter, &r->family) && + ParamTraits<PP_TrueTypeFontFamily_Dev>::Read(m, iter, + &r->generic_family) && + ParamTraits<PP_TrueTypeFontStyle_Dev>::Read(m, iter, &r->style) && + ParamTraits<PP_TrueTypeFontWeight_Dev>::Read(m, iter, &r->weight) && + ParamTraits<PP_TrueTypeFontWidth_Dev>::Read(m, iter, &r->width) && + ParamTraits<PP_TrueTypeFontCharset_Dev>::Read(m, iter, &r->charset); +} + +// static +void ParamTraits<ppapi::proxy::SerializedTrueTypeFontDesc>::Log( + const param_type& p, + std::string* l) { +} + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +// ppapi::PepperFilePath ------------------------------------------------------- + +// static +void ParamTraits<ppapi::PepperFilePath>::Write(Message* m, + const param_type& p) { + WriteParam(m, static_cast<unsigned>(p.domain())); + WriteParam(m, p.path()); +} + +// static +bool ParamTraits<ppapi::PepperFilePath>::Read(const Message* m, + PickleIterator* iter, + param_type* p) { + unsigned domain; + base::FilePath path; + if (!ReadParam(m, iter, &domain) || !ReadParam(m, iter, &path)) + return false; + if (domain > ppapi::PepperFilePath::DOMAIN_MAX_VALID) + return false; + + *p = ppapi::PepperFilePath( + static_cast<ppapi::PepperFilePath::Domain>(domain), path); + return true; +} + +// static +void ParamTraits<ppapi::PepperFilePath>::Log(const param_type& p, + std::string* l) { + l->append("("); + LogParam(static_cast<unsigned>(p.domain()), l); + l->append(", "); + LogParam(p.path(), l); + l->append(")"); +} + +// SerializedFlashMenu --------------------------------------------------------- + +// static +void ParamTraits<ppapi::proxy::SerializedFlashMenu>::Write( + Message* m, + const param_type& p) { + p.WriteToMessage(m); +} + +// static +bool ParamTraits<ppapi::proxy::SerializedFlashMenu>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + return r->ReadFromMessage(m, iter); +} + +// static +void ParamTraits<ppapi::proxy::SerializedFlashMenu>::Log(const param_type& p, + std::string* l) { +} +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +// PPB_X509Certificate_Fields -------------------------------------------------- + +// static +void ParamTraits<ppapi::PPB_X509Certificate_Fields>::Write( + Message* m, + const param_type& p) { + ParamTraits<base::ListValue>::Write(m, p.values_); +} + +// static +bool ParamTraits<ppapi::PPB_X509Certificate_Fields>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + return ParamTraits<base::ListValue>::Read(m, iter, &(r->values_)); +} + +// static +void ParamTraits<ppapi::PPB_X509Certificate_Fields>::Log(const param_type& p, + std::string* l) { +} + +// ppapi::SocketOptionData ----------------------------------------------------- + +// static +void ParamTraits<ppapi::SocketOptionData>::Write(Message* m, + const param_type& p) { + ppapi::SocketOptionData::Type type = p.GetType(); + ParamTraits<int32_t>::Write(m, static_cast<int32_t>(type)); + switch (type) { + case ppapi::SocketOptionData::TYPE_INVALID: { + break; + } + case ppapi::SocketOptionData::TYPE_BOOL: { + bool out_value = false; + bool result = p.GetBool(&out_value); + // Suppress unused variable warnings. + static_cast<void>(result); + DCHECK(result); + + ParamTraits<bool>::Write(m, out_value); + break; + } + case ppapi::SocketOptionData::TYPE_INT32: { + int32_t out_value = 0; + bool result = p.GetInt32(&out_value); + // Suppress unused variable warnings. + static_cast<void>(result); + DCHECK(result); + + ParamTraits<int32_t>::Write(m, out_value); + break; + } + // No default so the compiler will warn on new types. + } +} + +// static +bool ParamTraits<ppapi::SocketOptionData>::Read(const Message* m, + PickleIterator* iter, + param_type* r) { + *r = ppapi::SocketOptionData(); + int32_t type = 0; + if (!ParamTraits<int32_t>::Read(m, iter, &type)) + return false; + if (type != ppapi::SocketOptionData::TYPE_INVALID && + type != ppapi::SocketOptionData::TYPE_BOOL && + type != ppapi::SocketOptionData::TYPE_INT32) { + return false; + } + switch (static_cast<ppapi::SocketOptionData::Type>(type)) { + case ppapi::SocketOptionData::TYPE_INVALID: { + return true; + } + case ppapi::SocketOptionData::TYPE_BOOL: { + bool value = false; + if (!ParamTraits<bool>::Read(m, iter, &value)) + return false; + r->SetBool(value); + return true; + } + case ppapi::SocketOptionData::TYPE_INT32: { + int32_t value = 0; + if (!ParamTraits<int32_t>::Read(m, iter, &value)) + return false; + r->SetInt32(value); + return true; + } + // No default so the compiler will warn on new types. + } + return false; +} + +// static +void ParamTraits<ppapi::SocketOptionData>::Log(const param_type& p, + std::string* l) { +} + +} // namespace IPC diff --git a/chromium/ppapi/proxy/ppapi_param_traits.h b/chromium/ppapi/proxy/ppapi_param_traits.h new file mode 100644 index 00000000000..f56415a869f --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_param_traits.h @@ -0,0 +1,209 @@ +// 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_PROXY_PPAPI_PARAM_TRAITS_H_ +#define PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ + +#include <string> +#include <vector> + +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/file_path.h" +#include "ppapi/shared_impl/file_ref_create_info.h" +#include "ppapi/shared_impl/ppapi_permissions.h" +#include "ppapi/shared_impl/ppb_file_ref_shared.h" +#include "ppapi/shared_impl/socket_option_data.h" + +struct PP_FileInfo; +struct PP_NetAddress_Private; + +namespace ppapi { + +class HostResource; +class PPB_X509Certificate_Fields; + +namespace proxy { + +struct PPBFlash_DrawGlyphs_Params; +struct PPBURLLoader_UpdateProgress_Params; +struct SerializedDirEntry; +struct SerializedFontDescription; +struct SerializedTrueTypeFontDesc; +class SerializedFlashMenu; +class SerializedHandle; +class SerializedVar; + +} // namespace proxy +} // namespace ppapi + +namespace IPC { + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<PP_Bool> { + typedef PP_Bool param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<PP_FileInfo> { + typedef PP_FileInfo param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template <> +struct PPAPI_PROXY_EXPORT ParamTraits<PP_NetAddress_Private> { + typedef PP_NetAddress_Private param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits< + ppapi::proxy::PPBFlash_DrawGlyphs_Params> { + typedef ppapi::proxy::PPBFlash_DrawGlyphs_Params param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +// TODO(teravest): Remove this when we've switched over to the new proxy. +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::PPB_FileRef_CreateInfo> { + typedef ppapi::PPB_FileRef_CreateInfo param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits< + ppapi::proxy::PPBURLLoader_UpdateProgress_Params> { + typedef ppapi::proxy::PPBURLLoader_UpdateProgress_Params param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::proxy::SerializedDirEntry> { + typedef ppapi::proxy::SerializedDirEntry param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::proxy::SerializedFontDescription> { + typedef ppapi::proxy::SerializedFontDescription param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT + ParamTraits<ppapi::proxy::SerializedTrueTypeFontDesc> { + typedef ppapi::proxy::SerializedTrueTypeFontDesc param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::proxy::SerializedHandle> { + typedef ppapi::proxy::SerializedHandle param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::HostResource> { + typedef ppapi::HostResource param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::proxy::SerializedVar> { + typedef ppapi::proxy::SerializedVar param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits< + std::vector<ppapi::proxy::SerializedVar> > { + typedef std::vector<ppapi::proxy::SerializedVar> param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits< std::vector< + ppapi::PPB_FileRef_CreateInfo> > { + typedef std::vector<ppapi::PPB_FileRef_CreateInfo> param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::PpapiPermissions> { + typedef ppapi::PpapiPermissions param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +#if !defined(OS_NACL) && !defined(NACL_WIN64) +template <> +struct ParamTraits<ppapi::PepperFilePath> { + typedef ppapi::PepperFilePath param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::proxy::SerializedFlashMenu> { + typedef ppapi::proxy::SerializedFlashMenu param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::PPB_X509Certificate_Fields> { + typedef ppapi::PPB_X509Certificate_Fields param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::SocketOptionData> { + typedef ppapi::SocketOptionData param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +} // namespace IPC + +#endif // PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ diff --git a/chromium/ppapi/proxy/ppapi_perftests.cc b/chromium/ppapi/proxy/ppapi_perftests.cc new file mode 100644 index 00000000000..a9138e6a2a2 --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_perftests.cc @@ -0,0 +1,10 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/perf_test_suite.h" + +int main(int argc, char** argv) { + return base::PerfTestSuite(argc, argv).Run(); +} + diff --git a/chromium/ppapi/proxy/ppapi_proxy_export.h b/chromium/ppapi/proxy/ppapi_proxy_export.h new file mode 100644 index 00000000000..be86da43d6e --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_proxy_export.h @@ -0,0 +1,29 @@ +// 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 PPAPI_PROXY_PPAPI_PROXY_EXPORT_H_ +#define PPAPI_PROXY_PPAPI_PROXY_EXPORT_H_ + +#if defined(COMPONENT_BUILD) && !defined(NACL_WIN64) +#if defined(WIN32) + +#if defined(PPAPI_PROXY_IMPLEMENTATION) +#define PPAPI_PROXY_EXPORT __declspec(dllexport) +#else +#define PPAPI_PROXY_EXPORT __declspec(dllimport) +#endif // defined(PPAPI_PROXY_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(PPAPI_PROXY_IMPLEMENTATION) +#define PPAPI_PROXY_EXPORT __attribute__((visibility("default"))) +#else +#define PPAPI_PROXY_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) && !defined(NACL_WIN64) +#define PPAPI_PROXY_EXPORT +#endif + +#endif // PPAPI_PROXY_PPAPI_PROXY_EXPORT_H_ diff --git a/chromium/ppapi/proxy/ppapi_proxy_test.cc b/chromium/ppapi/proxy/ppapi_proxy_test.cc new file mode 100644 index 00000000000..5e4b67bc4f3 --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_proxy_test.cc @@ -0,0 +1,592 @@ +// 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 "ppapi/proxy/ppapi_proxy_test.h" + +#include <sstream> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/observer_list.h" +#include "base/run_loop.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_message_loop_proxy.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { +// HostDispatcher requires a PPB_Proxy_Private, so we always provide a fallback +// do-nothing implementation. +void PluginCrashed(PP_Module module) { + NOTREACHED(); +}; + +PP_Instance GetInstanceForResource(PP_Resource resource) { + // If a test relies on this, we need to implement it. + NOTREACHED(); + return 0; +} + +void SetReserveInstanceIDCallback(PP_Module module, + PP_Bool (*is_seen)(PP_Module, PP_Instance)) { + // This function gets called in HostDispatcher's constructor. We simply don't + // worry about Instance uniqueness in tests, so we can ignore the call. +} + +void AddRefModule(PP_Module module) {} +void ReleaseModule(PP_Module module) {} +PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; } + +PPB_Proxy_Private ppb_proxy_private = { + &PluginCrashed, + &GetInstanceForResource, + &SetReserveInstanceIDCallback, + &AddRefModule, + &ReleaseModule, + &IsInModuleDestructor +}; + +// We allow multiple harnesses at a time to respond to 'GetInterface' calls. +// We assume that only 1 harness's GetInterface function will ever support a +// given interface name. In practice, there will either be only 1 GetInterface +// handler (for PluginProxyTest or HostProxyTest), or there will be only 2 +// GetInterface handlers (for TwoWayTest). In the latter case, one handler is +// for the PluginProxyTestHarness and should only respond for PPP interfaces, +// and the other handler is for the HostProxyTestHarness which should only +// ever respond for PPB interfaces. +ObserverList<ProxyTestHarnessBase> get_interface_handlers_; + +const void* MockGetInterface(const char* name) { + ObserverList<ProxyTestHarnessBase>::Iterator it = + get_interface_handlers_; + while (ProxyTestHarnessBase* observer = it.GetNext()) { + const void* interface = observer->GetInterface(name); + if (interface) + return interface; + } + if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0) + return &ppb_proxy_private; + return NULL; +} + +void SetUpRemoteHarness(ProxyTestHarnessBase* harness, + const IPC::ChannelHandle& handle, + base::MessageLoopProxy* ipc_message_loop_proxy, + base::WaitableEvent* shutdown_event, + base::WaitableEvent* harness_set_up) { + harness->SetUpHarnessWithChannel(handle, ipc_message_loop_proxy, + shutdown_event, false); + harness_set_up->Signal(); +} + +void TearDownRemoteHarness(ProxyTestHarnessBase* harness, + base::WaitableEvent* harness_torn_down) { + harness->TearDownHarness(); + harness_torn_down->Signal(); +} + +void RunTaskOnRemoteHarness(const base::Closure& task, + base::WaitableEvent* task_complete) { + task.Run(); + task_complete->Signal(); +} + +} // namespace + +// ProxyTestHarnessBase -------------------------------------------------------- + +ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765), + pp_instance_(0x12345) { + get_interface_handlers_.AddObserver(this); +} + +ProxyTestHarnessBase::~ProxyTestHarnessBase() { + get_interface_handlers_.RemoveObserver(this); +} + +const void* ProxyTestHarnessBase::GetInterface(const char* name) { + return registered_interfaces_[name]; +} + +void ProxyTestHarnessBase::RegisterTestInterface(const char* name, + const void* test_interface) { + registered_interfaces_[name] = test_interface; +} + +bool ProxyTestHarnessBase::SupportsInterface(const char* name) { + sink().ClearMessages(); + + // IPC doesn't actually write to this when we send a message manually + // not actually using IPC. + bool unused_result = false; + PpapiMsg_SupportsInterface msg(name, &unused_result); + GetDispatcher()->OnMessageReceived(msg); + + const IPC::Message* reply_msg = + sink().GetUniqueMessageMatching(IPC_REPLY_ID); + EXPECT_TRUE(reply_msg); + if (!reply_msg) + return false; + + TupleTypes<PpapiMsg_SupportsInterface::ReplyParam>::ValueTuple reply_data; + EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam( + reply_msg, &reply_data)); + + sink().ClearMessages(); + return reply_data.a; +} + +// PluginProxyTestHarness ------------------------------------------------------ + +PluginProxyTestHarness::PluginProxyTestHarness( + GlobalsConfiguration globals_config) + : globals_config_(globals_config) { +} + +PluginProxyTestHarness::~PluginProxyTestHarness() { +} + +PpapiGlobals* PluginProxyTestHarness::GetGlobals() { + return plugin_globals_.get(); +} + +Dispatcher* PluginProxyTestHarness::GetDispatcher() { + return plugin_dispatcher_.get(); +} + +void PluginProxyTestHarness::SetUpHarness() { + // These must be first since the dispatcher set-up uses them. + CreatePluginGlobals(); + // Some of the methods called during set-up check that the lock is held. + ProxyAutoLock lock; + + resource_tracker().DidCreateInstance(pp_instance()); + + plugin_dispatcher_.reset(new PluginDispatcher( + &MockGetInterface, + PpapiPermissions(), + false)); + plugin_dispatcher_->InitWithTestSink(&sink()); + // The plugin proxy delegate is needed for + // |PluginProxyDelegate::GetBrowserSender| which is used + // in |ResourceCreationProxy::GetConnection| to get the channel to the + // browser. In this case we just use the |plugin_dispatcher_| as the channel + // for test purposes. + plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get()); + PluginGlobals::Get()->set_plugin_proxy_delegate(&plugin_delegate_mock_); + plugin_dispatcher_->DidCreateInstance(pp_instance()); +} + +void PluginProxyTestHarness::SetUpHarnessWithChannel( + const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client) { + // These must be first since the dispatcher set-up uses them. + CreatePluginGlobals(); + // Some of the methods called during set-up check that the lock is held. + ProxyAutoLock lock; + + resource_tracker().DidCreateInstance(pp_instance()); + plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event); + + plugin_dispatcher_.reset(new PluginDispatcher( + &MockGetInterface, + PpapiPermissions(), + false)); + plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_, + base::kNullProcessId, + channel_handle, + is_client); + plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get()); + PluginGlobals::Get()->set_plugin_proxy_delegate(&plugin_delegate_mock_); + plugin_dispatcher_->DidCreateInstance(pp_instance()); +} + +void PluginProxyTestHarness::TearDownHarness() { + { + // Some of the methods called during tear-down check that the lock is held. + ProxyAutoLock lock; + + plugin_dispatcher_->DidDestroyInstance(pp_instance()); + plugin_dispatcher_.reset(); + + resource_tracker().DidDeleteInstance(pp_instance()); + } + plugin_globals_.reset(); +} + +void PluginProxyTestHarness::CreatePluginGlobals() { + if (globals_config_ == PER_THREAD_GLOBALS) { + plugin_globals_.reset(new PluginGlobals(PpapiGlobals::PerThreadForTest())); + PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals()); + } else { + plugin_globals_.reset(new PluginGlobals()); + } +} + +base::MessageLoopProxy* +PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() { + return ipc_message_loop_; +} + +base::WaitableEvent* +PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() { + return shutdown_event_; +} + +IPC::PlatformFileForTransit +PluginProxyTestHarness::PluginDelegateMock::ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId /* remote_pid */, + bool should_close_source) { + return IPC::GetFileHandleForProcess(handle, + base::Process::Current().handle(), + should_close_source); +} + +std::set<PP_Instance>* +PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() { + return &instance_id_set_; +} + +uint32 PluginProxyTestHarness::PluginDelegateMock::Register( + PluginDispatcher* plugin_dispatcher) { + return 0; +} + +void PluginProxyTestHarness::PluginDelegateMock::Unregister( + uint32 plugin_dispatcher_id) { +} + +IPC::Sender* PluginProxyTestHarness::PluginDelegateMock::GetBrowserSender() { + return browser_sender_; +} + +std::string PluginProxyTestHarness::PluginDelegateMock::GetUILanguage() { + return std::string("en-US"); +} + +void PluginProxyTestHarness::PluginDelegateMock::PreCacheFont( + const void* logfontw) { +} + +void PluginProxyTestHarness::PluginDelegateMock::SetActiveURL( + const std::string& url) { +} + +PP_Resource PluginProxyTestHarness::PluginDelegateMock::CreateBrowserFont( + Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const Preferences& prefs) { + return 0; +} + +// PluginProxyTest ------------------------------------------------------------- + +PluginProxyTest::PluginProxyTest() : PluginProxyTestHarness(SINGLETON_GLOBALS) { +} + +PluginProxyTest::~PluginProxyTest() { +} + +void PluginProxyTest::SetUp() { + SetUpHarness(); +} + +void PluginProxyTest::TearDown() { + TearDownHarness(); +} + +// PluginProxyMultiThreadTest -------------------------------------------------- + +PluginProxyMultiThreadTest::PluginProxyMultiThreadTest() { +} + +PluginProxyMultiThreadTest::~PluginProxyMultiThreadTest() { +} + +void PluginProxyMultiThreadTest::RunTest() { + main_thread_message_loop_proxy_ = + PpapiGlobals::Get()->GetMainThreadMessageLoop(); + ASSERT_EQ(main_thread_message_loop_proxy_.get(), + base::MessageLoopProxy::current()); + nested_main_thread_message_loop_.reset(new base::RunLoop()); + + secondary_thread_.reset(new base::DelegateSimpleThread( + this, "PluginProxyMultiThreadTest")); + + { + ProxyAutoLock auto_lock; + + // MessageLoopResource assumes that the proxy lock has been acquired. + secondary_thread_message_loop_ = new MessageLoopResource(pp_instance()); + + ASSERT_EQ(PP_OK, + secondary_thread_message_loop_->PostWork( + PP_MakeCompletionCallback( + &PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread, + this), + 0)); + } + + SetUpTestOnMainThread(); + + secondary_thread_->Start(); + nested_main_thread_message_loop_->Run(); + secondary_thread_->Join(); + + { + ProxyAutoLock auto_lock; + + // The destruction requires a valid PpapiGlobals instance, so we should + // explicitly release it. + secondary_thread_message_loop_ = NULL; + } + + secondary_thread_.reset(NULL); + nested_main_thread_message_loop_.reset(NULL); + main_thread_message_loop_proxy_ = NULL; +} + +void PluginProxyMultiThreadTest::CheckOnThread(ThreadType thread_type) { + ProxyAutoLock auto_lock; + if (thread_type == MAIN_THREAD) { + ASSERT_TRUE(MessageLoopResource::GetCurrent()->is_main_thread_loop()); + } else { + ASSERT_EQ(secondary_thread_message_loop_.get(), + MessageLoopResource::GetCurrent()); + } +} + +void PluginProxyMultiThreadTest::PostQuitForMainThread() { + main_thread_message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&PluginProxyMultiThreadTest::QuitNestedLoop, + base::Unretained(this))); +} + +void PluginProxyMultiThreadTest::PostQuitForSecondaryThread() { + ProxyAutoLock auto_lock; + secondary_thread_message_loop_->PostQuit(PP_TRUE); +} + +void PluginProxyMultiThreadTest::Run() { + ProxyAutoLock auto_lock; + ASSERT_EQ(PP_OK, secondary_thread_message_loop_->AttachToCurrentThread()); + ASSERT_EQ(PP_OK, secondary_thread_message_loop_->Run()); + secondary_thread_message_loop_->DetachFromThread(); +} + +void PluginProxyMultiThreadTest::QuitNestedLoop() { + nested_main_thread_message_loop_->Quit(); +} + +// static +void PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread( + void* user_data, + int32_t result) { + EXPECT_EQ(PP_OK, result); + PluginProxyMultiThreadTest* thiz = + static_cast<PluginProxyMultiThreadTest*>(user_data); + thiz->CheckOnThread(SECONDARY_THREAD); + thiz->SetUpTestOnSecondaryThread(); +} + +// HostProxyTestHarness -------------------------------------------------------- + +class HostProxyTestHarness::MockSyncMessageStatusReceiver + : public HostDispatcher::SyncMessageStatusReceiver { + public: + virtual void BeginBlockOnSyncMessage() OVERRIDE {} + virtual void EndBlockOnSyncMessage() OVERRIDE {} +}; + +HostProxyTestHarness::HostProxyTestHarness(GlobalsConfiguration globals_config) + : globals_config_(globals_config), + status_receiver_(new MockSyncMessageStatusReceiver) { +} + +HostProxyTestHarness::~HostProxyTestHarness() { +} + +PpapiGlobals* HostProxyTestHarness::GetGlobals() { + return host_globals_.get(); +} + +Dispatcher* HostProxyTestHarness::GetDispatcher() { + return host_dispatcher_.get(); +} + +void HostProxyTestHarness::SetUpHarness() { + // These must be first since the dispatcher set-up uses them. + CreateHostGlobals(); + + host_dispatcher_.reset(new HostDispatcher( + pp_module(), + &MockGetInterface, + status_receiver_.release(), + PpapiPermissions::AllPermissions())); + host_dispatcher_->InitWithTestSink(&sink()); + HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get()); +} + +void HostProxyTestHarness::SetUpHarnessWithChannel( + const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client) { + // These must be first since the dispatcher set-up uses them. + CreateHostGlobals(); + + delegate_mock_.Init(ipc_message_loop, shutdown_event); + + host_dispatcher_.reset(new HostDispatcher( + pp_module(), + &MockGetInterface, + status_receiver_.release(), + PpapiPermissions::AllPermissions())); + ppapi::Preferences preferences; + host_dispatcher_->InitHostWithChannel(&delegate_mock_, + base::kNullProcessId, channel_handle, + is_client, preferences); + HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get()); +} + +void HostProxyTestHarness::TearDownHarness() { + HostDispatcher::RemoveForInstance(pp_instance()); + host_dispatcher_.reset(); + host_globals_.reset(); +} + +void HostProxyTestHarness::CreateHostGlobals() { + if (globals_config_ == PER_THREAD_GLOBALS) { + host_globals_.reset(new TestGlobals(PpapiGlobals::PerThreadForTest())); + PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals()); + } else { + host_globals_.reset(new TestGlobals()); + } +} + +base::MessageLoopProxy* +HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() { + return ipc_message_loop_; +} + +base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() { + return shutdown_event_; +} + +IPC::PlatformFileForTransit +HostProxyTestHarness::DelegateMock::ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId /* remote_pid */, + bool should_close_source) { + return IPC::GetFileHandleForProcess(handle, + base::Process::Current().handle(), + should_close_source); +} + + +// HostProxyTest --------------------------------------------------------------- + +HostProxyTest::HostProxyTest() : HostProxyTestHarness(SINGLETON_GLOBALS) { +} + +HostProxyTest::~HostProxyTest() { +} + +void HostProxyTest::SetUp() { + SetUpHarness(); +} + +void HostProxyTest::TearDown() { + TearDownHarness(); +} + +// TwoWayTest --------------------------------------------------------------- + +TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode) + : test_mode_(test_mode), + host_(ProxyTestHarnessBase::PER_THREAD_GLOBALS), + plugin_(ProxyTestHarnessBase::PER_THREAD_GLOBALS), + io_thread_("TwoWayTest_IOThread"), + plugin_thread_("TwoWayTest_PluginThread"), + remote_harness_(NULL), + local_harness_(NULL), + channel_created_(true, false), + shutdown_event_(true, false) { + if (test_mode == TEST_PPP_INTERFACE) { + remote_harness_ = &plugin_; + local_harness_ = &host_; + } else { + remote_harness_ = &host_; + local_harness_ = &plugin_; + } +} + +TwoWayTest::~TwoWayTest() { + shutdown_event_.Signal(); +} + +void TwoWayTest::SetUp() { + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); + plugin_thread_.Start(); + + // Construct the IPC handle name using the process ID so we can safely run + // multiple |TwoWayTest|s concurrently. + std::ostringstream handle_name; + handle_name << "TwoWayTestChannel" << base::GetCurrentProcId(); + IPC::ChannelHandle handle(handle_name.str()); + base::WaitableEvent remote_harness_set_up(true, false); + plugin_thread_.message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&SetUpRemoteHarness, + remote_harness_, + handle, + io_thread_.message_loop_proxy(), + &shutdown_event_, + &remote_harness_set_up)); + remote_harness_set_up.Wait(); + local_harness_->SetUpHarnessWithChannel(handle, + io_thread_.message_loop_proxy().get(), + &shutdown_event_, + true); // is_client +} + +void TwoWayTest::TearDown() { + base::WaitableEvent remote_harness_torn_down(true, false); + plugin_thread_.message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&TearDownRemoteHarness, + remote_harness_, + &remote_harness_torn_down)); + remote_harness_torn_down.Wait(); + + local_harness_->TearDownHarness(); + + io_thread_.Stop(); +} + +void TwoWayTest::PostTaskOnRemoteHarness(const base::Closure& task) { + base::WaitableEvent task_complete(true, false); + plugin_thread_.message_loop_proxy()->PostTask(FROM_HERE, + base::Bind(&RunTaskOnRemoteHarness, + task, + &task_complete)); + task_complete.Wait(); +} + + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppapi_proxy_test.h b/chromium/ppapi/proxy/ppapi_proxy_test.h new file mode 100644 index 00000000000..9a2df1c5d2c --- /dev/null +++ b/chromium/ppapi/proxy/ppapi_proxy_test.h @@ -0,0 +1,372 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <map> +#include <string> + +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/simple_thread.h" +#include "base/threading/thread.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_proxy_delegate.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/resource_message_test_sink.h" +#include "ppapi/shared_impl/test_globals.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +class MessageLoopProxy; +class RunLoop; +} + +namespace ppapi { +namespace proxy { + +class MessageLoopResource; + +// Base class for plugin and host test harnesses. Tests will not use this +// directly. Instead, use the PluginProxyTest, HostProxyTest, or TwoWayTest. +class ProxyTestHarnessBase { + public: + enum GlobalsConfiguration { + PER_THREAD_GLOBALS, + SINGLETON_GLOBALS + }; + + ProxyTestHarnessBase(); + virtual ~ProxyTestHarnessBase(); + + PP_Module pp_module() const { return pp_module_; } + PP_Instance pp_instance() const { return pp_instance_; } + ResourceMessageTestSink& sink() { return sink_; } + + virtual PpapiGlobals* GetGlobals() = 0; + // Returns either the plugin or host dispatcher, depending on the test. + virtual Dispatcher* GetDispatcher() = 0; + + // Set up the harness using an IPC::TestSink to capture messages. + virtual void SetUpHarness() = 0; + + // Set up the harness using a real IPC channel. + virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client) = 0; + + virtual void TearDownHarness() = 0; + + // Implementation of GetInterface for the dispatcher. This will + // return NULL for all interfaces unless one is registered by calling + // RegisterTestInterface(); + const void* GetInterface(const char* name); + + // Allows the test to specify an interface implementation for a given + // interface name. This will be returned when any of the proxy logic + // requests a local interface. + void RegisterTestInterface(const char* name, const void* test_interface); + + // Sends a "supports interface" message to the current dispatcher and returns + // true if it's supported. This is just for the convenience of tests. + bool SupportsInterface(const char* name); + + private: + // Destination for IPC messages sent by the test. + ResourceMessageTestSink sink_; + + // The module and instance ID associated with the plugin dispatcher. + PP_Module pp_module_; + PP_Instance pp_instance_; + + // Stores the data for GetInterface/RegisterTestInterface. + std::map<std::string, const void*> registered_interfaces_; +}; + +// Test harness for the plugin side of the proxy. +class PluginProxyTestHarness : public ProxyTestHarnessBase { + public: + explicit PluginProxyTestHarness(GlobalsConfiguration globals_config); + virtual ~PluginProxyTestHarness(); + + PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); } + PluginResourceTracker& resource_tracker() { + return *plugin_globals_->plugin_resource_tracker(); + } + PluginVarTracker& var_tracker() { + return *plugin_globals_->plugin_var_tracker(); + } + + // ProxyTestHarnessBase implementation. + virtual PpapiGlobals* GetGlobals(); + virtual Dispatcher* GetDispatcher(); + virtual void SetUpHarness(); + virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client); + virtual void TearDownHarness(); + + class PluginDelegateMock : public PluginDispatcher::PluginDelegate, + public PluginProxyDelegate { + public: + PluginDelegateMock() : ipc_message_loop_(NULL), shutdown_event_() {} + virtual ~PluginDelegateMock() {} + + void Init(base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event) { + ipc_message_loop_ = ipc_message_loop; + shutdown_event_ = shutdown_event; + } + + void set_browser_sender(IPC::Sender* browser_sender) { + browser_sender_ = browser_sender; + } + + // ProxyChannel::Delegate implementation. + virtual base::MessageLoopProxy* GetIPCMessageLoop() OVERRIDE; + virtual base::WaitableEvent* GetShutdownEvent() OVERRIDE; + virtual IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId remote_pid, + bool should_close_source) OVERRIDE; + + // PluginDispatcher::PluginDelegate implementation. + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() OVERRIDE; + virtual uint32 Register(PluginDispatcher* plugin_dispatcher) OVERRIDE; + virtual void Unregister(uint32 plugin_dispatcher_id) OVERRIDE; + + // PluginProxyDelegate implementation. + virtual IPC::Sender* GetBrowserSender() OVERRIDE; + virtual std::string GetUILanguage() OVERRIDE; + virtual void PreCacheFont(const void* logfontw) OVERRIDE; + virtual void SetActiveURL(const std::string& url) OVERRIDE; + virtual PP_Resource CreateBrowserFont( + Connection connection, + PP_Instance instance, + const PP_BrowserFont_Trusted_Description& desc, + const Preferences& prefs) OVERRIDE; + + private: + base::MessageLoopProxy* ipc_message_loop_; // Weak + base::WaitableEvent* shutdown_event_; // Weak + std::set<PP_Instance> instance_id_set_; + IPC::Sender* browser_sender_; + + DISALLOW_COPY_AND_ASSIGN(PluginDelegateMock); + }; + + private: + void CreatePluginGlobals(); + + GlobalsConfiguration globals_config_; + scoped_ptr<PluginGlobals> plugin_globals_; + + scoped_ptr<PluginDispatcher> plugin_dispatcher_; + PluginDelegateMock plugin_delegate_mock_; +}; + +class PluginProxyTest : public PluginProxyTestHarness, public testing::Test { + public: + PluginProxyTest(); + virtual ~PluginProxyTest(); + + // testing::Test implementation. + virtual void SetUp(); + virtual void TearDown(); + private: + base::MessageLoop message_loop_; +}; + +// This class provides support for multi-thread testing. A secondary thread is +// created with a Pepper message loop. +// Subclasses need to implement the two SetUpTestOn*Thread() methods to do the +// actual testing work; and call both PostQuitFor*Thread() when testing is +// done. +class PluginProxyMultiThreadTest + : public PluginProxyTest, + public base::DelegateSimpleThread::Delegate { + public: + PluginProxyMultiThreadTest(); + virtual ~PluginProxyMultiThreadTest(); + + // Called before the secondary thread is started, but after all the member + // variables, including |secondary_thread_| and + // |secondary_thread_message_loop_|, are initialized. + virtual void SetUpTestOnMainThread() = 0; + + virtual void SetUpTestOnSecondaryThread() = 0; + + // TEST_F() should call this method. + void RunTest(); + + enum ThreadType { + MAIN_THREAD, + SECONDARY_THREAD + }; + void CheckOnThread(ThreadType thread_type); + + // These can be called on any thread. + void PostQuitForMainThread(); + void PostQuitForSecondaryThread(); + + protected: + scoped_refptr<MessageLoopResource> secondary_thread_message_loop_; + scoped_refptr<base::MessageLoopProxy> main_thread_message_loop_proxy_; + + private: + // base::DelegateSimpleThread::Delegate implementation. + virtual void Run() OVERRIDE; + + void QuitNestedLoop(); + + static void InternalSetUpTestOnSecondaryThread(void* user_data, + int32_t result); + + scoped_ptr<base::DelegateSimpleThread> secondary_thread_; + scoped_ptr<base::RunLoop> nested_main_thread_message_loop_; +}; + +class HostProxyTestHarness : public ProxyTestHarnessBase { + public: + explicit HostProxyTestHarness(GlobalsConfiguration globals_config); + virtual ~HostProxyTestHarness(); + + HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); } + ResourceTracker& resource_tracker() { + return *host_globals_->GetResourceTracker(); + } + VarTracker& var_tracker() { + return *host_globals_->GetVarTracker(); + } + + // ProxyTestBase implementation. + virtual PpapiGlobals* GetGlobals(); + virtual Dispatcher* GetDispatcher(); + virtual void SetUpHarness(); + virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client); + virtual void TearDownHarness(); + + class DelegateMock : public ProxyChannel::Delegate { + public: + DelegateMock() : ipc_message_loop_(NULL), shutdown_event_(NULL) { + } + virtual ~DelegateMock() {} + + void Init(base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event) { + ipc_message_loop_ = ipc_message_loop; + shutdown_event_ = shutdown_event; + } + + // ProxyChannel::Delegate implementation. + virtual base::MessageLoopProxy* GetIPCMessageLoop(); + virtual base::WaitableEvent* GetShutdownEvent(); + virtual IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId remote_pid, + bool should_close_source) OVERRIDE; + + private: + base::MessageLoopProxy* ipc_message_loop_; // Weak + base::WaitableEvent* shutdown_event_; // Weak + + DISALLOW_COPY_AND_ASSIGN(DelegateMock); + }; + + private: + class MockSyncMessageStatusReceiver; + + void CreateHostGlobals(); + + GlobalsConfiguration globals_config_; + scoped_ptr<ppapi::TestGlobals> host_globals_; + scoped_ptr<HostDispatcher> host_dispatcher_; + DelegateMock delegate_mock_; + + scoped_ptr<MockSyncMessageStatusReceiver> status_receiver_; +}; + +class HostProxyTest : public HostProxyTestHarness, public testing::Test { + public: + HostProxyTest(); + virtual ~HostProxyTest(); + + // testing::Test implementation. + virtual void SetUp(); + virtual void TearDown(); + private: + base::MessageLoop message_loop_; +}; + +// Use this base class to test both sides of a proxy. +class TwoWayTest : public testing::Test { + public: + enum TwoWayTestMode { + TEST_PPP_INTERFACE, + TEST_PPB_INTERFACE + }; + TwoWayTest(TwoWayTestMode test_mode); + virtual ~TwoWayTest(); + + HostProxyTestHarness& host() { return host_; } + PluginProxyTestHarness& plugin() { return plugin_; } + PP_Module pp_module() const { return host_.pp_module(); } + PP_Instance pp_instance() const { return host_.pp_instance(); } + TwoWayTestMode test_mode() { return test_mode_; } + + // testing::Test implementation. + virtual void SetUp(); + virtual void TearDown(); + + protected: + // Post a task to the thread where the remote harness lives. This + // is typically used to test the state of the var tracker on the plugin + // thread. This runs the task synchronously for convenience. + void PostTaskOnRemoteHarness(const base::Closure& task); + + private: + TwoWayTestMode test_mode_; + HostProxyTestHarness host_; + PluginProxyTestHarness plugin_; + // In order to use sync IPC, we need to have an IO thread. + base::Thread io_thread_; + // The plugin side of the proxy runs on its own thread. + base::Thread plugin_thread_; + // The message loop for the main (host) thread. + base::MessageLoop message_loop_; + + // Aliases for the host and plugin harnesses; if we're testing a PPP + // interface, remote_harness will point to plugin_, and local_harness + // will point to host_. This makes it convenient when we're starting and + // stopping the harnesses. + ProxyTestHarnessBase* remote_harness_; + ProxyTestHarnessBase* local_harness_; + + base::WaitableEvent channel_created_; + base::WaitableEvent shutdown_event_; +}; + +// Used during Gtests when you have a PP_Var that you want to EXPECT is equal +// to a certain constant string value: +// +// EXPECT_VAR_IS_STRING("foo", my_var); +#define EXPECT_VAR_IS_STRING(str, var) { \ + StringVar* sv = StringVar::FromPPVar(var); \ + EXPECT_TRUE(sv); \ + if (sv) \ + EXPECT_EQ(str, sv->value()); \ +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_audio_proxy.cc b/chromium/ppapi/proxy/ppb_audio_proxy.cc new file mode 100644 index 00000000000..aae9a5de198 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_audio_proxy.cc @@ -0,0 +1,349 @@ +// 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 "ppapi/proxy/ppb_audio_proxy.h" + +#include "base/compiler_specific.h" +#include "base/threading/simple_thread.h" +#include "media/audio/shared_memory_util.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/api_id.h" +#include "ppapi/shared_impl/platform_file.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/ppb_audio_shared.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/ppb_audio_config_api.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::IntToPlatformFile; +using ppapi::proxy::SerializedHandle; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Audio_API; +using ppapi::thunk::PPB_AudioConfig_API; + +namespace ppapi { +namespace proxy { + +class Audio : public Resource, public PPB_Audio_Shared { + public: + Audio(const HostResource& audio_id, + PP_Resource config_id, + PPB_Audio_Callback callback, + void* user_data); + virtual ~Audio(); + + // Resource overrides. + virtual PPB_Audio_API* AsPPB_Audio_API(); + + // 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<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: + // Owning reference to the current config object. This isn't actually used, + // we just dish it out as requested by the plugin. + PP_Resource config_; + + DISALLOW_COPY_AND_ASSIGN(Audio); +}; + +Audio::Audio(const HostResource& audio_id, + PP_Resource config_id, + PPB_Audio_Callback callback, + void* user_data) + : Resource(OBJECT_IS_PROXY, audio_id), + config_(config_id) { + SetCallback(callback, user_data); + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_); +} + +Audio::~Audio() { +#if defined(OS_NACL) + // Invoke StopPlayback() to ensure audio back-end has a chance to send the + // escape value over the sync socket, which will terminate the client side + // audio callback loop. This is required for NaCl Plugins that can't escape + // by shutting down the sync_socket. + StopPlayback(); +#endif + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(config_); +} + +PPB_Audio_API* Audio::AsPPB_Audio_API() { + return this; +} + +PP_Resource Audio::GetCurrentConfig() { + // AddRef for the caller. + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_); + return config_; +} + +PP_Bool Audio::StartPlayback() { + if (playing()) + return PP_TRUE; + SetStartPlaybackState(); + PluginDispatcher::GetForResource(this)->Send( + new PpapiHostMsg_PPBAudio_StartOrStop( + API_ID_PPB_AUDIO, host_resource(), true)); + return PP_TRUE; +} + +PP_Bool Audio::StopPlayback() { + if (!playing()) + return PP_TRUE; + PluginDispatcher::GetForResource(this)->Send( + new PpapiHostMsg_PPBAudio_StartOrStop( + API_ID_PPB_AUDIO, host_resource(), false)); + SetStopPlaybackState(); + return PP_TRUE; +} + +int32_t Audio::Open(PP_Resource config_id, + scoped_refptr<TrackedCallback> create_callback) { + return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface. +} + +int32_t Audio::GetSyncSocket(int* sync_socket) { + return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface. +} + +int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) { + return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface. +} + +PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + callback_factory_(this) { +} + +PPB_Audio_Proxy::~PPB_Audio_Proxy() { +} + +// static +PP_Resource PPB_Audio_Proxy::CreateProxyResource( + PP_Instance instance_id, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return 0; + + EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true); + if (config.failed()) + return 0; + + if (!audio_callback) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBAudio_Create( + API_ID_PPB_AUDIO, instance_id, + config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(), + &result)); + if (result.is_null()) + return 0; + + return (new Audio(result, config_id, + audio_callback, user_data))->GetReference(); +} + +bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg) +// Don't build host side into NaCl IRT. +#if !defined(OS_NACL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop, + OnMsgStartOrStop) +#endif + IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, + OnMsgNotifyAudioStreamCreated) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +#if !defined(OS_NACL) +void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id, + int32_t sample_rate, + uint32_t sample_frame_count, + HostResource* result) { + thunk::EnterResourceCreation resource_creation(instance_id); + if (resource_creation.failed()) + return; + + // Make the resource and get the API pointer to its trusted interface. + result->SetHostResource( + instance_id, + resource_creation.functions()->CreateAudioTrusted(instance_id)); + if (result->is_null()) + return; + + // At this point, we've set the result resource, and this is a sync request. + // Anything below this point must issue the AudioChannelConnected callback + // to the browser. Since that's an async message, it will be issued back to + // the plugin after the Create function returns (which is good because it + // would be weird to get a connected message with a failure code for a + // resource you haven't finished creating yet). + // + // The ...ForceCallback class will help ensure the callback is always called. + // All error cases must call SetResult on this class. + EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter( + *result, callback_factory_, + &PPB_Audio_Proxy::AudioChannelConnected, *result); + if (enter.failed()) + return; // When enter fails, it will internally schedule the callback. + + // Make an audio config object. + PP_Resource audio_config_res = + resource_creation.functions()->CreateAudioConfig( + instance_id, static_cast<PP_AudioSampleRate>(sample_rate), + sample_frame_count); + if (!audio_config_res) { + enter.SetResult(PP_ERROR_FAILED); + return; + } + + // Initiate opening the audio object. + enter.SetResult(enter.object()->Open(audio_config_res, + enter.callback())); + + // Clean up the temporary audio config resource we made. + const PPB_Core* core = static_cast<const PPB_Core*>( + dispatcher()->local_get_interface()(PPB_CORE_INTERFACE)); + core->ReleaseResource(audio_config_res); +} + +void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id, + bool play) { + EnterHostFromHostResource<PPB_Audio_API> enter(audio_id); + if (enter.failed()) + return; + if (play) + enter.object()->StartPlayback(); + else + enter.object()->StopPlayback(); +} + +void PPB_Audio_Proxy::AudioChannelConnected( + int32_t result, + const HostResource& resource) { + IPC::PlatformFileForTransit socket_handle = + IPC::InvalidPlatformFileForTransit(); + base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit(); + uint32_t audio_buffer_length = 0; + + int32_t result_code = result; + if (result_code == PP_OK) { + result_code = GetAudioConnectedHandles(resource, &socket_handle, + &shared_memory, + &audio_buffer_length); + } + + // Send all the values, even on error. This simplifies some of our cleanup + // code since the handles will be in the other process and could be + // inconvenient to clean up. Our IPC code will automatically handle this for + // us, as long as the remote side always closes the handles it receives + // (in OnMsgNotifyAudioStreamCreated), even in the failure case. + SerializedHandle fd_wrapper(SerializedHandle::SOCKET, socket_handle); + + // Note that we must call TotalSharedMemorySizeInBytes because + // Audio allocates extra space in shared memory for book-keeping, so the + // actual size of the shared memory buffer is larger than audio_buffer_length. + // When sending to NaCl, NaClIPCAdapter expects this size to match the size + // of the full shared memory buffer. + SerializedHandle handle_wrapper( + shared_memory, + media::TotalSharedMemorySizeInBytes(audio_buffer_length)); + dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated( + API_ID_PPB_AUDIO, resource, result_code, fd_wrapper, handle_wrapper)); +} + +int32_t PPB_Audio_Proxy::GetAudioConnectedHandles( + const HostResource& resource, + IPC::PlatformFileForTransit* foreign_socket_handle, + base::SharedMemoryHandle* foreign_shared_memory_handle, + uint32_t* shared_memory_length) { + // Get the audio interface which will give us the handles. + EnterHostFromHostResource<PPB_Audio_API> enter(resource); + if (enter.failed()) + return PP_ERROR_NOINTERFACE; + + // Get the socket handle for signaling. + int32_t socket_handle; + int32_t result = enter.object()->GetSyncSocket(&socket_handle); + if (result != PP_OK) + return result; + + // socket_handle doesn't belong to us: don't close it. + *foreign_socket_handle = dispatcher()->ShareHandleWithRemote( + IntToPlatformFile(socket_handle), false); + if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) + return PP_ERROR_FAILED; + + // Get the shared memory for the buffer. + int shared_memory_handle; + result = enter.object()->GetSharedMemory(&shared_memory_handle, + shared_memory_length); + if (result != PP_OK) + return result; + + // shared_memory_handle doesn't belong to us: don't close it. + *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote( + IntToPlatformFile(shared_memory_handle), false); + if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit()) + return PP_ERROR_FAILED; + + return PP_OK; +} +#endif // !defined(OS_NACL) + +// Processed in the plugin (message from host). +void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated( + const HostResource& audio_id, + int32_t result_code, + SerializedHandle socket_handle, + SerializedHandle handle) { + CHECK(socket_handle.is_socket()); + CHECK(handle.is_shmem()); + EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id); + if (enter.failed() || result_code != PP_OK) { + // The caller may still have given us these handles in the failure case. + // The easiest way to clean these up is to just put them in the objects + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle.descriptor())); + base::SharedMemory temp_mem(handle.shmem(), false); + } else { + EnterResourceNoLock<PPB_AudioConfig_API> config( + static_cast<Audio*>(enter.object())->GetCurrentConfig(), true); + // See the comment above about how we must call + // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here, + // we must call PacketSizeInBytes to get back the size of the audio buffer, + // excluding the bytes that audio uses for book-keeping. + static_cast<Audio*>(enter.object())->SetStreamInfo( + enter.resource()->pp_instance(), handle.shmem(), + media::PacketSizeInBytes(handle.size()), + IPC::PlatformFileForTransitToPlatformFile(socket_handle.descriptor()), + config.object()->GetSampleFrameCount()); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_audio_proxy.h b/chromium/ppapi/proxy/ppb_audio_proxy.h new file mode 100644 index 00000000000..fa887de7f1a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_audio_proxy.h @@ -0,0 +1,87 @@ +// 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_PROXY_PPB_AUDIO_PROXY_H_ +#define PPAPI_PROXY_PPB_AUDIO_PROXY_H_ + +#include <utility> + +#include "base/basictypes.h" +#include "base/memory/shared_memory.h" +#include "base/sync_socket.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_completion_callback_factory.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace ppapi { + +class HostResource; + +namespace proxy { + +class SerializedHandle; + +class PPB_Audio_Proxy : public InterfaceProxy { + public: + PPB_Audio_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Audio_Proxy(); + + // Creates an Audio object in the plugin process. + static PP_Resource CreateProxyResource(PP_Instance instance_id, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data); + + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_AUDIO; + + private: + // Plugin->renderer message handlers. + void OnMsgCreate(PP_Instance instance_id, + int32_t sample_rate, + uint32_t sample_frame_count, + ppapi::HostResource* result); + void OnMsgStartOrStop(const ppapi::HostResource& audio_id, bool play); + + // Renderer->plugin message handlers. + void OnMsgNotifyAudioStreamCreated( + const ppapi::HostResource& audio_id, + int32_t result_code, + ppapi::proxy::SerializedHandle socket_handle, + ppapi::proxy::SerializedHandle handle); + + void AudioChannelConnected(int32_t result, + const ppapi::HostResource& resource); + + // In the renderer, this is called in response to a stream created message. + // It will retrieve the shared memory and socket handles and place them into + // the given out params. The return value is a PPAPI error code. + // + // The input arguments should be initialized to 0 or -1, depending on the + // platform's default invalid handle values. On error, some of these + // arguments may be written to, and others may be untouched, depending on + // where the error occurred. + int32_t GetAudioConnectedHandles( + const ppapi::HostResource& resource, + IPC::PlatformFileForTransit* foreign_socket_handle, + base::SharedMemoryHandle* foreign_shared_memory_handle, + uint32_t* shared_memory_length); + + ProxyCompletionCallbackFactory<PPB_Audio_Proxy> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_AUDIO_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_broker_proxy.cc b/chromium/ppapi/proxy/ppb_broker_proxy.cc new file mode 100644 index 00000000000..19cd978608f --- /dev/null +++ b/chromium/ppapi/proxy/ppb_broker_proxy.cc @@ -0,0 +1,235 @@ +// 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 "ppapi/proxy/ppb_broker_proxy.h" + +#include "base/bind.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/trusted/ppb_broker_trusted.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/platform_file.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_broker_api.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::IntToPlatformFile; +using ppapi::PlatformFileToInt; +using ppapi::thunk::PPB_Broker_API; + +namespace ppapi { +namespace proxy { + +class Broker : public PPB_Broker_API, public Resource { + public: + explicit Broker(const HostResource& resource); + virtual ~Broker(); + + // Resource overrides. + virtual PPB_Broker_API* AsPPB_Broker_API() OVERRIDE; + + // PPB_Broker_API implementation. + virtual int32_t Connect( + scoped_refptr<TrackedCallback> connect_callback) OVERRIDE; + virtual int32_t GetHandle(int32_t* handle) OVERRIDE; + + // Called by the proxy when the host side has completed the request. + void ConnectComplete(IPC::PlatformFileForTransit socket_handle, + int32_t result); + + private: + bool called_connect_; + scoped_refptr<TrackedCallback> current_connect_callback_; + + // The plugin module owns the handle. + // The host side transfers ownership of the handle to the plugin side when it + // sends the IPC. This member holds the handle value for the plugin module + // to read, but the plugin side of the proxy never takes ownership. + base::SyncSocket::Handle socket_handle_; + + DISALLOW_COPY_AND_ASSIGN(Broker); +}; + +Broker::Broker(const HostResource& resource) + : Resource(OBJECT_IS_PROXY, resource), + called_connect_(false), + socket_handle_(base::kInvalidPlatformFileValue) { +} + +Broker::~Broker() { + socket_handle_ = base::kInvalidPlatformFileValue; +} + +PPB_Broker_API* Broker::AsPPB_Broker_API() { + return this; +} + +int32_t Broker::Connect(scoped_refptr<TrackedCallback> connect_callback) { + if (TrackedCallback::IsPending(current_connect_callback_)) + return PP_ERROR_INPROGRESS; + else if (called_connect_) + return PP_ERROR_FAILED; + + current_connect_callback_ = connect_callback; + called_connect_ = true; + + bool success = PluginDispatcher::GetForResource(this)->Send( + new PpapiHostMsg_PPBBroker_Connect( + API_ID_PPB_BROKER, host_resource())); + return success ? PP_OK_COMPLETIONPENDING : PP_ERROR_FAILED; +} + +int32_t Broker::GetHandle(int32_t* handle) { + if (socket_handle_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + *handle = PlatformFileToInt(socket_handle_); + return PP_OK; +} + +void Broker::ConnectComplete(IPC::PlatformFileForTransit socket_handle, + int32_t result) { + if (result == PP_OK) { + DCHECK(socket_handle_ == base::kInvalidPlatformFileValue); + socket_handle_ = IPC::PlatformFileForTransitToPlatformFile(socket_handle); + } else { + // The caller may still have given us a handle in the failure case. + // The easiest way to clean it up is to just put it in an object + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + } + + if (!TrackedCallback::IsPending(current_connect_callback_)) { + // The handle might leak if the plugin never calls GetHandle(). + return; + } + + current_connect_callback_->Run(result); +} + +PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + callback_factory_(this){ +} + +PPB_Broker_Proxy::~PPB_Broker_Proxy() { +} + +// static +PP_Resource PPB_Broker_Proxy::CreateProxyResource(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBBroker_Create( + API_ID_PPB_BROKER, instance, &result)); + if (result.is_null()) + return 0; + return (new Broker(result))->GetReference(); +} + +bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete, + OnMsgConnectComplete) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance, + HostResource* result_resource) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + thunk::EnterResourceCreation enter(instance); + if (enter.succeeded()) { + result_resource->SetHostResource( + instance, + enter.functions()->CreateBroker(instance)); + } +} + +void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterHostFromHostResourceForceCallback<PPB_Broker_API> enter( + broker, callback_factory_, + &PPB_Broker_Proxy::ConnectCompleteInHost, broker); + if (enter.succeeded()) + enter.SetResult(enter.object()->Connect(enter.callback())); +} + +// Called in the plugin to handle the connect callback. +// The proxy owns the handle and transfers it to the Broker. At that point, +// the plugin owns the handle and is responsible for closing it. +// The caller guarantees that socket_handle is not valid if result is not PP_OK. +void PPB_Broker_Proxy::OnMsgConnectComplete( + const HostResource& resource, + IPC::PlatformFileForTransit socket_handle, + int32_t result) { + DCHECK(result == PP_OK || + socket_handle == IPC::InvalidPlatformFileForTransit()); + + EnterPluginFromHostResource<PPB_Broker_API> enter(resource); + if (enter.failed()) { + // As in Broker::ConnectComplete, we need to close the resource on error. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + } else { + static_cast<Broker*>(enter.object())->ConnectComplete(socket_handle, + result); + } +} + +// Callback on the host side. +// Transfers ownership of the handle to the plugin side. This function must +// either successfully call the callback or close the handle. +void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result, + const HostResource& broker) { + IPC::PlatformFileForTransit foreign_socket_handle = + IPC::InvalidPlatformFileForTransit(); + if (result == PP_OK) { + int32_t socket_handle = PlatformFileToInt(base::kInvalidPlatformFileValue); + EnterHostFromHostResource<PPB_Broker_API> enter(broker); + if (enter.succeeded()) + result = enter.object()->GetHandle(&socket_handle); + DCHECK(result == PP_OK || + socket_handle == PlatformFileToInt(base::kInvalidPlatformFileValue)); + + if (result == PP_OK) { + foreign_socket_handle = + dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle), + true); + if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) { + result = PP_ERROR_FAILED; + // Assume the local handle was closed even if the foreign handle could + // not be created. + } + } + } + DCHECK(result == PP_OK || + foreign_socket_handle == IPC::InvalidPlatformFileForTransit()); + + bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete( + API_ID_PPB_BROKER, broker, foreign_socket_handle, result)); + + if (!success || result != PP_OK) { + // The plugin did not receive the handle, so it must be closed. + // The easiest way to clean it up is to just put it in an object + // and then close it. This failure case is not performance critical. + // The handle could still leak if Send succeeded but the IPC later failed. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle)); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_broker_proxy.h b/chromium/ppapi/proxy/ppb_broker_proxy.h new file mode 100644 index 00000000000..5bc195afa50 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_broker_proxy.h @@ -0,0 +1,50 @@ +// 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 PPAPI_PROXY_PPB_BROKER_PROXY_H_ +#define PPAPI_PROXY_PPB_BROKER_PROXY_H_ + +#include "base/sync_socket.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_completion_callback_factory.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace ppapi { + +class HostResource; + +namespace proxy { + +class PPB_Broker_Proxy : public InterfaceProxy { + public: + explicit PPB_Broker_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Broker_Proxy(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_BROKER; + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, ppapi::HostResource* result_resource); + void OnMsgConnect(const ppapi::HostResource& broker); + void OnMsgConnectComplete(const ppapi::HostResource& broker, + IPC::PlatformFileForTransit foreign_socket_handle, + int32_t result); + + void ConnectCompleteInHost(int32_t result, + const ppapi::HostResource& host_resource); + + ProxyCompletionCallbackFactory<PPB_Broker_Proxy> callback_factory_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_BROKER_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_buffer_proxy.cc b/chromium/ppapi/proxy/ppb_buffer_proxy.cc new file mode 100644 index 00000000000..c6d8cdd626b --- /dev/null +++ b/chromium/ppapi/proxy/ppb_buffer_proxy.cc @@ -0,0 +1,156 @@ +// 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 "ppapi/proxy/ppb_buffer_proxy.h" + +#include <vector> + +#include "base/logging.h" +#include "build/build_config.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +Buffer::Buffer(const HostResource& resource, + const base::SharedMemoryHandle& shm_handle, + uint32_t size) + : Resource(OBJECT_IS_PROXY, resource), + shm_(shm_handle, false), + size_(size), + map_count_(0) { +} + +Buffer::~Buffer() { + Unmap(); +} + +thunk::PPB_Buffer_API* Buffer::AsPPB_Buffer_API() { + return this; +} + +PP_Bool Buffer::Describe(uint32_t* size_in_bytes) { + *size_in_bytes = size_; + return PP_TRUE; +} + +PP_Bool Buffer::IsMapped() { + return PP_FromBool(map_count_ > 0); +} + +void* Buffer::Map() { + if (map_count_++ == 0) + shm_.Map(size_); + return shm_.memory(); +} + +void Buffer::Unmap() { + if (--map_count_ == 0) + shm_.Unmap(); +} + +int32_t Buffer::GetSharedMemory(int* out_handle) { + NOTREACHED(); + return PP_ERROR_NOTSUPPORTED; +} + +PPB_Buffer_Proxy::PPB_Buffer_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_Buffer_Proxy::~PPB_Buffer_Proxy() { +} + +// static +PP_Resource PPB_Buffer_Proxy::CreateProxyResource(PP_Instance instance, + uint32_t size) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + ppapi::proxy::SerializedHandle shm_handle; + dispatcher->Send(new PpapiHostMsg_PPBBuffer_Create( + API_ID_PPB_BUFFER, instance, size, &result, &shm_handle)); + if (result.is_null() || !shm_handle.IsHandleValid() || + !shm_handle.is_shmem()) + return 0; + + return AddProxyResource(result, shm_handle.shmem(), size); +} + +// static +PP_Resource PPB_Buffer_Proxy::AddProxyResource( + const HostResource& resource, + base::SharedMemoryHandle shm_handle, + uint32_t size) { + return (new Buffer(resource, shm_handle, size))->GetReference(); +} + +bool PPB_Buffer_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Buffer_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBuffer_Create, OnMsgCreate) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Buffer_Proxy::OnMsgCreate( + PP_Instance instance, + uint32_t size, + HostResource* result_resource, + ppapi::proxy::SerializedHandle* result_shm_handle) { + // Overwritten below on success. + result_shm_handle->set_null_shmem(); + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + if (!dispatcher->permissions().HasPermission(ppapi::PERMISSION_DEV)) + return; + + thunk::EnterResourceCreation enter(instance); + if (enter.failed()) + return; + PP_Resource local_buffer_resource = enter.functions()->CreateBuffer(instance, + size); + if (local_buffer_resource == 0) + return; + + thunk::EnterResourceNoLock<thunk::PPB_Buffer_API> trusted_buffer( + local_buffer_resource, false); + if (trusted_buffer.failed()) + return; + int local_fd; + if (trusted_buffer.object()->GetSharedMemory(&local_fd) != PP_OK) + return; + + result_resource->SetHostResource(instance, local_buffer_resource); + + // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle, + // those casts are ugly. + base::PlatformFile platform_file = +#if defined(OS_WIN) + reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)); +#elif defined(OS_POSIX) + local_fd; +#else + #error Not implemented. +#endif + result_shm_handle->set_shmem( + dispatcher->ShareHandleWithRemote(platform_file, false), size); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_buffer_proxy.h b/chromium/ppapi/proxy/ppb_buffer_proxy.h new file mode 100644 index 00000000000..6c8fcc2fe4e --- /dev/null +++ b/chromium/ppapi/proxy/ppb_buffer_proxy.h @@ -0,0 +1,76 @@ +// 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_PROXY_PPB_BUFFER_PROXY_H_ +#define PPAPI_PROXY_PPB_BUFFER_PROXY_H_ + +#include "base/memory/shared_memory.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/ppb_buffer_api.h" + +namespace ppapi { + +class HostResource; + +namespace proxy { + +class SerializedHandle; + +class Buffer : public thunk::PPB_Buffer_API, public Resource { + public: + Buffer(const HostResource& resource, + const base::SharedMemoryHandle& shm_handle, + uint32_t size); + virtual ~Buffer(); + + // Resource overrides. + virtual 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: + base::SharedMemory shm_; + uint32_t size_; + int map_count_; + + DISALLOW_COPY_AND_ASSIGN(Buffer); +}; + +class PPB_Buffer_Proxy : public InterfaceProxy { + public: + explicit PPB_Buffer_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Buffer_Proxy(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + uint32_t size); + static PP_Resource AddProxyResource(const HostResource& resource, + base::SharedMemoryHandle shm_handle, + uint32_t size); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_BUFFER; + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, + uint32_t size, + HostResource* result_resource, + ppapi::proxy::SerializedHandle* result_shm_handle); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_BUFFER_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_core_proxy.cc b/chromium/ppapi/proxy/ppb_core_proxy.cc new file mode 100644 index 00000000000..65845aed7be --- /dev/null +++ b/chromium/ppapi/proxy/ppb_core_proxy.cc @@ -0,0 +1,131 @@ +// 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 "ppapi/proxy/ppb_core_proxy.h" + +#include <stdlib.h> // For malloc + +#include "base/bind.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "base/time/time.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/time_conversion.h" + +namespace ppapi { +namespace proxy { + +namespace { + +void AddRefResource(PP_Resource resource) { + ppapi::ProxyAutoLock lock; + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(resource); +} + +void ReleaseResource(PP_Resource resource) { + ppapi::ProxyAutoLock lock; + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(resource); +} + +double GetTime() { + return TimeToPPTime(base::Time::Now()); +} + +double GetTimeTicks() { + return TimeTicksToPPTimeTicks(base::TimeTicks::Now()); +} + +void CallbackWrapper(PP_CompletionCallback callback, int32_t result) { + TRACE_EVENT2("ppapi proxy", "CallOnMainThread callback", + "Func", reinterpret_cast<void*>(callback.func), + "UserData", callback.user_data); + CallWhileUnlocked(PP_RunCompletionCallback, &callback, result); +} + +void CallOnMainThread(int delay_in_ms, + PP_CompletionCallback callback, + int32_t result) { + DCHECK(callback.func); +#if defined(OS_NACL) + // Some NaCl apps pass a negative delay, so we just sanitize to 0, to run as + // soon as possible. MessageLoop checks that the delay is non-negative. + if (delay_in_ms < 0) + delay_in_ms = 0; +#endif + if (!callback.func) + return; + ProxyAutoLock lock; + PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostDelayedTask( + FROM_HERE, + RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), + base::TimeDelta::FromMilliseconds(delay_in_ms)); +} + +PP_Bool IsMainThread() { + return PP_FromBool(PpapiGlobals::Get()-> + GetMainThreadMessageLoop()->BelongsToCurrentThread()); +} + +const PPB_Core core_interface = { + &AddRefResource, + &ReleaseResource, + &GetTime, + &GetTimeTicks, + &CallOnMainThread, + &IsMainThread +}; + +} // namespace + +PPB_Core_Proxy::PPB_Core_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppb_core_impl_(NULL) { + if (!dispatcher->IsPlugin()) { + ppb_core_impl_ = static_cast<const PPB_Core*>( + dispatcher->local_get_interface()(PPB_CORE_INTERFACE)); + } +} + +PPB_Core_Proxy::~PPB_Core_Proxy() { +} + +// static +const PPB_Core* PPB_Core_Proxy::GetPPB_Core_Interface() { + return &core_interface; +} + +bool PPB_Core_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Core_Proxy, msg) +#if !defined(OS_NACL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCore_AddRefResource, + OnMsgAddRefResource) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCore_ReleaseResource, + OnMsgReleaseResource) +#endif + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +#if !defined(OS_NACL) +void PPB_Core_Proxy::OnMsgAddRefResource(const HostResource& resource) { + ppb_core_impl_->AddRefResource(resource.host_resource()); +} + +void PPB_Core_Proxy::OnMsgReleaseResource(const HostResource& resource) { + ppb_core_impl_->ReleaseResource(resource.host_resource()); +} +#endif // !defined(OS_NACL) + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_core_proxy.h b/chromium/ppapi/proxy/ppb_core_proxy.h new file mode 100644 index 00000000000..a5645195fdb --- /dev/null +++ b/chromium/ppapi/proxy/ppb_core_proxy.h @@ -0,0 +1,44 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_CORE_PROXY_H_ +#define PPAPI_PPB_CORE_PROXY_H_ + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/host_resource.h" + +namespace ppapi { +namespace proxy { + +class PPB_Core_Proxy : public InterfaceProxy { + public: + PPB_Core_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Core_Proxy(); + + static const PPB_Core* GetPPB_Core_Interface(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_CORE; + + private: + // Message handlers. + void OnMsgAddRefResource(const ppapi::HostResource& resource); + void OnMsgReleaseResource(const ppapi::HostResource& resource); + + // When this proxy is in the host side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the plugin, this value is always NULL. + const PPB_Core* ppb_core_impl_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PPB_CORE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_file_ref_proxy.cc b/chromium/ppapi/proxy/ppb_file_ref_proxy.cc new file mode 100644 index 00000000000..62c55da9d8b --- /dev/null +++ b/chromium/ppapi/proxy/ppb_file_ref_proxy.cc @@ -0,0 +1,549 @@ +// 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 "ppapi/proxy/ppb_file_ref_proxy.h" + +#include <map> + +#include "base/bind.h" +#include "ppapi/c/pp_directory_entry.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_ref.h" +#include "ppapi/c/private/ppb_file_ref_private.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/ppb_file_ref_shared.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_FileRef_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace ppapi { +namespace proxy { + +namespace { + +void ReleaseEntries(const std::vector<PP_DirectoryEntry>& entries) { + ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); + for (std::vector<PP_DirectoryEntry>::const_iterator it = entries.begin(); + it != entries.end(); ++it) + tracker->ReleaseResource(it->file_ref); +} + +} // namespace + +class FileRef : public PPB_FileRef_Shared { + public: + explicit FileRef(const PPB_FileRef_CreateInfo& info); + virtual ~FileRef(); + + // Resource overrides. + virtual void LastPluginRefWasDeleted() OVERRIDE; + + // 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<TrackedCallback> callback) OVERRIDE; + virtual int32_t Touch(PP_Time last_access_time, + PP_Time last_modified_time, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Delete(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Rename(PP_Resource new_file_ref, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Query(PP_FileInfo* info, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t ReadDirectoryEntries( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t QueryInHost( + linked_ptr<PP_FileInfo> info, + scoped_refptr<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<TrackedCallback> callback) OVERRIDE; + virtual PP_Var GetAbsolutePath() OVERRIDE; + + // Executes the pending callback with the given ID. See pending_callbacks_. + void ExecuteCallback(uint32_t callback_id, int32_t result); + int32_t SetFileInfo(uint32_t callback_id, const PP_FileInfo& info); + int32_t SetReadDirectoryEntriesOutput( + uint32_t callback_id, + const std::vector<ppapi::PPB_FileRef_CreateInfo>& infos, + const std::vector<PP_FileType>& file_types); + + private: + PluginDispatcher* GetDispatcher() const { + return PluginDispatcher::GetForResource(this); + } + + // Adds a callback to the list and returns its ID. + uint32_t SendCallback(scoped_refptr<TrackedCallback> callback); + + // This class can have any number of out-standing requests with completion + // callbacks, in contrast to most resources which have one possible pending + // callback pending (like a Flush callback). + // + // To keep track of them, assign integer IDs to the callbacks, which is how + // the callback will be identified when it's passed to the host and then + // back here. Use unsigned so that overflow is well-defined. + uint32_t next_callback_id_; + typedef std::map<uint32_t, + scoped_refptr<TrackedCallback> > PendingCallbackMap; + PendingCallbackMap pending_callbacks_; + + // Used to keep pointers to PP_FileInfo instances that are written before + // callbacks are invoked. The id of a pending file info will match that of + // the corresponding callback. + typedef std::map<uint32_t, PP_FileInfo*> PendingFileInfoMap; + PendingFileInfoMap pending_file_infos_; + + // Used to keep PP_ArrayOutput instances that are written before callbacks + // are invoked. The id of a pending array output will match that of the + // corresponding callback. + typedef std::map<uint32_t, PP_ArrayOutput> + PendingReadDirectoryEntriesOutputMap; + PendingReadDirectoryEntriesOutputMap pending_read_entries_outputs_; + + // Holds a reference on plugin side when running out of process, so that + // FileSystem won't die before FileRef. See PPB_FileRef_Impl for + // corresponding code for in-process mode. Note that this workaround will + // be no longer needed after FileRef refactoring. + ScopedPPResource file_system_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(FileRef); +}; + +FileRef::FileRef(const PPB_FileRef_CreateInfo& info) + : PPB_FileRef_Shared(OBJECT_IS_PROXY, info), + next_callback_id_(0u), + file_system_(info.file_system_plugin_resource) { +} + +FileRef::~FileRef() { + // The callbacks map should have been cleared by LastPluginRefWasDeleted. + DCHECK(pending_callbacks_.empty()); + DCHECK(pending_file_infos_.empty()); + DCHECK(pending_read_entries_outputs_.empty()); +} + +void FileRef::LastPluginRefWasDeleted() { + // The callback tracker will abort our callbacks for us. + pending_callbacks_.clear(); + pending_file_infos_.clear(); + pending_read_entries_outputs_.clear(); +} + +PP_Resource FileRef::GetParent() { + PPB_FileRef_CreateInfo create_info; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetParent( + API_ID_PPB_FILE_REF, host_resource(), &create_info)); + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +int32_t FileRef::MakeDirectory(PP_Bool make_ancestors, + scoped_refptr<TrackedCallback> callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( + API_ID_PPB_FILE_REF, host_resource(), make_ancestors, + SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Touch(PP_Time last_access_time, + PP_Time last_modified_time, + scoped_refptr<TrackedCallback> callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch( + API_ID_PPB_FILE_REF, host_resource(), last_access_time, + last_modified_time, SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Delete(scoped_refptr<TrackedCallback> callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete( + API_ID_PPB_FILE_REF, host_resource(), SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Rename(PP_Resource new_file_ref, + scoped_refptr<TrackedCallback> callback) { + Resource* new_file_ref_object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(new_file_ref); + if (!new_file_ref_object || + new_file_ref_object->host_resource().instance() != pp_instance()) + return PP_ERROR_BADRESOURCE; + + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename( + API_ID_PPB_FILE_REF, host_resource(), + new_file_ref_object->host_resource(), SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Query(PP_FileInfo* info, + scoped_refptr<TrackedCallback> callback) { + // Store the pending file info id. + uint32_t id = SendCallback(callback); + pending_file_infos_[id] = info; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Query( + API_ID_PPB_FILE_REF, host_resource(), id)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::ReadDirectoryEntries( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + // Store the pending read entries output id. + uint32_t id = SendCallback(callback); + pending_read_entries_outputs_[id] = output; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_ReadDirectoryEntries( + API_ID_PPB_FILE_REF, host_resource(), id)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::QueryInHost( + linked_ptr<PP_FileInfo> info, + scoped_refptr<TrackedCallback> callback) { + NOTREACHED(); + return PP_ERROR_FAILED; +} + +int32_t FileRef::ReadDirectoryEntriesInHost( + linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > files, + linked_ptr<std::vector<PP_FileType> > file_types, + scoped_refptr<TrackedCallback> callback) { + NOTREACHED(); + return PP_ERROR_FAILED; +} + +PP_Var FileRef::GetAbsolutePath() { + ReceiveSerializedVarReturnValue result; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetAbsolutePath( + API_ID_PPB_FILE_REF, host_resource(), &result)); + return result.Return(GetDispatcher()); +} + +void FileRef::ExecuteCallback(uint32_t callback_id, int32_t result) { + PendingCallbackMap::iterator found = pending_callbacks_.find(callback_id); + if (found == pending_callbacks_.end()) { + // This will happen when the plugin deletes its resource with a pending + // callback. The callback will be locally issued with an ABORTED call while + // the operation may still be pending in the renderer. + return; + } + + // Executing the callback may mutate the callback list. + scoped_refptr<TrackedCallback> callback = found->second; + pending_callbacks_.erase(found); + callback->Run(result); +} + +int32_t FileRef::SetFileInfo(uint32_t callback_id, const PP_FileInfo& info) { + PendingFileInfoMap::iterator found = pending_file_infos_.find(callback_id); + if (found == pending_file_infos_.end()) + return PP_ERROR_FAILED; + PP_FileInfo* target_info = found->second; + *target_info = info; + pending_file_infos_.erase(found); + return PP_OK; +} + +int32_t FileRef::SetReadDirectoryEntriesOutput( + uint32_t callback_id, + const std::vector<ppapi::PPB_FileRef_CreateInfo>& infos, + const std::vector<PP_FileType>& file_types) { + PendingReadDirectoryEntriesOutputMap::iterator found = + pending_read_entries_outputs_.find(callback_id); + if (found == pending_read_entries_outputs_.end()) + return PP_ERROR_FAILED; + + PP_ArrayOutput output = found->second; + pending_read_entries_outputs_.erase(found); + + std::vector<PP_DirectoryEntry> entries; + for (size_t i = 0; i < infos.size(); ++i) { + PP_DirectoryEntry entry; + entry.file_ref = PPB_FileRef_Proxy::DeserializeFileRef(infos[i]); + entry.file_type = file_types[i]; + entries.push_back(entry); + } + + ArrayWriter writer(output); + if (!writer.is_valid()) { + ReleaseEntries(entries); + return PP_ERROR_BADARGUMENT; + } + + writer.StoreVector(entries); + return PP_OK; +} + +uint32_t FileRef::SendCallback(scoped_refptr<TrackedCallback> callback) { + // In extreme cases the IDs may wrap around, so avoid duplicates. + while (pending_callbacks_.count(next_callback_id_)) + ++next_callback_id_; + + pending_callbacks_[next_callback_id_] = callback; + return next_callback_id_++; +} + +PPB_FileRef_Proxy::PPB_FileRef_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + callback_factory_(this) { +} + +PPB_FileRef_Proxy::~PPB_FileRef_Proxy() { +} + +// static +PP_Resource PPB_FileRef_Proxy::CreateProxyResource(PP_Instance instance, + PP_Resource file_system, + const char* path) { + PPB_FileRef_CreateInfo create_info; + PluginDispatcher::GetForInstance(instance)->Send( + new PpapiHostMsg_PPBFileRef_Create( + API_ID_PPB_FILE_REF, instance, file_system, path, &create_info)); + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +bool PPB_FileRef_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_FileRef_Proxy, msg) +#if !defined(OS_NACL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_GetParent, OnMsgGetParent) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_MakeDirectory, + OnMsgMakeDirectory) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Touch, OnMsgTouch) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Delete, OnMsgDelete) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Rename, OnMsgRename) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Query, OnMsgQuery) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_ReadDirectoryEntries, + OnMsgReadDirectoryEntries) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_GetAbsolutePath, + OnMsgGetAbsolutePath) +#endif // !defined(OS_NACL) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileRef_CallbackComplete, + OnMsgCallbackComplete) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileRef_QueryCallbackComplete, + OnMsgQueryCallbackComplete) + IPC_MESSAGE_HANDLER( + PpapiMsg_PPBFileRef_ReadDirectoryEntriesCallbackComplete, + OnMsgReadDirectoryEntriesCallbackComplete) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +// static +void PPB_FileRef_Proxy::SerializeFileRef(PP_Resource file_ref, + PPB_FileRef_CreateInfo* result) { + EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, false); + if (enter.succeeded()) + *result = enter.object()->GetCreateInfo(); +} + +// static +PP_Resource PPB_FileRef_Proxy::DeserializeFileRef( + const PPB_FileRef_CreateInfo& serialized) { + if (serialized.resource.is_null()) + return 0; // Resource invalid. + return (new FileRef(serialized))->GetReference(); +} + +#if !defined(OS_NACL) +void PPB_FileRef_Proxy::OnMsgCreate(PP_Instance pp_instance, + PP_Resource file_system, + const std::string& path, + PPB_FileRef_CreateInfo* result) { + thunk::EnterResourceCreation enter(pp_instance); + if (enter.failed()) + return; + + PP_Resource resource = enter.functions()->CreateFileRef( + pp_instance, file_system, path.c_str()); + if (!resource) + return; // CreateInfo default constructor initializes to 0. + SerializeFileRef(resource, result); +} + +void PPB_FileRef_Proxy::OnMsgGetParent(const HostResource& host_resource, + PPB_FileRef_CreateInfo* result) { + EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.succeeded()) + SerializeFileRef(enter.object()->GetParent(), result); +} + +void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, + PP_Bool make_ancestors, + uint32_t callback_id) { + EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( + host_resource, callback_factory_, + &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); + if (enter.succeeded()) { + enter.SetResult(enter.object()->MakeDirectory(make_ancestors, + enter.callback())); + } +} + +void PPB_FileRef_Proxy::OnMsgTouch(const HostResource& host_resource, + PP_Time last_access, + PP_Time last_modified, + uint32_t callback_id) { + EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( + host_resource, callback_factory_, + &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); + if (enter.succeeded()) { + enter.SetResult(enter.object()->Touch(last_access, last_modified, + enter.callback())); + } +} + +void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, + uint32_t callback_id) { + EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( + host_resource, callback_factory_, + &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); + if (enter.succeeded()) + enter.SetResult(enter.object()->Delete(enter.callback())); +} + +void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, + const HostResource& new_file_ref, + uint32_t callback_id) { + EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( + file_ref, callback_factory_, + &PPB_FileRef_Proxy::OnCallbackCompleteInHost, file_ref, callback_id); + if (enter.succeeded()) { + enter.SetResult(enter.object()->Rename(new_file_ref.host_resource(), + enter.callback())); + } +} + +void PPB_FileRef_Proxy::OnMsgQuery(const HostResource& file_ref, + uint32_t callback_id) { + linked_ptr<PP_FileInfo> info(new PP_FileInfo()); + EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( + file_ref, callback_factory_, + &PPB_FileRef_Proxy::OnQueryCallbackCompleteInHost, file_ref, + info, callback_id); + if (enter.succeeded()) + enter.SetResult(enter.object()->QueryInHost(info, enter.callback())); +} + +void PPB_FileRef_Proxy::OnMsgGetAbsolutePath(const HostResource& host_resource, + SerializedVarReturnValue result) { + EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.succeeded()) + result.Return(dispatcher(), enter.object()->GetAbsolutePath()); +} + +void PPB_FileRef_Proxy::OnMsgReadDirectoryEntries(const HostResource& file_ref, + uint32_t callback_id) { + linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > files( + new std::vector<ppapi::PPB_FileRef_CreateInfo>()); + linked_ptr<std::vector<PP_FileType> > file_types( + new std::vector<PP_FileType>()); + HostCallbackParams params(file_ref, callback_id); + EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( + file_ref, callback_factory_, + &PPB_FileRef_Proxy::OnReadDirectoryEntriesCallbackCompleteInHost, + params, files, file_types); + if (enter.succeeded()) { + enter.SetResult(enter.object()->ReadDirectoryEntriesInHost( + files, file_types, enter.callback())); + } +} + +#endif // !defined(OS_NACL) + +void PPB_FileRef_Proxy::OnMsgCallbackComplete( + const HostResource& host_resource, + uint32_t callback_id, + int32_t result) { + // Forward the callback info to the plugin resource. + EnterPluginFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.succeeded()) + static_cast<FileRef*>(enter.object())->ExecuteCallback(callback_id, result); +} + +void PPB_FileRef_Proxy::OnMsgQueryCallbackComplete( + const HostResource& host_resource, + const PP_FileInfo& info, + uint32_t callback_id, + int32_t result) { + EnterPluginFromHostResource<PPB_FileRef_API> enter(host_resource); + if (!enter.succeeded()) + return; + + if (result == PP_OK) { + result = static_cast<FileRef*>(enter.object())->SetFileInfo( + callback_id, info); + } + static_cast<FileRef*>(enter.object())->ExecuteCallback(callback_id, result); +} + +void PPB_FileRef_Proxy::OnMsgReadDirectoryEntriesCallbackComplete( + const HostResource& host_resource, + const std::vector<ppapi::PPB_FileRef_CreateInfo>& infos, + const std::vector<PP_FileType>& file_types, + uint32_t callback_id, + int32_t result) { + CHECK_EQ(infos.size(), file_types.size()); + + EnterPluginFromHostResource<PPB_FileRef_API> enter(host_resource); + if (!enter.succeeded()) + return; + + if (result == PP_OK) { + result = + static_cast<FileRef*>(enter.object())->SetReadDirectoryEntriesOutput( + callback_id, infos, file_types); + } + static_cast<FileRef*>(enter.object())->ExecuteCallback( + callback_id, result); +} + +#if !defined(OS_NACL) +void PPB_FileRef_Proxy::OnCallbackCompleteInHost( + int32_t result, + const HostResource& host_resource, + uint32_t callback_id) { + // Execute OnMsgCallbackComplete in the plugin process. + Send(new PpapiMsg_PPBFileRef_CallbackComplete( + API_ID_PPB_FILE_REF, host_resource, callback_id, result)); +} + +void PPB_FileRef_Proxy::OnQueryCallbackCompleteInHost( + int32_t result, + const HostResource& host_resource, + linked_ptr<PP_FileInfo> info, + uint32_t callback_id) { + Send(new PpapiMsg_PPBFileRef_QueryCallbackComplete( + API_ID_PPB_FILE_REF, host_resource, *info, callback_id, result)); +} + +void PPB_FileRef_Proxy::OnReadDirectoryEntriesCallbackCompleteInHost( + int32_t result, + HostCallbackParams params, + linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > files, + linked_ptr<std::vector<PP_FileType> > file_types) { + Send(new PpapiMsg_PPBFileRef_ReadDirectoryEntriesCallbackComplete( + API_ID_PPB_FILE_REF, params.host_resource, + *files, *file_types, params.callback_id, result)); +} + +#endif // !defined(OS_NACL) + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_file_ref_proxy.h b/chromium/ppapi/proxy/ppb_file_ref_proxy.h new file mode 100644 index 00000000000..cbfadb5b5f4 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_file_ref_proxy.h @@ -0,0 +1,138 @@ +// 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 PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ +#define PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/linked_ptr.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/proxy_completion_callback_factory.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace ppapi { + +struct PPB_FileRef_CreateInfo; + +namespace proxy { + +class SerializedVarReturnValue; + +class PPAPI_PROXY_EXPORT PPB_FileRef_Proxy + : public NON_EXPORTED_BASE(InterfaceProxy) { + public: + explicit PPB_FileRef_Proxy(Dispatcher* dispatcher); + virtual ~PPB_FileRef_Proxy(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + PP_Resource file_system, + const char* path); + static PP_Resource CreateProxyResource( + const PPB_FileRef_CreateInfo& serialized); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // Takes a resource in the host and converts it into a serialized file ref + // "create info" for reconstitution in the plugin. This struct contains all + // the necessary information about the file ref. + // + // Various PPAPI functions return file refs from various interfaces, so this + // function is public so anybody can send a file ref. + static void SerializeFileRef(PP_Resource file_ref, + PPB_FileRef_CreateInfo* result); + + // Creates a plugin resource from the given CreateInfo sent from the host. + // The value will be the result of calling SerializeFileRef on the host. + // This represents passing the resource ownership to the plugin. This + // function also checks the validity of the result and returns 0 on failure. + // + // Various PPAPI functions return file refs from various interfaces, so this + // function is public so anybody can receive a file ref. + static PP_Resource DeserializeFileRef( + const PPB_FileRef_CreateInfo& serialized); + + static const ApiID kApiID = API_ID_PPB_FILE_REF; + + private: + // Plugin -> host message handlers. + void OnMsgCreate(PP_Instance instance, + PP_Resource file_system, + const std::string& path, + PPB_FileRef_CreateInfo* result); + void OnMsgGetParent(const HostResource& host_resource, + PPB_FileRef_CreateInfo* result); + void OnMsgMakeDirectory(const HostResource& host_resource, + PP_Bool make_ancestors, + uint32_t callback_id); + void OnMsgTouch(const HostResource& host_resource, + PP_Time last_access, + PP_Time last_modified, + uint32_t callback_id); + void OnMsgDelete(const HostResource& host_resource, + uint32_t callback_id); + void OnMsgRename(const HostResource& file_ref, + const HostResource& new_file_ref, + uint32_t callback_id); + void OnMsgQuery(const HostResource& file_ref, + uint32_t callback_id); + void OnMsgGetAbsolutePath(const HostResource& host_resource, + SerializedVarReturnValue result); + void OnMsgReadDirectoryEntries(const HostResource& file_ref, + uint32_t callback_id); + + // Host -> Plugin message handlers. + void OnMsgCallbackComplete(const HostResource& host_resource, + uint32_t callback_id, + int32_t result); + void OnMsgQueryCallbackComplete(const HostResource& host_resource, + const PP_FileInfo& info, + uint32_t callback_id, + int32_t result); + void OnMsgReadDirectoryEntriesCallbackComplete( + const HostResource& host_resource, + const std::vector<ppapi::PPB_FileRef_CreateInfo>& infos, + const std::vector<PP_FileType>& file_types, + uint32_t callback_id, + int32_t result); + + struct HostCallbackParams { + HostCallbackParams(const HostResource& host_res, uint32_t cb_id) + : host_resource(host_res), callback_id(cb_id) { + } + HostResource host_resource; + uint32_t callback_id; + }; + + void OnCallbackCompleteInHost(int32_t result, + const HostResource& host_resource, + uint32_t callback_id); + void OnQueryCallbackCompleteInHost( + int32_t result, + const HostResource& host_resource, + linked_ptr<PP_FileInfo> info, + uint32_t callback_id); + void OnReadDirectoryEntriesCallbackCompleteInHost( + int32_t result, + HostCallbackParams params, + linked_ptr<std::vector<ppapi::PPB_FileRef_CreateInfo> > files, + linked_ptr<std::vector<PP_FileType> > file_types); + + ProxyCompletionCallbackFactory<PPB_FileRef_Proxy> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileRef_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_flash_message_loop_proxy.cc b/chromium/ppapi/proxy/ppb_flash_message_loop_proxy.cc new file mode 100644 index 00000000000..8b7ff823ee0 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_flash_message_loop_proxy.cc @@ -0,0 +1,165 @@ +// 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 "ppapi/proxy/ppb_flash_message_loop_proxy.h" + +#include "base/bind.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash_message_loop.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_flash_message_loop_api.h" +#include "ppapi/thunk/resource_creation_api.h" + +using ppapi::thunk::PPB_Flash_MessageLoop_API; + +namespace ppapi { +namespace proxy { +namespace { + +class FlashMessageLoop : public PPB_Flash_MessageLoop_API, public Resource { + public: + explicit FlashMessageLoop(const HostResource& resource); + virtual ~FlashMessageLoop(); + + // Resource overrides. + virtual PPB_Flash_MessageLoop_API* AsPPB_Flash_MessageLoop_API() OVERRIDE; + + // PPB_Flash_MesssageLoop_API implementation. + virtual int32_t Run() OVERRIDE; + virtual void Quit() OVERRIDE; + virtual void RunFromHostProxy( + const RunFromHostProxyCallback& callback) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(FlashMessageLoop); +}; + +FlashMessageLoop::FlashMessageLoop(const HostResource& resource) + : Resource(OBJECT_IS_PROXY, resource) { +} + +FlashMessageLoop::~FlashMessageLoop() { +} + +PPB_Flash_MessageLoop_API* FlashMessageLoop::AsPPB_Flash_MessageLoop_API() { + return this; +} + +int32_t FlashMessageLoop::Run() { + int32_t result = PP_ERROR_FAILED; + IPC::SyncMessage* msg = new PpapiHostMsg_PPBFlashMessageLoop_Run( + API_ID_PPB_FLASH_MESSAGELOOP, host_resource(), &result); + msg->EnableMessagePumping(); + PluginDispatcher::GetForResource(this)->Send(msg); + return result; +} + +void FlashMessageLoop::Quit() { + PluginDispatcher::GetForResource(this)->Send( + new PpapiHostMsg_PPBFlashMessageLoop_Quit( + API_ID_PPB_FLASH_MESSAGELOOP, host_resource())); +} + +void FlashMessageLoop::RunFromHostProxy( + const RunFromHostProxyCallback& callback) { + // This should never be called on the plugin side. + NOTREACHED(); +} + +} // namespace + +PPB_Flash_MessageLoop_Proxy::PPB_Flash_MessageLoop_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_Flash_MessageLoop_Proxy::~PPB_Flash_MessageLoop_Proxy() { +} + +// static +PP_Resource PPB_Flash_MessageLoop_Proxy::CreateProxyResource( + PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBFlashMessageLoop_Create( + API_ID_PPB_FLASH_MESSAGELOOP, instance, &result)); + if (result.is_null()) + return 0; + return (new FlashMessageLoop(result))->GetReference(); +} + +bool PPB_Flash_MessageLoop_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_FLASH)) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_MessageLoop_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashMessageLoop_Create, + OnMsgCreate) + // We cannot use IPC_MESSAGE_HANDLER here. Because it tries to send the sync + // message reply after the handler returns. However, in this case, the + // PPB_Flash_MessageLoop_Proxy object may be destroyed before the handler + // returns. + IPC_MESSAGE_HANDLER_DELAY_REPLY(PpapiHostMsg_PPBFlashMessageLoop_Run, + OnMsgRun) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashMessageLoop_Quit, + OnMsgQuit) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Flash_MessageLoop_Proxy::OnMsgCreate(PP_Instance instance, + HostResource* result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_FLASH)) + return; + thunk::EnterResourceCreation enter(instance); + if (enter.succeeded()) { + result->SetHostResource( + instance, enter.functions()->CreateFlashMessageLoop(instance)); + } +} + +void PPB_Flash_MessageLoop_Proxy::OnMsgRun( + const HostResource& flash_message_loop, + IPC::Message* reply) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_FLASH)) + return; + + PPB_Flash_MessageLoop_API::RunFromHostProxyCallback callback = + base::Bind(&PPB_Flash_MessageLoop_Proxy::WillQuitSoon, AsWeakPtr(), + base::Passed(scoped_ptr<IPC::Message>(reply))); + + EnterHostFromHostResource<PPB_Flash_MessageLoop_API> + enter(flash_message_loop); + if (enter.succeeded()) + enter.object()->RunFromHostProxy(callback); + else + callback.Run(PP_ERROR_BADRESOURCE); +} + +void PPB_Flash_MessageLoop_Proxy::OnMsgQuit( + const ppapi::HostResource& flash_message_loop) { + EnterHostFromHostResource<PPB_Flash_MessageLoop_API> + enter(flash_message_loop); + if (enter.succeeded()) + enter.object()->Quit(); +} + +void PPB_Flash_MessageLoop_Proxy::WillQuitSoon( + scoped_ptr<IPC::Message> reply_message, + int32_t result) { + PpapiHostMsg_PPBFlashMessageLoop_Run::WriteReplyParams(reply_message.get(), + result); + Send(reply_message.release()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_flash_message_loop_proxy.h b/chromium/ppapi/proxy/ppb_flash_message_loop_proxy.h new file mode 100644 index 00000000000..238f106ddc5 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_flash_message_loop_proxy.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 PPAPI_PPB_FLASH_MESSAGE_LOOP_PROXY_H_ +#define PPAPI_PPB_FLASH_MESSAGE_LOOP_PROXY_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace IPC { +class Message; +} + +namespace ppapi { + +class HostResource; + +namespace proxy { + +class PPB_Flash_MessageLoop_Proxy + : public InterfaceProxy, + public base::SupportsWeakPtr<PPB_Flash_MessageLoop_Proxy> { + public: + explicit PPB_Flash_MessageLoop_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Flash_MessageLoop_Proxy(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + static const ApiID kApiID = API_ID_PPB_FLASH_MESSAGELOOP; + + private: + void OnMsgCreate(PP_Instance instance, ppapi::HostResource* resource); + void OnMsgRun(const ppapi::HostResource& flash_message_loop, + IPC::Message* reply); + void OnMsgQuit(const ppapi::HostResource& flash_message_loop); + + void WillQuitSoon(scoped_ptr<IPC::Message> reply_message, int32_t result); + + DISALLOW_COPY_AND_ASSIGN(PPB_Flash_MessageLoop_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PPB_FLASH_MESSAGE_LOOP_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_graphics_3d_proxy.cc b/chromium/ppapi/proxy/ppb_graphics_3d_proxy.cc new file mode 100644 index 00000000000..7d18850ea3c --- /dev/null +++ b/chromium/ppapi/proxy/ppb_graphics_3d_proxy.cc @@ -0,0 +1,497 @@ +// 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 "ppapi/proxy/ppb_graphics_3d_proxy.h" + +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_command_buffer_proxy.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Graphics3D_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace ppapi { +namespace proxy { + +namespace { + +const int32 kCommandBufferSize = 1024 * 1024; +const int32 kTransferBufferSize = 1024 * 1024; + +base::SharedMemoryHandle TransportSHMHandleFromInt(Dispatcher* dispatcher, + int shm_handle) { + // TODO(piman): Change trusted interface to return a PP_FileHandle, those + // casts are ugly. + base::PlatformFile source = +#if defined(OS_WIN) + reinterpret_cast<HANDLE>(static_cast<intptr_t>(shm_handle)); +#elif defined(OS_POSIX) + shm_handle; +#else + #error Not implemented. +#endif + // Don't close the handle, it doesn't belong to us. + return dispatcher->ShareHandleWithRemote(source, false); +} + +gpu::CommandBuffer::State GetErrorState() { + gpu::CommandBuffer::State error_state; + error_state.error = gpu::error::kGenericError; + return error_state; +} + +} // namespace + +// This class just wraps a CommandBuffer and optionally locks around every +// method. This is used to ensure that we have the Proxy lock any time we enter +// PpapiCommandBufferProxy. +// +// Note, for performance reasons, most of this code is not truly thread +// safe in the sense of multiple threads concurrently rendering to the same +// Graphics3D context; this isn't allowed, and will likely either crash or +// result in undefined behavior. It is assumed that the thread which creates +// the Graphics3D context will be the thread on which subsequent gl rendering +// will be done. +// +// TODO(nfullagar): At some point, allow multiple threads to concurrently render +// each to its own context. First step is to allow a single thread (either main +// thread or background thread) to render to a single Graphics3D context. +class Graphics3D::LockingCommandBuffer : public gpu::CommandBuffer { + public: + explicit LockingCommandBuffer(gpu::CommandBuffer* gpu_command_buffer) + : gpu_command_buffer_(gpu_command_buffer), need_to_lock_(true) { + } + virtual ~LockingCommandBuffer() { + } + void set_need_to_lock(bool need_to_lock) { need_to_lock_ = need_to_lock; } + bool need_to_lock() const { return need_to_lock_; } + + private: + // MaybeLock acquires the proxy lock on construction if and only if + // need_to_lock is true. If it acquired the lock, it releases it on + // destruction. If need_to_lock is false, then the lock must already be held. + struct MaybeLock { + explicit MaybeLock(bool need_to_lock) : locked_(need_to_lock) { + if (need_to_lock) + ppapi::ProxyLock::Acquire(); + else + ppapi::ProxyLock::AssertAcquired(); + } + ~MaybeLock() { + if (locked_) + ppapi::ProxyLock::Release(); + } + private: + bool locked_; + }; + + // gpu::CommandBuffer implementation: + virtual bool Initialize() OVERRIDE { + MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->Initialize(); + } + virtual State GetState() OVERRIDE { + MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->GetState(); + } + virtual State GetLastState() OVERRIDE { + // During a normal scene, the vast majority of calls are to GetLastState(). + // We don't allow multi-threaded rendering on the same contex, so for + // performance reasons, avoid the global lock for this entry point. We can + // get away with this here because the underlying implementation of + // GetLastState() is trivial and does not involve global or shared state + // between other contexts. + // TODO(nfullagar): We can probably skip MaybeLock for other methods, but + // the performance gain may not be worth it. + // + // MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->GetLastState(); + } + virtual int32 GetLastToken() OVERRIDE { + return GetLastState().token; + } + virtual void Flush(int32 put_offset) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->Flush(put_offset); + } + virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE { + MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->FlushSync(put_offset, last_known_get); + } + virtual void SetGetBuffer(int32 transfer_buffer_id) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->SetGetBuffer(transfer_buffer_id); + } + virtual void SetGetOffset(int32 get_offset) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->SetGetOffset(get_offset); + } + virtual gpu::Buffer CreateTransferBuffer(size_t size, + int32* id) OVERRIDE { + MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->CreateTransferBuffer(size, id); + } + virtual void DestroyTransferBuffer(int32 id) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->DestroyTransferBuffer(id); + } + virtual gpu::Buffer GetTransferBuffer(int32 id) OVERRIDE { + MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->GetTransferBuffer(id); + } + virtual void SetToken(int32 token) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->SetToken(token); + } + virtual void SetParseError(gpu::error::Error error) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->SetParseError(error); + } + virtual void SetContextLostReason( + gpu::error::ContextLostReason reason) OVERRIDE { + MaybeLock lock(need_to_lock_); + gpu_command_buffer_->SetContextLostReason(reason); + } + virtual uint32 InsertSyncPoint() OVERRIDE { + MaybeLock lock(need_to_lock_); + return gpu_command_buffer_->InsertSyncPoint(); + } + + // Weak pointer - see class Graphics3D for the scopted_ptr. + gpu::CommandBuffer* gpu_command_buffer_; + + bool need_to_lock_; +}; + +Graphics3D::Graphics3D(const HostResource& resource) + : PPB_Graphics3D_Shared(resource), + num_already_locked_calls_(0) { +} + +Graphics3D::~Graphics3D() { + DestroyGLES2Impl(); +} + +bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this); + if (!dispatcher) + return false; + + command_buffer_.reset( + new PpapiCommandBufferProxy(host_resource(), dispatcher)); + locking_command_buffer_.reset( + new LockingCommandBuffer(command_buffer_.get())); + + ScopedNoLocking already_locked(this); + return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize, + share_gles2); +} + +PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) { + return PP_FALSE; +} + +gpu::CommandBuffer::State Graphics3D::GetState() { + return GetErrorState(); +} + +PP_Bool Graphics3D::Flush(int32_t put_offset) { + return PP_FALSE; +} + +gpu::CommandBuffer::State Graphics3D::FlushSync(int32_t put_offset) { + return GetErrorState(); +} + +int32_t Graphics3D::CreateTransferBuffer(uint32_t size) { + return PP_FALSE; +} + +PP_Bool Graphics3D::DestroyTransferBuffer(int32_t id) { + return PP_FALSE; +} + +PP_Bool Graphics3D::GetTransferBuffer(int32_t id, + int* shm_handle, + uint32_t* shm_size) { + return PP_FALSE; +} + +gpu::CommandBuffer::State Graphics3D::FlushSyncFast(int32_t put_offset, + int32_t last_known_get) { + return GetErrorState(); +} + +uint32_t Graphics3D::InsertSyncPoint() { + NOTREACHED(); + return 0; +} + +gpu::CommandBuffer* Graphics3D::GetCommandBuffer() { + return locking_command_buffer_.get(); +} + +int32 Graphics3D::DoSwapBuffers() { + // gles2_impl()->SwapBuffers() results in CommandBuffer calls, and we already + // have the proxy lock. + ScopedNoLocking already_locked(this); + + gles2_impl()->SwapBuffers(); + IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers( + API_ID_PPB_GRAPHICS_3D, host_resource()); + msg->set_unblock(true); + PluginDispatcher::GetForResource(this)->Send(msg); + + return PP_OK_COMPLETIONPENDING; +} + +void Graphics3D::PushAlreadyLocked() { + ppapi::ProxyLock::AssertAcquired(); + if (num_already_locked_calls_ == 0) + locking_command_buffer_->set_need_to_lock(false); + ++num_already_locked_calls_; +} + +void Graphics3D::PopAlreadyLocked() { + // We must have Pushed before we can Pop. + DCHECK(!locking_command_buffer_->need_to_lock()); + DCHECK_GT(num_already_locked_calls_, 0); + ppapi::ProxyLock::AssertAcquired(); + --num_already_locked_calls_; + if (num_already_locked_calls_ == 0) + locking_command_buffer_->set_need_to_lock(true); +} + +PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + callback_factory_(this) { +} + +PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() { +} + +// static +PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource( + PP_Instance instance, + PP_Resource share_context, + const int32_t* attrib_list) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + HostResource share_host; + gpu::gles2::GLES2Implementation* share_gles2 = NULL; + if (share_context != 0) { + EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true); + if (enter.failed()) + return PP_ERROR_BADARGUMENT; + + PPB_Graphics3D_Shared* share_graphics = + static_cast<PPB_Graphics3D_Shared*>(enter.object()); + share_host = share_graphics->host_resource(); + share_gles2 = share_graphics->gles2_impl(); + } + + std::vector<int32_t> attribs; + if (attrib_list) { + for (const int32_t* attr = attrib_list; + attr[0] != PP_GRAPHICS3DATTRIB_NONE; + attr += 2) { + attribs.push_back(attr[0]); + attribs.push_back(attr[1]); + } + } + attribs.push_back(PP_GRAPHICS3DATTRIB_NONE); + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBGraphics3D_Create( + API_ID_PPB_GRAPHICS_3D, instance, share_host, attribs, &result)); + if (result.is_null()) + return 0; + + scoped_refptr<Graphics3D> graphics_3d(new Graphics3D(result)); + if (!graphics_3d->Init(share_gles2)) + return 0; + return graphics_3d->GetReference(); +} + +bool PPB_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Graphics3D_Proxy, msg) +#if !defined(OS_NACL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SetGetBuffer, + OnMsgSetGetBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_GetState, + OnMsgGetState) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Flush, + OnMsgFlush) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_AsyncFlush, + OnMsgAsyncFlush) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer, + OnMsgCreateTransferBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer, + OnMsgDestroyTransferBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer, + OnMsgGetTransferBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SwapBuffers, + OnMsgSwapBuffers) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_InsertSyncPoint, + OnMsgInsertSyncPoint) +#endif // !defined(OS_NACL) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBGraphics3D_SwapBuffersACK, + OnMsgSwapBuffersACK) + IPC_MESSAGE_UNHANDLED(handled = false) + + IPC_END_MESSAGE_MAP() + // FIXME(brettw) handle bad messages! + return handled; +} + +#if !defined(OS_NACL) +void PPB_Graphics3D_Proxy::OnMsgCreate(PP_Instance instance, + HostResource share_context, + const std::vector<int32_t>& attribs, + HostResource* result) { + if (attribs.empty() || + attribs.back() != PP_GRAPHICS3DATTRIB_NONE || + !(attribs.size() & 1)) + return; // Bad message. + + thunk::EnterResourceCreation enter(instance); + + if (enter.succeeded()) { + result->SetHostResource( + instance, + enter.functions()->CreateGraphics3DRaw(instance, + share_context.host_resource(), + &attribs.front())); + } +} + +void PPB_Graphics3D_Proxy::OnMsgSetGetBuffer( + const HostResource& context, + int32 transfer_buffer_id) { + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.succeeded()) + enter.object()->SetGetBuffer(transfer_buffer_id); +} + +void PPB_Graphics3D_Proxy::OnMsgGetState(const HostResource& context, + gpu::CommandBuffer::State* state, + bool* success) { + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.failed()) { + *success = false; + return; + } + *state = enter.object()->GetState(); + *success = true; +} + +void PPB_Graphics3D_Proxy::OnMsgFlush(const HostResource& context, + int32 put_offset, + int32 last_known_get, + gpu::CommandBuffer::State* state, + bool* success) { + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.failed()) { + *success = false; + return; + } + *state = enter.object()->FlushSyncFast(put_offset, last_known_get); + *success = true; +} + +void PPB_Graphics3D_Proxy::OnMsgAsyncFlush(const HostResource& context, + int32 put_offset) { + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.succeeded()) + enter.object()->Flush(put_offset); +} + +void PPB_Graphics3D_Proxy::OnMsgCreateTransferBuffer( + const HostResource& context, + uint32 size, + int32* id) { + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.succeeded()) + *id = enter.object()->CreateTransferBuffer(size); + else + *id = -1; +} + +void PPB_Graphics3D_Proxy::OnMsgDestroyTransferBuffer( + const HostResource& context, + int32 id) { + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.succeeded()) + enter.object()->DestroyTransferBuffer(id); +} + +void PPB_Graphics3D_Proxy::OnMsgGetTransferBuffer( + const HostResource& context, + int32 id, + ppapi::proxy::SerializedHandle* transfer_buffer) { + transfer_buffer->set_null_shmem(); + + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + int shm_handle = 0; + uint32_t shm_size = 0; + if (enter.succeeded() && + enter.object()->GetTransferBuffer(id, &shm_handle, &shm_size)) { + transfer_buffer->set_shmem( + TransportSHMHandleFromInt(dispatcher(), shm_handle), + shm_size); + } +} + +void PPB_Graphics3D_Proxy::OnMsgSwapBuffers(const HostResource& context) { + EnterHostFromHostResourceForceCallback<PPB_Graphics3D_API> enter( + context, callback_factory_, + &PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin, context); + if (enter.succeeded()) + enter.SetResult(enter.object()->SwapBuffers(enter.callback())); +} + +void PPB_Graphics3D_Proxy::OnMsgInsertSyncPoint(const HostResource& context, + uint32* sync_point) { + *sync_point = 0; + EnterHostFromHostResource<PPB_Graphics3D_API> enter(context); + if (enter.succeeded()) + *sync_point = enter.object()->InsertSyncPoint(); +} +#endif // !defined(OS_NACL) + +void PPB_Graphics3D_Proxy::OnMsgSwapBuffersACK(const HostResource& resource, + int32_t pp_error) { + EnterPluginFromHostResource<PPB_Graphics3D_API> enter(resource); + if (enter.succeeded()) + static_cast<Graphics3D*>(enter.object())->SwapBuffersACK(pp_error); +} + +#if !defined(OS_NACL) +void PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin( + int32_t result, + const HostResource& context) { + dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK( + API_ID_PPB_GRAPHICS_3D, context, result)); +} +#endif // !defined(OS_NACL) + +} // namespace proxy +} // namespace ppapi + diff --git a/chromium/ppapi/proxy/ppb_graphics_3d_proxy.h b/chromium/ppapi/proxy/ppb_graphics_3d_proxy.h new file mode 100644 index 00000000000..ffda80c754a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_graphics_3d_proxy.h @@ -0,0 +1,124 @@ +// 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_PROXY_PPB_GRAPHICS_3D_PROXY_H_ +#define PPAPI_PROXY_PPB_GRAPHICS_3D_PROXY_H_ + +#include <vector> + +#include "base/memory/shared_memory.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "ppapi/c/pp_graphics_3d.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_completion_callback_factory.h" +#include "ppapi/shared_impl/ppb_graphics_3d_shared.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace ppapi { + +class HostResource; + +namespace proxy { + +class SerializedHandle; + +class Graphics3D : public PPB_Graphics3D_Shared { + public: + explicit Graphics3D(const HostResource& resource); + virtual ~Graphics3D(); + + bool Init(gpu::gles2::GLES2Implementation* share_gles2); + + // Graphics3DTrusted API. These are not implemented in the proxy. + virtual PP_Bool SetGetBuffer(int32_t shm_id) OVERRIDE; + virtual gpu::CommandBuffer::State GetState() OVERRIDE; + virtual PP_Bool Flush(int32_t put_offset) OVERRIDE; + virtual gpu::CommandBuffer::State FlushSync(int32_t put_offset) 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 gpu::CommandBuffer::State FlushSyncFast( + int32_t put_offset, + int32_t last_known_get) OVERRIDE; + virtual uint32_t InsertSyncPoint() OVERRIDE; + + private: + class LockingCommandBuffer; + + // PPB_Graphics3D_Shared overrides. + virtual gpu::CommandBuffer* GetCommandBuffer() OVERRIDE; + virtual int32 DoSwapBuffers() OVERRIDE; + virtual void PushAlreadyLocked() OVERRIDE; + virtual void PopAlreadyLocked() OVERRIDE; + + int num_already_locked_calls_; + scoped_ptr<gpu::CommandBuffer> command_buffer_; + scoped_ptr<LockingCommandBuffer> locking_command_buffer_; + + DISALLOW_COPY_AND_ASSIGN(Graphics3D); +}; + +class PPB_Graphics3D_Proxy : public InterfaceProxy { + public: + PPB_Graphics3D_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Graphics3D_Proxy(); + + static PP_Resource CreateProxyResource( + PP_Instance instance, + PP_Resource share_context, + const int32_t* attrib_list); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_GRAPHICS_3D; + + private: + void OnMsgCreate(PP_Instance instance, + HostResource share_context, + const std::vector<int32_t>& attribs, + HostResource* result); + void OnMsgSetGetBuffer(const HostResource& context, + int32 id); + void OnMsgGetState(const HostResource& context, + gpu::CommandBuffer::State* state, + bool* success); + void OnMsgFlush(const HostResource& context, + int32 put_offset, + int32 last_known_get, + gpu::CommandBuffer::State* state, + bool* success); + void OnMsgAsyncFlush(const HostResource& context, + int32 put_offset); + void OnMsgCreateTransferBuffer(const HostResource& context, + uint32 size, + int32* id); + void OnMsgDestroyTransferBuffer(const HostResource& context, + int32 id); + void OnMsgGetTransferBuffer(const HostResource& context, + int32 id, + ppapi::proxy::SerializedHandle* transfer_buffer); + void OnMsgSwapBuffers(const HostResource& context); + void OnMsgInsertSyncPoint(const HostResource& context, uint32* sync_point); + // Renderer->plugin message handlers. + void OnMsgSwapBuffersACK(const HostResource& context, + int32_t pp_error); + + void SendSwapBuffersACKToPlugin(int32_t result, + const HostResource& context); + + ProxyCompletionCallbackFactory<PPB_Graphics3D_Proxy> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Graphics3D_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_GRAPHICS_3D_PROXY_H_ + diff --git a/chromium/ppapi/proxy/ppb_image_data_proxy.cc b/chromium/ppapi/proxy/ppb_image_data_proxy.cc new file mode 100644 index 00000000000..0ed3c24a37a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_image_data_proxy.cc @@ -0,0 +1,707 @@ +// 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 "ppapi/proxy/ppb_image_data_proxy.h" + +#include <string.h> // For memcpy + +#include <map> +#include <vector> + +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/memory/weak_ptr.h" +#include "build/build_config.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/thunk.h" + +#if !defined(OS_NACL) +#include "skia/ext/platform_canvas.h" +#include "ui/surface/transport_dib.h" +#endif + +using ppapi::thunk::PPB_ImageData_API; + +namespace ppapi { +namespace proxy { + +namespace { + +// How ImageData re-use works +// -------------------------- +// +// When animating plugins (like video), re-creating image datas for each frame +// and mapping the memory has a high overhead. So we try to re-use these when +// possible. +// +// 1. Plugin makes an asynchronous call that transfers an ImageData to the +// implementation of some API. +// 2. Plugin frees its ImageData reference. If it doesn't do this we can't +// re-use it. +// 3. When the last plugin ref of an ImageData is released, we don't actually +// delete it. Instead we put it on a queue where we hold onto it in the +// plugin process for a short period of time. +// 4. The API implementation that received the ImageData finishes using it. +// Without our caching system it would get deleted at this point. +// 5. The proxy in the renderer will send NotifyUnusedImageData back to the +// plugin process. We check if the given resource is in the queue and mark +// it as usable. +// 6. When the plugin requests a new image data, we check our queue and if there +// is a usable ImageData of the right size and format, we'll return it +// instead of making a new one. It's important that caching is only requested +// when the size is unlikely to change, so cache hits are high. +// +// Some notes: +// +// - We only re-use image data when the plugin and host are rapidly exchanging +// them and the size is likely to remain constant. It should be clear that +// the plugin is promising that it's done with the image. +// +// - Theoretically we could re-use them in other cases but the lifetime +// becomes more difficult to manage. The plugin could have used an ImageData +// in an arbitrary number of queued up PaintImageData calls which we would +// have to check. +// +// - If a flush takes a long time or there are many released image datas +// accumulating in our queue such that some are deleted, we will have +// released our reference by the time the renderer notifies us of an unused +// image data. In this case we just give up. +// +// - We maintain a per-instance cache. Some pages have many instances of +// Flash, for example, each of a different size. If they're all animating we +// want each to get its own image data re-use. +// +// - We generate new resource IDs when re-use happens to try to avoid weird +// problems if the plugin messes up its refcounting. + +// Keep a cache entry for this many seconds before expiring it. We get an entry +// back from the renderer after an ImageData is swapped out, so it means the +// plugin has to be painting at least two frames for this time interval to +// get caching. +static const int kMaxAgeSeconds = 2; + +// ImageDataCacheEntry --------------------------------------------------------- + +struct ImageDataCacheEntry { + ImageDataCacheEntry() : added_time(), usable(false), image() {} + ImageDataCacheEntry(ImageData* i) + : added_time(base::TimeTicks::Now()), + usable(false), + image(i) { + } + + base::TimeTicks added_time; + + // Set to true when the renderer tells us that it's OK to re-use this iamge. + bool usable; + + scoped_refptr<ImageData> image; +}; + +// ImageDataInstanceCache ------------------------------------------------------ + +// Per-instance cache of image datas. +class ImageDataInstanceCache { + public: + ImageDataInstanceCache() : next_insertion_point_(0) {} + + // These functions have the same spec as the ones in ImageDataCache. + scoped_refptr<ImageData> Get(PPB_ImageData_Shared::ImageDataType type, + int width, int height, + PP_ImageDataFormat format); + void Add(ImageData* image_data); + void ImageDataUsable(ImageData* image_data); + + // Expires old entries. Returns true if there are still entries in the list, + // false if this instance cache is now empty. + bool ExpireEntries(); + + private: + void IncrementInsertionPoint(); + + // We'll store this many ImageDatas per instance. + const static int kCacheSize = 2; + + ImageDataCacheEntry images_[kCacheSize]; + + // Index into cache where the next item will go. + int next_insertion_point_; +}; + +scoped_refptr<ImageData> ImageDataInstanceCache::Get( + PPB_ImageData_Shared::ImageDataType type, + int width, int height, + PP_ImageDataFormat format) { + // Just do a brute-force search since the cache is so small. + for (int i = 0; i < kCacheSize; i++) { + if (!images_[i].usable) + continue; + if (images_[i].image->type() != type) + continue; + const PP_ImageDataDesc& desc = images_[i].image->desc(); + if (desc.format == format && + desc.size.width == width && desc.size.height == height) { + scoped_refptr<ImageData> ret(images_[i].image); + images_[i] = ImageDataCacheEntry(); + + // Since we just removed an item, this entry is the best place to insert + // a subsequent one. + next_insertion_point_ = i; + return ret; + } + } + return scoped_refptr<ImageData>(); +} + +void ImageDataInstanceCache::Add(ImageData* image_data) { + images_[next_insertion_point_] = ImageDataCacheEntry(image_data); + IncrementInsertionPoint(); +} + +void ImageDataInstanceCache::ImageDataUsable(ImageData* image_data) { + for (int i = 0; i < kCacheSize; i++) { + if (images_[i].image.get() == image_data) { + images_[i].usable = true; + + // This test is important. The renderer doesn't guarantee how many image + // datas it has or when it notifies us when one is usable. Its possible + // to get into situations where it's always telling us the old one is + // usable, and then the older one immediately gets expired. Therefore, + // if the next insertion would overwrite this now-usable entry, make the + // next insertion overwrite some other entry to avoid the replacement. + if (next_insertion_point_ == i) + IncrementInsertionPoint(); + return; + } + } +} + +bool ImageDataInstanceCache::ExpireEntries() { + base::TimeTicks threshold_time = + base::TimeTicks::Now() - base::TimeDelta::FromSeconds(kMaxAgeSeconds); + + bool has_entry = false; + for (int i = 0; i < kCacheSize; i++) { + if (images_[i].image.get()) { + // Entry present. + if (images_[i].added_time <= threshold_time) { + // Found an entry to expire. + images_[i] = ImageDataCacheEntry(); + next_insertion_point_ = i; + } else { + // Found an entry that we're keeping. + has_entry = true; + } + } + } + return has_entry; +} + +void ImageDataInstanceCache::IncrementInsertionPoint() { + // Go to the next location, wrapping around to get LRU. + next_insertion_point_++; + if (next_insertion_point_ >= kCacheSize) + next_insertion_point_ = 0; +} + +// ImageDataCache -------------------------------------------------------------- + +class ImageDataCache { + public: + ImageDataCache() : weak_factory_(this) {} + ~ImageDataCache() {} + + static ImageDataCache* GetInstance(); + + // Retrieves an image data from the cache of the specified type, size and + // format if one exists. If one doesn't exist, this will return a null refptr. + scoped_refptr<ImageData> Get(PP_Instance instance, + PPB_ImageData_Shared::ImageDataType type, + int width, int height, + PP_ImageDataFormat format); + + // Adds the given image data to the cache. There should be no plugin + // references to it. This may delete an older item from the cache. + void Add(ImageData* image_data); + + // Notification from the renderer that the given image data is usable. + void ImageDataUsable(ImageData* image_data); + + void DidDeleteInstance(PP_Instance instance); + + private: + friend struct LeakySingletonTraits<ImageDataCache>; + + // Timer callback to expire entries for the given instance. + void OnTimer(PP_Instance instance); + + // This class does timer calls and we don't want to run these outside of the + // scope of the object. Technically, since this class is a leaked static, + // this will never happen and this factory is unnecessary. However, it's + // probably better not to make assumptions about the lifetime of this class. + base::WeakPtrFactory<ImageDataCache> weak_factory_; + + typedef std::map<PP_Instance, ImageDataInstanceCache> CacheMap; + CacheMap cache_; + + DISALLOW_COPY_AND_ASSIGN(ImageDataCache); +}; + +// static +ImageDataCache* ImageDataCache::GetInstance() { + return Singleton<ImageDataCache, + LeakySingletonTraits<ImageDataCache> >::get(); +} + +scoped_refptr<ImageData> ImageDataCache::Get( + PP_Instance instance, + PPB_ImageData_Shared::ImageDataType type, + int width, int height, + PP_ImageDataFormat format) { + CacheMap::iterator found = cache_.find(instance); + if (found == cache_.end()) + return scoped_refptr<ImageData>(); + return found->second.Get(type, width, height, format); +} + +void ImageDataCache::Add(ImageData* image_data) { + cache_[image_data->pp_instance()].Add(image_data); + + // Schedule a timer to invalidate this entry. + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + RunWhileLocked(base::Bind(&ImageDataCache::OnTimer, + weak_factory_.GetWeakPtr(), + image_data->pp_instance())), + base::TimeDelta::FromSeconds(kMaxAgeSeconds)); +} + +void ImageDataCache::ImageDataUsable(ImageData* image_data) { + CacheMap::iterator found = cache_.find(image_data->pp_instance()); + if (found != cache_.end()) + found->second.ImageDataUsable(image_data); +} + +void ImageDataCache::DidDeleteInstance(PP_Instance instance) { + cache_.erase(instance); +} + +void ImageDataCache::OnTimer(PP_Instance instance) { + CacheMap::iterator found = cache_.find(instance); + if (found == cache_.end()) + return; + if (!found->second.ExpireEntries()) { + // There are no more entries for this instance, remove it from the cache. + cache_.erase(found); + } +} + +} // namespace + +// ImageData ------------------------------------------------------------------- + +ImageData::ImageData(const HostResource& resource, + PPB_ImageData_Shared::ImageDataType type, + const PP_ImageDataDesc& desc) + : Resource(OBJECT_IS_PROXY, resource), + type_(type), + desc_(desc), + is_candidate_for_reuse_(false) { +} + +ImageData::~ImageData() { +} + +PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { + return this; +} + +void ImageData::LastPluginRefWasDeleted() { + // The plugin no longer needs this ImageData, add it to our cache if it's + // been used in a ReplaceContents. These are the ImageDatas that the renderer + // will send back ImageDataUsable messages for. + if (is_candidate_for_reuse_) + ImageDataCache::GetInstance()->Add(this); +} + +void ImageData::InstanceWasDeleted() { + ImageDataCache::GetInstance()->DidDeleteInstance(pp_instance()); +} + +PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { + memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); + return PP_TRUE; +} + +int32_t ImageData::GetSharedMemory(int* /* handle */, + uint32_t* /* byte_count */) { + // Not supported in the proxy (this method is for actually implementing the + // proxy in the host). + return PP_ERROR_NOACCESS; +} + +void ImageData::SetIsCandidateForReuse() { + is_candidate_for_reuse_ = true; +} + +void ImageData::RecycleToPlugin(bool zero_contents) { + is_candidate_for_reuse_ = false; + if (zero_contents) { + void* data = Map(); + memset(data, 0, desc_.stride * desc_.size.height); + Unmap(); + } +} + +// PlatformImageData ----------------------------------------------------------- + +#if !defined(OS_NACL) +PlatformImageData::PlatformImageData(const HostResource& resource, + const PP_ImageDataDesc& desc, + ImageHandle handle) + : ImageData(resource, PPB_ImageData_Shared::PLATFORM, desc) { +#if defined(OS_WIN) + transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); +#else + transport_dib_.reset(TransportDIB::Map(handle)); +#endif // defined(OS_WIN) +} + +PlatformImageData::~PlatformImageData() { +} + +void* PlatformImageData::Map() { + if (!mapped_canvas_.get()) { + mapped_canvas_.reset(transport_dib_->GetPlatformCanvas(desc_.size.width, + desc_.size.height)); + if (!mapped_canvas_.get()) + return NULL; + } + const SkBitmap& bitmap = + skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true); + + bitmap.lockPixels(); + return bitmap.getAddr(0, 0); +} + +void PlatformImageData::Unmap() { + // TODO(brettw) have a way to unmap a TransportDIB. Currently this isn't + // possible since deleting the TransportDIB also frees all the handles. + // We need to add a method to TransportDIB to release the handles. +} + +SkCanvas* PlatformImageData::GetPlatformCanvas() { + return mapped_canvas_.get(); +} + +SkCanvas* PlatformImageData::GetCanvas() { + return mapped_canvas_.get(); +} + +// static +ImageHandle PlatformImageData::NullHandle() { +#if defined(OS_WIN) + return NULL; +#elif defined(TOOLKIT_GTK) + return 0; +#else + return ImageHandle(); +#endif +} + +ImageHandle PlatformImageData::HandleFromInt(int32_t i) { +#if defined(OS_WIN) + return reinterpret_cast<ImageHandle>(i); +#elif defined(TOOLKIT_GTK) + return static_cast<ImageHandle>(i); +#else + return ImageHandle(i, false); +#endif +} +#endif // !defined(OS_NACL) + +// SimpleImageData ------------------------------------------------------------- + +SimpleImageData::SimpleImageData(const HostResource& resource, + const PP_ImageDataDesc& desc, + const base::SharedMemoryHandle& handle) + : ImageData(resource, PPB_ImageData_Shared::SIMPLE, desc), + shm_(handle, false /* read_only */), + size_(desc.size.width * desc.size.height * 4), + map_count_(0) { +} + +SimpleImageData::~SimpleImageData() { +} + +void* SimpleImageData::Map() { + if (map_count_++ == 0) + shm_.Map(size_); + return shm_.memory(); +} + +void SimpleImageData::Unmap() { + if (--map_count_ == 0) + shm_.Unmap(); +} + +SkCanvas* SimpleImageData::GetPlatformCanvas() { + return NULL; // No canvas available. +} + +SkCanvas* SimpleImageData::GetCanvas() { + return NULL; // No canvas available. +} + +// PPB_ImageData_Proxy --------------------------------------------------------- + +PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_ImageData_Proxy::~PPB_ImageData_Proxy() { +} + +// static +PP_Resource PPB_ImageData_Proxy::CreateProxyResource( + PP_Instance instance, + PPB_ImageData_Shared::ImageDataType type, + PP_ImageDataFormat format, + const PP_Size& size, + PP_Bool init_to_zero) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + // Check the cache. + scoped_refptr<ImageData> cached_image_data = + ImageDataCache::GetInstance()->Get(instance, type, + size.width, size.height, format); + if (cached_image_data.get()) { + // We have one we can re-use rather than allocating a new one. + cached_image_data->RecycleToPlugin(PP_ToBool(init_to_zero)); + return cached_image_data->GetReference(); + } + + HostResource result; + PP_ImageDataDesc desc; + switch (type) { + case PPB_ImageData_Shared::SIMPLE: { + ppapi::proxy::SerializedHandle image_handle_wrapper; + dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateSimple( + kApiID, instance, format, size, init_to_zero, + &result, &desc, &image_handle_wrapper)); + if (image_handle_wrapper.is_shmem()) { + base::SharedMemoryHandle image_handle = image_handle_wrapper.shmem(); + if (!result.is_null()) + return + (new SimpleImageData(result, desc, image_handle))->GetReference(); + } + break; + } + case PPB_ImageData_Shared::PLATFORM: { +#if !defined(OS_NACL) + ImageHandle image_handle = PlatformImageData::NullHandle(); + dispatcher->Send(new PpapiHostMsg_PPBImageData_CreatePlatform( + kApiID, instance, format, size, init_to_zero, + &result, &desc, &image_handle)); + if (!result.is_null()) + return + (new PlatformImageData(result, desc, image_handle))->GetReference(); +#else + // PlatformImageData shouldn't be created in untrusted code. + NOTREACHED(); +#endif + break; + } + } + + return 0; +} + +bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_ImageData_Proxy, msg) +#if !defined(OS_NACL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_CreatePlatform, + OnHostMsgCreatePlatform) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_CreateSimple, + OnHostMsgCreateSimple) +#endif + IPC_MESSAGE_HANDLER(PpapiMsg_PPBImageData_NotifyUnusedImageData, + OnPluginMsgNotifyUnusedImageData) + + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +#if !defined(OS_NACL) +// static +PP_Resource PPB_ImageData_Proxy::CreateImageData( + PP_Instance instance, + PPB_ImageData_Shared::ImageDataType type, + PP_ImageDataFormat format, + const PP_Size& size, + bool init_to_zero, + PP_ImageDataDesc* desc, + IPC::PlatformFileForTransit* image_handle, + uint32_t* byte_count) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + thunk::EnterResourceCreation enter(instance); + if (enter.failed()) + return 0; + + PP_Bool pp_init_to_zero = init_to_zero ? PP_TRUE : PP_FALSE; + PP_Resource pp_resource = 0; + switch (type) { + case PPB_ImageData_Shared::SIMPLE: { + pp_resource = enter.functions()->CreateImageDataSimple( + instance, format, &size, pp_init_to_zero); + break; + } + case PPB_ImageData_Shared::PLATFORM: { + pp_resource = enter.functions()->CreateImageData( + instance, format, &size, pp_init_to_zero); + break; + } + } + + if (!pp_resource) + return 0; + + ppapi::ScopedPPResource resource(ppapi::ScopedPPResource::PassRef(), + pp_resource); + + thunk::EnterResourceNoLock<PPB_ImageData_API> enter_resource(resource.get(), + false); + if (enter_resource.object()->Describe(desc) != PP_TRUE) { + DVLOG(1) << "CreateImageData failed: could not Describe"; + return 0; + } + + int local_fd = 0; + if (enter_resource.object()->GetSharedMemory(&local_fd, + byte_count) != PP_OK) { + DVLOG(1) << "CreateImageData failed: could not GetSharedMemory"; + return 0; + } + +#if defined(OS_WIN) + *image_handle = dispatcher->ShareHandleWithRemote( + reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)), false); +#elif defined(TOOLKIT_GTK) + // On X Windows, a PlatformImageData is backed by a SysV shared memory key, + // so embed that in a fake PlatformFileForTransit and don't share it across + // processes. + if (type == PPB_ImageData_Shared::PLATFORM) + *image_handle = IPC::PlatformFileForTransit(local_fd, false); + else + *image_handle = dispatcher->ShareHandleWithRemote(local_fd, false); +#elif defined(OS_POSIX) + *image_handle = dispatcher->ShareHandleWithRemote(local_fd, false); +#else + #error Not implemented. +#endif + + return resource.Release(); +} + +void PPB_ImageData_Proxy::OnHostMsgCreatePlatform( + PP_Instance instance, + int32_t format, + const PP_Size& size, + PP_Bool init_to_zero, + HostResource* result, + PP_ImageDataDesc* desc, + ImageHandle* result_image_handle) { + IPC::PlatformFileForTransit image_handle; + uint32_t byte_count; + PP_Resource resource = + CreateImageData(instance, + PPB_ImageData_Shared::PLATFORM, + static_cast<PP_ImageDataFormat>(format), + size, + true /* init_to_zero */, + desc, &image_handle, &byte_count); + result->SetHostResource(instance, resource); + if (resource) { +#if defined(TOOLKIT_GTK) + // On X Windows ImageHandle is a SysV shared memory key. + *result_image_handle = image_handle.fd; +#else + *result_image_handle = image_handle; +#endif + } else { + *result_image_handle = PlatformImageData::NullHandle(); + } +} + +void PPB_ImageData_Proxy::OnHostMsgCreateSimple( + PP_Instance instance, + int32_t format, + const PP_Size& size, + PP_Bool init_to_zero, + HostResource* result, + PP_ImageDataDesc* desc, + ppapi::proxy::SerializedHandle* result_image_handle) { + IPC::PlatformFileForTransit image_handle; + uint32_t byte_count; + PP_Resource resource = + CreateImageData(instance, + PPB_ImageData_Shared::SIMPLE, + static_cast<PP_ImageDataFormat>(format), + size, + true /* init_to_zero */, + desc, &image_handle, &byte_count); + + result->SetHostResource(instance, resource); + if (resource) { + result_image_handle->set_shmem(image_handle, byte_count); + } else { + result_image_handle->set_null_shmem(); + } +} +#endif // !defined(OS_NACL) + +void PPB_ImageData_Proxy::OnPluginMsgNotifyUnusedImageData( + const HostResource& old_image_data) { + PluginGlobals* plugin_globals = PluginGlobals::Get(); + if (!plugin_globals) + return; // This may happen if the plugin is maliciously sending this + // message to the renderer. + + EnterPluginFromHostResource<PPB_ImageData_API> enter(old_image_data); + if (enter.succeeded()) { + ImageData* image_data = static_cast<ImageData*>(enter.object()); + ImageDataCache::GetInstance()->ImageDataUsable(image_data); + } + + // The renderer sent us a reference with the message. If the image data was + // still cached in our process, the proxy still holds a reference so we can + // remove the one the renderer just sent is. If the proxy no longer holds a + // reference, we released everything and we should also release the one the + // renderer just sent us. + dispatcher()->Send(new PpapiHostMsg_PPBCore_ReleaseResource( + API_ID_PPB_CORE, old_image_data)); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_image_data_proxy.h b/chromium/ppapi/proxy/ppb_image_data_proxy.h new file mode 100644 index 00000000000..ab7191b0c92 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_image_data_proxy.h @@ -0,0 +1,192 @@ +// 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_PPB_IMAGE_DATA_PROXY_H_ +#define PPAPI_PPB_IMAGE_DATA_PROXY_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "build/build_config.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/ppb_image_data_shared.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/ppb_image_data_api.h" + +class TransportDIB; + +namespace ppapi { +namespace proxy { + +class SerializedHandle; + +// ImageData is an abstract base class for image data resources. Unlike most +// resources, ImageData must be public in the header since a number of other +// resources need to access it. +class PPAPI_PROXY_EXPORT ImageData + : public ppapi::Resource, + public NON_EXPORTED_BASE(ppapi::thunk::PPB_ImageData_API), + public ppapi::PPB_ImageData_Shared { + public: + virtual ~ImageData(); + + // Resource overrides. + virtual ppapi::thunk::PPB_ImageData_API* AsPPB_ImageData_API() OVERRIDE; + virtual void LastPluginRefWasDeleted() OVERRIDE; + virtual void InstanceWasDeleted() OVERRIDE; + + // PPB_ImageData API. + virtual PP_Bool Describe(PP_ImageDataDesc* desc) OVERRIDE; + virtual int32_t GetSharedMemory(int* handle, uint32_t* byte_count) OVERRIDE; + virtual void SetIsCandidateForReuse() OVERRIDE; + + PPB_ImageData_Shared::ImageDataType type() const { return type_; } + const PP_ImageDataDesc& desc() const { return desc_; } + + // Prepares this image data to be recycled to the plugin. Clears the contents + // if zero_contents is true. + void RecycleToPlugin(bool zero_contents); + + protected: + ImageData(const ppapi::HostResource& resource, + PPB_ImageData_Shared::ImageDataType type, + const PP_ImageDataDesc& desc); + + PPB_ImageData_Shared::ImageDataType type_; + PP_ImageDataDesc desc_; + + // Set to true when this ImageData is a good candidate for reuse. + bool is_candidate_for_reuse_; + + DISALLOW_COPY_AND_ASSIGN(ImageData); +}; + +// PlatformImageData is a full featured image data resource which can access +// the underlying platform-specific canvas and ImageHandle. This can't be used +// by NaCl apps. +#if !defined(OS_NACL) +class PPAPI_PROXY_EXPORT PlatformImageData : public ImageData { + public: + PlatformImageData(const ppapi::HostResource& resource, + const PP_ImageDataDesc& desc, + ImageHandle handle); + virtual ~PlatformImageData(); + + // PPB_ImageData API. + virtual void* Map() OVERRIDE; + virtual void Unmap() OVERRIDE; + virtual SkCanvas* GetPlatformCanvas() OVERRIDE; + virtual SkCanvas* GetCanvas() OVERRIDE; + + static ImageHandle NullHandle(); + static ImageHandle HandleFromInt(int32_t i); + + private: + scoped_ptr<TransportDIB> transport_dib_; + + // Null when the image isn't mapped. + scoped_ptr<SkCanvas> mapped_canvas_; + + DISALLOW_COPY_AND_ASSIGN(PlatformImageData); +}; +#endif // !defined(OS_NACL) + +// SimpleImageData is a simple, platform-independent image data resource which +// can be used by NaCl. It can also be used by trusted apps when access to the +// platform canvas isn't needed. +class PPAPI_PROXY_EXPORT SimpleImageData : public ImageData { + public: + SimpleImageData(const ppapi::HostResource& resource, + const PP_ImageDataDesc& desc, + const base::SharedMemoryHandle& handle); + virtual ~SimpleImageData(); + + // PPB_ImageData API. + virtual void* Map() OVERRIDE; + virtual void Unmap() OVERRIDE; + virtual SkCanvas* GetPlatformCanvas() OVERRIDE; + virtual SkCanvas* GetCanvas() OVERRIDE; + + private: + base::SharedMemory shm_; + uint32 size_; + int map_count_; + + DISALLOW_COPY_AND_ASSIGN(SimpleImageData); +}; + +class PPB_ImageData_Proxy : public InterfaceProxy { + public: + PPB_ImageData_Proxy(Dispatcher* dispatcher); + virtual ~PPB_ImageData_Proxy(); + + static PP_Resource CreateProxyResource( + PP_Instance instance, + PPB_ImageData_Shared::ImageDataType type, + PP_ImageDataFormat format, + const PP_Size& size, + PP_Bool init_to_zero); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // Utility for creating ImageData resources. + // This can only be called on the host side of the proxy. + // On failure, will return invalid resource (0). On success it will return a + // valid resource and the out params will be written. + // |desc| contains the result of Describe. + // |image_handle| and |byte_count| contain the result of GetSharedMemory. + // NOTE: if |init_to_zero| is false, you should write over the entire image + // to avoid leaking sensitive data to a less privileged process. + PPAPI_PROXY_EXPORT static PP_Resource CreateImageData( + PP_Instance instance, + PPB_ImageData_Shared::ImageDataType type, + PP_ImageDataFormat format, + const PP_Size& size, + bool init_to_zero, + PP_ImageDataDesc* desc, + IPC::PlatformFileForTransit* image_handle, + uint32_t* byte_count); + + static const ApiID kApiID = API_ID_PPB_IMAGE_DATA; + + private: + // Plugin->Host message handlers. + void OnHostMsgCreatePlatform( + PP_Instance instance, + int32_t format, + const PP_Size& size, + PP_Bool init_to_zero, + HostResource* result, + PP_ImageDataDesc* desc, + ImageHandle* result_image_handle); + void OnHostMsgCreateSimple( + PP_Instance instance, + int32_t format, + const PP_Size& size, + PP_Bool init_to_zero, + HostResource* result, + PP_ImageDataDesc* desc, + ppapi::proxy::SerializedHandle* result_image_handle); + + // Host->Plugin message handlers. + void OnPluginMsgNotifyUnusedImageData(const HostResource& old_image_data); + + DISALLOW_COPY_AND_ASSIGN(PPB_ImageData_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PPB_IMAGE_DATA_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_instance_proxy.cc b/chromium/ppapi/proxy/ppb_instance_proxy.cc new file mode 100644 index 00000000000..20b93649ece --- /dev/null +++ b/chromium/ppapi/proxy/ppb_instance_proxy.cc @@ -0,0 +1,1277 @@ +// 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 "ppapi/proxy/ppb_instance_proxy.h" + +#include "base/memory/ref_counted.h" +#include "build/build_config.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppb_messaging.h" +#include "ppapi/c/ppb_mouse_lock.h" +#include "ppapi/c/private/pp_content_decryptor.h" +#include "ppapi/proxy/broker_resource.h" +#include "ppapi/proxy/browser_font_singleton_resource.h" +#include "ppapi/proxy/content_decryptor_private_serializer.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/ext_crx_file_system_private_resource.h" +#include "ppapi/proxy/extensions_common_resource.h" +#include "ppapi/proxy/flash_clipboard_resource.h" +#include "ppapi/proxy/flash_file_resource.h" +#include "ppapi/proxy/flash_fullscreen_resource.h" +#include "ppapi/proxy/flash_resource.h" +#include "ppapi/proxy/gamepad_resource.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/network_proxy_resource.h" +#include "ppapi/proxy/pdf_resource.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/proxy/truetype_font_singleton_resource.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/ppb_url_util_shared.h" +#include "ppapi/shared_impl/ppb_view_shared.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_graphics_2d_api.h" +#include "ppapi/thunk/ppb_graphics_3d_api.h" +#include "ppapi/thunk/thunk.h" + +// Windows headers interfere with this file. +#ifdef PostMessage +#undef PostMessage +#endif + +using ppapi::thunk::EnterInstanceNoLock; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Graphics2D_API; +using ppapi::thunk::PPB_Graphics3D_API; +using ppapi::thunk::PPB_Instance_API; + +namespace ppapi { +namespace proxy { + +namespace { + +const char kSerializationError[] = "Failed to convert a PostMessage " + "argument from a PP_Var to a Javascript value. It may have cycles or be of " + "an unsupported type."; + +InterfaceProxy* CreateInstanceProxy(Dispatcher* dispatcher) { + return new PPB_Instance_Proxy(dispatcher); +} + +void RequestSurroundingText(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; // Instance has gone away while message was pending. + + InstanceData* data = dispatcher->GetInstanceData(instance); + DCHECK(data); // Should have it, since we still have a dispatcher. + data->is_request_surrounding_text_pending = false; + if (!data->should_do_request_surrounding_text) + return; + + // Just fake out a RequestSurroundingText message to the proxy for the PPP + // interface. + InterfaceProxy* proxy = dispatcher->GetInterfaceProxy(API_ID_PPP_TEXT_INPUT); + if (!proxy) + return; + proxy->OnMessageReceived(PpapiMsg_PPPTextInput_RequestSurroundingText( + API_ID_PPP_TEXT_INPUT, instance, + PPB_Instance_Shared::kExtraCharsForTextInput)); +} + +} // namespace + +PPB_Instance_Proxy::PPB_Instance_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + callback_factory_(this) { +} + +PPB_Instance_Proxy::~PPB_Instance_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Instance_Proxy::GetInfoPrivate() { + static const Info info = { + ppapi::thunk::GetPPB_Instance_Private_0_1_Thunk(), + PPB_INSTANCE_PRIVATE_INTERFACE_0_1, + API_ID_NONE, // 1_0 is the canonical one. + false, + &CreateInstanceProxy, + }; + return &info; +} + +bool PPB_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) { + // Prevent the dispatcher from going away during a call to ExecuteScript. + // This must happen OUTSIDE of ExecuteScript since the SerializedVars use + // the dispatcher upon return of the function (converting the + // SerializedVarReturnValue/OutParam to a SerializedVar in the destructor). +#if !defined(OS_NACL) + ScopedModuleReference death_grip(dispatcher()); +#endif + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Instance_Proxy, msg) +#if !defined(OS_NACL) + // Plugin -> Host messages. + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetWindowObject, + OnHostMsgGetWindowObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetOwnerElementObject, + OnHostMsgGetOwnerElementObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_BindGraphics, + OnHostMsgBindGraphics) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_IsFullFrame, + OnHostMsgIsFullFrame) + IPC_MESSAGE_HANDLER( + PpapiHostMsg_PPBInstance_GetAudioHardwareOutputSampleRate, + OnHostMsgGetAudioHardwareOutputSampleRate) + IPC_MESSAGE_HANDLER( + PpapiHostMsg_PPBInstance_GetAudioHardwareOutputBufferSize, + OnHostMsgGetAudioHardwareOutputBufferSize) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_ExecuteScript, + OnHostMsgExecuteScript) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetDefaultCharSet, + OnHostMsgGetDefaultCharSet) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_PostMessage, + OnHostMsgPostMessage) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_SetFullscreen, + OnHostMsgSetFullscreen) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetScreenSize, + OnHostMsgGetScreenSize) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_RequestInputEvents, + OnHostMsgRequestInputEvents) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_ClearInputEvents, + OnHostMsgClearInputEvents) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_LockMouse, + OnHostMsgLockMouse) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_UnlockMouse, + OnHostMsgUnlockMouse) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_SetCursor, + OnHostMsgSetCursor) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_SetTextInputType, + OnHostMsgSetTextInputType) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_UpdateCaretPosition, + OnHostMsgUpdateCaretPosition) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_CancelCompositionText, + OnHostMsgCancelCompositionText) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_UpdateSurroundingText, + OnHostMsgUpdateSurroundingText) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetDocumentURL, + OnHostMsgGetDocumentURL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_ResolveRelativeToDocument, + OnHostMsgResolveRelativeToDocument) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DocumentCanRequest, + OnHostMsgDocumentCanRequest) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DocumentCanAccessDocument, + OnHostMsgDocumentCanAccessDocument) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetPluginInstanceURL, + OnHostMsgGetPluginInstanceURL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_NeedKey, + OnHostMsgNeedKey) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_KeyAdded, + OnHostMsgKeyAdded) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_KeyMessage, + OnHostMsgKeyMessage) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_KeyError, + OnHostMsgKeyError) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DeliverBlock, + OnHostMsgDeliverBlock) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DecoderInitializeDone, + OnHostMsgDecoderInitializeDone) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DecoderDeinitializeDone, + OnHostMsgDecoderDeinitializeDone) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DecoderResetDone, + OnHostMsgDecoderResetDone) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DeliverFrame, + OnHostMsgDeliverFrame) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_DeliverSamples, + OnHostMsgDeliverSamples) +#endif // !defined(OS_NACL) + + // Host -> Plugin messages. + IPC_MESSAGE_HANDLER(PpapiMsg_PPBInstance_MouseLockComplete, + OnPluginMsgMouseLockComplete) + + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +PP_Bool PPB_Instance_Proxy::BindGraphics(PP_Instance instance, + PP_Resource device) { + // If device is 0, pass a null HostResource. This signals the host to unbind + // all devices. + HostResource host_resource; + PP_Resource pp_resource = 0; + if (device) { + Resource* resource = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(device); + if (!resource || resource->pp_instance() != instance) + return PP_FALSE; + host_resource = resource->host_resource(); + pp_resource = resource->pp_resource(); + } else { + // Passing 0 means unbinding all devices. + dispatcher()->Send(new PpapiHostMsg_PPBInstance_BindGraphics( + API_ID_PPB_INSTANCE, instance, 0)); + return PP_TRUE; + } + + // We need to pass different resource to Graphics 2D and 3D right now. Once + // 3D is migrated to the new design, we should be able to unify this. + EnterResourceNoLock<PPB_Graphics2D_API> enter_2d(device, false); + EnterResourceNoLock<PPB_Graphics3D_API> enter_3d(device, false); + if (enter_2d.succeeded()) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_BindGraphics( + API_ID_PPB_INSTANCE, instance, pp_resource)); + return PP_TRUE; + } else if (enter_3d.succeeded()) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_BindGraphics( + API_ID_PPB_INSTANCE, instance, host_resource.host_resource())); + return PP_TRUE; + } + return PP_FALSE; +} + +PP_Bool PPB_Instance_Proxy::IsFullFrame(PP_Instance instance) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_IsFullFrame( + API_ID_PPB_INSTANCE, instance, &result)); + return result; +} + +const ViewData* PPB_Instance_Proxy::GetViewData(PP_Instance instance) { + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + if (!data) + return NULL; + return &data->view; +} + +PP_Bool PPB_Instance_Proxy::FlashIsFullscreen(PP_Instance instance) { + // This function is only used for proxying in the renderer process. It is not + // implemented in the plugin process. + NOTREACHED(); + return PP_FALSE; +} + +PP_Var PPB_Instance_Proxy::GetWindowObject(PP_Instance instance) { + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetWindowObject( + API_ID_PPB_INSTANCE, instance, &result)); + return result.Return(dispatcher()); +} + +PP_Var PPB_Instance_Proxy::GetOwnerElementObject(PP_Instance instance) { + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetOwnerElementObject( + API_ID_PPB_INSTANCE, instance, &result)); + return result.Return(dispatcher()); +} + +PP_Var PPB_Instance_Proxy::ExecuteScript(PP_Instance instance, + PP_Var script, + PP_Var* exception) { + ReceiveSerializedException se(dispatcher(), exception); + if (se.IsThrown()) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_ExecuteScript( + API_ID_PPB_INSTANCE, instance, + SerializedVarSendInput(dispatcher(), script), &se, &result)); + return result.Return(dispatcher()); +} + +uint32_t PPB_Instance_Proxy::GetAudioHardwareOutputSampleRate( + PP_Instance instance) { + uint32_t result = PP_AUDIOSAMPLERATE_NONE; + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_GetAudioHardwareOutputSampleRate( + API_ID_PPB_INSTANCE, instance, &result)); + return result; +} + +uint32_t PPB_Instance_Proxy::GetAudioHardwareOutputBufferSize( + PP_Instance instance) { + uint32_t result = 0; + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_GetAudioHardwareOutputBufferSize( + API_ID_PPB_INSTANCE, instance, &result)); + return result; +} + +PP_Var PPB_Instance_Proxy::GetDefaultCharSet(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBInstance_GetDefaultCharSet( + API_ID_PPB_INSTANCE, instance, &result)); + return result.Return(dispatcher); +} + +void PPB_Instance_Proxy::NumberOfFindResultsChanged(PP_Instance instance, + int32_t total, + PP_Bool final_result) { + NOTIMPLEMENTED(); // Not proxied yet. +} + +void PPB_Instance_Proxy::SelectedFindResultChanged(PP_Instance instance, + int32_t index) { + NOTIMPLEMENTED(); // Not proxied yet. +} + +PP_Bool PPB_Instance_Proxy::IsFullscreen(PP_Instance instance) { + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + if (!data) + return PP_FALSE; + return PP_FromBool(data->view.is_fullscreen); +} + +PP_Bool PPB_Instance_Proxy::SetFullscreen(PP_Instance instance, + PP_Bool fullscreen) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_SetFullscreen( + API_ID_PPB_INSTANCE, instance, fullscreen, &result)); + return result; +} + +PP_Bool PPB_Instance_Proxy::GetScreenSize(PP_Instance instance, + PP_Size* size) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetScreenSize( + API_ID_PPB_INSTANCE, instance, &result, size)); + return result; +} + +Resource* PPB_Instance_Proxy::GetSingletonResource(PP_Instance instance, + SingletonResourceID id) { + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + + InstanceData::SingletonResourceMap::iterator it = + data->singleton_resources.find(id); + if (it != data->singleton_resources.end()) + return it->second.get(); + + scoped_refptr<Resource> new_singleton; + Connection connection(PluginGlobals::Get()->GetBrowserSender(), dispatcher()); + + switch (id) { + case BROKER_SINGLETON_ID: + new_singleton = new BrokerResource(connection, instance); + break; + case CRX_FILESYSTEM_SINGLETON_ID: + new_singleton = new ExtCrxFileSystemPrivateResource(connection, instance); + break; + case EXTENSIONS_COMMON_SINGLETON_ID: + new_singleton = new ExtensionsCommonResource(connection, instance); + break; + case GAMEPAD_SINGLETON_ID: + new_singleton = new GamepadResource(connection, instance); + break; + case NETWORK_PROXY_SINGLETON_ID: + new_singleton = new NetworkProxyResource(connection, instance); + break; + case TRUETYPE_FONT_SINGLETON_ID: + new_singleton = new TrueTypeFontSingletonResource(connection, instance); + break; +// Flash/trusted resources aren't needed for NaCl. +#if !defined(OS_NACL) && !defined(NACL_WIN64) + case BROWSER_FONT_SINGLETON_ID: + new_singleton = new BrowserFontSingletonResource(connection, instance); + break; + case FLASH_CLIPBOARD_SINGLETON_ID: + new_singleton = new FlashClipboardResource(connection, instance); + break; + case FLASH_FILE_SINGLETON_ID: + new_singleton = new FlashFileResource(connection, instance); + break; + case FLASH_FULLSCREEN_SINGLETON_ID: + new_singleton = new FlashFullscreenResource(connection, instance); + break; + case FLASH_SINGLETON_ID: + new_singleton = new FlashResource(connection, instance, + static_cast<PluginDispatcher*>(dispatcher())); + break; + case PDF_SINGLETON_ID: + new_singleton = new PDFResource(connection, instance); + break; +#else + case BROWSER_FONT_SINGLETON_ID: + case FLASH_CLIPBOARD_SINGLETON_ID: + case FLASH_FILE_SINGLETON_ID: + case FLASH_FULLSCREEN_SINGLETON_ID: + case FLASH_SINGLETON_ID: + case PDF_SINGLETON_ID: + NOTREACHED(); + break; +#endif // !defined(OS_NACL) && !defined(NACL_WIN64) + } + + if (!new_singleton.get()) { + // Getting here implies that a constructor is missing in the above switch. + NOTREACHED(); + return NULL; + } + + data->singleton_resources[id] = new_singleton; + return new_singleton.get(); +} + +int32_t PPB_Instance_Proxy::RequestInputEvents(PP_Instance instance, + uint32_t event_classes) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_RequestInputEvents( + API_ID_PPB_INSTANCE, instance, false, event_classes)); + + // We always register for the classes we can handle, this function validates + // the flags so we can notify it if anything was invalid, without requiring + // a sync reply. + return ValidateRequestInputEvents(false, event_classes); +} + +int32_t PPB_Instance_Proxy::RequestFilteringInputEvents( + PP_Instance instance, + uint32_t event_classes) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_RequestInputEvents( + API_ID_PPB_INSTANCE, instance, true, event_classes)); + + // We always register for the classes we can handle, this function validates + // the flags so we can notify it if anything was invalid, without requiring + // a sync reply. + return ValidateRequestInputEvents(true, event_classes); +} + +void PPB_Instance_Proxy::ClearInputEventRequest(PP_Instance instance, + uint32_t event_classes) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_ClearInputEvents( + API_ID_PPB_INSTANCE, instance, event_classes)); +} + +void PPB_Instance_Proxy::ZoomChanged(PP_Instance instance, + double factor) { + // Not proxied yet. + NOTIMPLEMENTED(); +} + +void PPB_Instance_Proxy::ZoomLimitsChanged(PP_Instance instance, + double minimum_factor, + double maximium_factor) { + // Not proxied yet. + NOTIMPLEMENTED(); +} + +PP_Var PPB_Instance_Proxy::GetDocumentURL(PP_Instance instance, + PP_URLComponents_Dev* components) { + ReceiveSerializedVarReturnValue result; + PP_URLComponents_Dev url_components; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetDocumentURL( + API_ID_PPB_INSTANCE, instance, &url_components, &result)); + if (components) + *components = url_components; + return result.Return(dispatcher()); +} + +#if !defined(OS_NACL) +PP_Var PPB_Instance_Proxy::ResolveRelativeToDocument( + PP_Instance instance, + PP_Var relative, + PP_URLComponents_Dev* components) { + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_ResolveRelativeToDocument( + API_ID_PPB_INSTANCE, instance, + SerializedVarSendInput(dispatcher(), relative), + &result)); + return PPB_URLUtil_Shared::ConvertComponentsAndReturnURL( + result.Return(dispatcher()), + components); +} + +PP_Bool PPB_Instance_Proxy::DocumentCanRequest(PP_Instance instance, + PP_Var url) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_DocumentCanRequest( + API_ID_PPB_INSTANCE, instance, + SerializedVarSendInput(dispatcher(), url), + &result)); + return result; +} + +PP_Bool PPB_Instance_Proxy::DocumentCanAccessDocument(PP_Instance instance, + PP_Instance target) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_DocumentCanAccessDocument( + API_ID_PPB_INSTANCE, instance, target, &result)); + return result; +} + +PP_Var PPB_Instance_Proxy::GetPluginInstanceURL( + PP_Instance instance, + PP_URLComponents_Dev* components) { + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetPluginInstanceURL( + API_ID_PPB_INSTANCE, instance, &result)); + return PPB_URLUtil_Shared::ConvertComponentsAndReturnURL( + result.Return(dispatcher()), + components); +} + +void PPB_Instance_Proxy::NeedKey(PP_Instance instance, + PP_Var key_system, + PP_Var session_id, + PP_Var init_data) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_NeedKey( + API_ID_PPB_INSTANCE, + instance, + SerializedVarSendInput(dispatcher(), key_system), + SerializedVarSendInput(dispatcher(), session_id), + SerializedVarSendInput(dispatcher(), init_data))); +} + +void PPB_Instance_Proxy::KeyAdded(PP_Instance instance, + PP_Var key_system, + PP_Var session_id) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_KeyAdded( + API_ID_PPB_INSTANCE, + instance, + SerializedVarSendInput(dispatcher(), key_system), + SerializedVarSendInput(dispatcher(), session_id))); +} + +void PPB_Instance_Proxy::KeyMessage(PP_Instance instance, + PP_Var key_system, + PP_Var session_id, + PP_Var message, + PP_Var default_url) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_KeyMessage( + API_ID_PPB_INSTANCE, + instance, + SerializedVarSendInput(dispatcher(), key_system), + SerializedVarSendInput(dispatcher(), session_id), + SerializedVarSendInput(dispatcher(), message), + SerializedVarSendInput(dispatcher(), default_url))); +} + +void PPB_Instance_Proxy::KeyError(PP_Instance instance, + PP_Var key_system, + PP_Var session_id, + int32_t media_error, + int32_t system_code) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_KeyError( + API_ID_PPB_INSTANCE, + instance, + SerializedVarSendInput(dispatcher(), key_system), + SerializedVarSendInput(dispatcher(), session_id), + media_error, + system_code)); +} + +void PPB_Instance_Proxy::DeliverBlock(PP_Instance instance, + PP_Resource decrypted_block, + const PP_DecryptedBlockInfo* block_info) { + PP_Resource decrypted_block_host_resource = 0; + + if (decrypted_block) { + Resource* object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(decrypted_block); + if (!object || object->pp_instance() != instance) { + NOTREACHED(); + return; + } + decrypted_block_host_resource = object->host_resource().host_resource(); + } + + std::string serialized_block_info; + if (!SerializeBlockInfo(*block_info, &serialized_block_info)) { + NOTREACHED(); + return; + } + + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_DeliverBlock(API_ID_PPB_INSTANCE, + instance, + decrypted_block_host_resource, + serialized_block_info)); +} + +void PPB_Instance_Proxy::DecoderInitializeDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id, + PP_Bool success) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_DecoderInitializeDone( + API_ID_PPB_INSTANCE, + instance, + decoder_type, + request_id, + success)); +} + +void PPB_Instance_Proxy::DecoderDeinitializeDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_DecoderDeinitializeDone( + API_ID_PPB_INSTANCE, + instance, + decoder_type, + request_id)); +} + +void PPB_Instance_Proxy::DecoderResetDone(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_DecoderResetDone( + API_ID_PPB_INSTANCE, + instance, + decoder_type, + request_id)); +} + +void PPB_Instance_Proxy::DeliverFrame(PP_Instance instance, + PP_Resource decrypted_frame, + const PP_DecryptedFrameInfo* frame_info) { + PP_Resource host_resource = 0; + if (decrypted_frame != 0) { + ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); + Resource* object = tracker->GetResource(decrypted_frame); + + if (!object || object->pp_instance() != instance) { + NOTREACHED(); + return; + } + + host_resource = object->host_resource().host_resource(); + } + + std::string serialized_frame_info; + if (!SerializeBlockInfo(*frame_info, &serialized_frame_info)) { + NOTREACHED(); + return; + } + + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_DeliverFrame(API_ID_PPB_INSTANCE, + instance, + host_resource, + serialized_frame_info)); +} + +void PPB_Instance_Proxy::DeliverSamples( + PP_Instance instance, + PP_Resource decrypted_samples, + const PP_DecryptedBlockInfo* block_info) { + PP_Resource host_resource = 0; + if (decrypted_samples != 0) { + ResourceTracker* tracker = PpapiGlobals::Get()->GetResourceTracker(); + Resource* object = tracker->GetResource(decrypted_samples); + + if (!object || object->pp_instance() != instance) { + NOTREACHED(); + return; + } + + host_resource = object->host_resource().host_resource(); + } + + std::string serialized_block_info; + if (!SerializeBlockInfo(*block_info, &serialized_block_info)) { + NOTREACHED(); + return; + } + + dispatcher()->Send( + new PpapiHostMsg_PPBInstance_DeliverSamples(API_ID_PPB_INSTANCE, + instance, + host_resource, + serialized_block_info)); +} +#endif // !defined(OS_NACL) + +void PPB_Instance_Proxy::PostMessage(PP_Instance instance, + PP_Var message) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_PostMessage( + API_ID_PPB_INSTANCE, + instance, SerializedVarSendInputShmem(dispatcher(), message, + instance))); +} + +PP_Bool PPB_Instance_Proxy::SetCursor(PP_Instance instance, + PP_MouseCursor_Type type, + PP_Resource image, + const PP_Point* hot_spot) { + // Some of these parameters are important for security. This check is in the + // plugin process just for the convenience of the caller (since we don't + // bother returning errors from the other process with a sync message). The + // parameters will be validated again in the renderer. + if (!ValidateSetCursorParams(type, image, hot_spot)) + return PP_FALSE; + + HostResource image_host_resource; + if (image) { + Resource* cursor_image = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(image); + if (!cursor_image || cursor_image->pp_instance() != instance) + return PP_FALSE; + image_host_resource = cursor_image->host_resource(); + } + + dispatcher()->Send(new PpapiHostMsg_PPBInstance_SetCursor( + API_ID_PPB_INSTANCE, instance, static_cast<int32_t>(type), + image_host_resource, hot_spot ? *hot_spot : PP_MakePoint(0, 0))); + return PP_TRUE; +} + +int32_t PPB_Instance_Proxy::LockMouse(PP_Instance instance, + scoped_refptr<TrackedCallback> callback) { + // Save the mouse callback on the instance data. + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + if (!data) + return PP_ERROR_BADARGUMENT; + if (TrackedCallback::IsPending(data->mouse_lock_callback)) + return PP_ERROR_INPROGRESS; // Already have a pending callback. + data->mouse_lock_callback = callback; + + dispatcher()->Send(new PpapiHostMsg_PPBInstance_LockMouse( + API_ID_PPB_INSTANCE, instance)); + return PP_OK_COMPLETIONPENDING; +} + +void PPB_Instance_Proxy::UnlockMouse(PP_Instance instance) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_UnlockMouse( + API_ID_PPB_INSTANCE, instance)); +} + +void PPB_Instance_Proxy::SetTextInputType(PP_Instance instance, + PP_TextInput_Type type) { + CancelAnyPendingRequestSurroundingText(instance); + dispatcher()->Send(new PpapiHostMsg_PPBInstance_SetTextInputType( + API_ID_PPB_INSTANCE, instance, type)); +} + +void PPB_Instance_Proxy::UpdateCaretPosition(PP_Instance instance, + const PP_Rect& caret, + const PP_Rect& bounding_box) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_UpdateCaretPosition( + API_ID_PPB_INSTANCE, instance, caret, bounding_box)); +} + +void PPB_Instance_Proxy::CancelCompositionText(PP_Instance instance) { + CancelAnyPendingRequestSurroundingText(instance); + dispatcher()->Send(new PpapiHostMsg_PPBInstance_CancelCompositionText( + API_ID_PPB_INSTANCE, instance)); +} + +void PPB_Instance_Proxy::SelectionChanged(PP_Instance instance) { + // The "right" way to do this is to send the message to the host. However, + // all it will do is call RequestSurroundingText with a hardcoded number of + // characters in response, which is an entire IPC round-trip. + // + // We can avoid this round-trip by just implementing the + // RequestSurroundingText logic in the plugin process. If the logic in the + // host becomes more complex (like a more adaptive number of characters), + // we'll need to reevanuate whether we want to do the round trip instead. + // + // Be careful to post a task to avoid reentering the plugin. + + InstanceData* data = + static_cast<PluginDispatcher*>(dispatcher())->GetInstanceData(instance); + if (!data) + return; + data->should_do_request_surrounding_text = true; + + if (!data->is_request_surrounding_text_pending) { + base::MessageLoop::current()->PostTask( + FROM_HERE, + RunWhileLocked(base::Bind(&RequestSurroundingText, instance))); + data->is_request_surrounding_text_pending = true; + } +} + +void PPB_Instance_Proxy::UpdateSurroundingText(PP_Instance instance, + const char* text, + uint32_t caret, + uint32_t anchor) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_UpdateSurroundingText( + API_ID_PPB_INSTANCE, instance, text, caret, anchor)); +} + +#if !defined(OS_NACL) +void PPB_Instance_Proxy::OnHostMsgGetWindowObject( + PP_Instance instance, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + result.Return(dispatcher(), enter.functions()->GetWindowObject(instance)); +} + +void PPB_Instance_Proxy::OnHostMsgGetOwnerElementObject( + PP_Instance instance, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + result.Return(dispatcher(), + enter.functions()->GetOwnerElementObject(instance)); + } +} + +void PPB_Instance_Proxy::OnHostMsgBindGraphics(PP_Instance instance, + PP_Resource device) { + // Note that we ignroe the return value here. Otherwise, this would need to + // be a slow sync call, and the plugin side of the proxy will have already + // validated the resources, so we shouldn't see errors here that weren't + // already caught. + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->BindGraphics(instance, device); +} + +void PPB_Instance_Proxy::OnHostMsgGetAudioHardwareOutputSampleRate( + PP_Instance instance, uint32_t* result) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + *result = enter.functions()->GetAudioHardwareOutputSampleRate(instance); +} + +void PPB_Instance_Proxy::OnHostMsgGetAudioHardwareOutputBufferSize( + PP_Instance instance, uint32_t* result) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + *result = enter.functions()->GetAudioHardwareOutputBufferSize(instance); +} + +void PPB_Instance_Proxy::OnHostMsgIsFullFrame(PP_Instance instance, + PP_Bool* result) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + *result = enter.functions()->IsFullFrame(instance); +} + +void PPB_Instance_Proxy::OnHostMsgExecuteScript( + PP_Instance instance, + SerializedVarReceiveInput script, + SerializedVarOutParam out_exception, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.failed()) + return; + + if (dispatcher()->IsPlugin()) + NOTREACHED(); + else + static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); + + result.Return(dispatcher(), enter.functions()->ExecuteScript( + instance, + script.Get(dispatcher()), + out_exception.OutParam(dispatcher()))); +} + +void PPB_Instance_Proxy::OnHostMsgGetDefaultCharSet( + PP_Instance instance, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + result.Return(dispatcher(), enter.functions()->GetDefaultCharSet(instance)); +} + +void PPB_Instance_Proxy::OnHostMsgSetFullscreen(PP_Instance instance, + PP_Bool fullscreen, + PP_Bool* result) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + *result = enter.functions()->SetFullscreen(instance, fullscreen); +} + + +void PPB_Instance_Proxy::OnHostMsgGetScreenSize(PP_Instance instance, + PP_Bool* result, + PP_Size* size) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + *result = enter.functions()->GetScreenSize(instance, size); +} + +void PPB_Instance_Proxy::OnHostMsgRequestInputEvents(PP_Instance instance, + bool is_filtering, + uint32_t event_classes) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + if (is_filtering) + enter.functions()->RequestFilteringInputEvents(instance, event_classes); + else + enter.functions()->RequestInputEvents(instance, event_classes); + } +} + +void PPB_Instance_Proxy::OnHostMsgClearInputEvents(PP_Instance instance, + uint32_t event_classes) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->ClearInputEventRequest(instance, event_classes); +} + +void PPB_Instance_Proxy::OnHostMsgPostMessage( + PP_Instance instance, + SerializedVarReceiveInput message) { + EnterInstanceNoLock enter(instance); + if (!message.is_valid_var()) { + PpapiGlobals::Get()->LogWithSource( + instance, PP_LOGLEVEL_ERROR, std::string(), kSerializationError); + return; + } + + if (enter.succeeded()) + enter.functions()->PostMessage(instance, + message.GetForInstance(dispatcher(), + instance)); +} + +void PPB_Instance_Proxy::OnHostMsgLockMouse(PP_Instance instance) { + // Need to be careful to always issue the callback. + pp::CompletionCallback cb = callback_factory_.NewCallback( + &PPB_Instance_Proxy::MouseLockCompleteInHost, instance); + + EnterInstanceNoLock enter(instance, cb.pp_completion_callback()); + if (enter.succeeded()) + enter.SetResult(enter.functions()->LockMouse(instance, enter.callback())); +} + +void PPB_Instance_Proxy::OnHostMsgUnlockMouse(PP_Instance instance) { + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->UnlockMouse(instance); +} + +void PPB_Instance_Proxy::OnHostMsgGetDocumentURL( + PP_Instance instance, + PP_URLComponents_Dev* components, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + PP_Var document_url = enter.functions()->GetDocumentURL(instance, + components); + result.Return(dispatcher(), document_url); + } +} + +void PPB_Instance_Proxy::OnHostMsgResolveRelativeToDocument( + PP_Instance instance, + SerializedVarReceiveInput relative, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + result.Return(dispatcher(), + enter.functions()->ResolveRelativeToDocument( + instance, relative.Get(dispatcher()), NULL)); + } +} + +void PPB_Instance_Proxy::OnHostMsgDocumentCanRequest( + PP_Instance instance, + SerializedVarReceiveInput url, + PP_Bool* result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + *result = enter.functions()->DocumentCanRequest(instance, + url.Get(dispatcher())); + } +} + +void PPB_Instance_Proxy::OnHostMsgDocumentCanAccessDocument(PP_Instance active, + PP_Instance target, + PP_Bool* result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(active); + if (enter.succeeded()) + *result = enter.functions()->DocumentCanAccessDocument(active, target); +} + +void PPB_Instance_Proxy::OnHostMsgGetPluginInstanceURL( + PP_Instance instance, + SerializedVarReturnValue result) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + result.Return(dispatcher(), + enter.functions()->GetPluginInstanceURL(instance, NULL)); + } +} + +void PPB_Instance_Proxy::OnHostMsgNeedKey(PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id, + SerializedVarReceiveInput init_data) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->NeedKey(instance, + key_system.Get(dispatcher()), + session_id.Get(dispatcher()), + init_data.Get(dispatcher())); + } +} + +void PPB_Instance_Proxy::OnHostMsgKeyAdded( + PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->KeyAdded(instance, + key_system.Get(dispatcher()), + session_id.Get(dispatcher())); + } +} + +void PPB_Instance_Proxy::OnHostMsgKeyMessage( + PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id, + SerializedVarReceiveInput message, + SerializedVarReceiveInput default_url) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->KeyMessage(instance, + key_system.Get(dispatcher()), + session_id.Get(dispatcher()), + message.Get(dispatcher()), + default_url.Get(dispatcher())); + } +} + +void PPB_Instance_Proxy::OnHostMsgKeyError( + PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id, + int32_t media_error, + int32_t system_error) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->KeyError(instance, + key_system.Get(dispatcher()), + session_id.Get(dispatcher()), + media_error, + system_error); + } +} + +void PPB_Instance_Proxy::OnHostMsgDeliverBlock( + PP_Instance instance, + PP_Resource decrypted_block, + const std::string& serialized_block_info) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + PP_DecryptedBlockInfo block_info; + if (!DeserializeBlockInfo(serialized_block_info, &block_info)) + return; + + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->DeliverBlock(instance, decrypted_block, &block_info); +} + +void PPB_Instance_Proxy::OnHostMsgDecoderInitializeDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id, + PP_Bool success) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->DecoderInitializeDone(instance, + decoder_type, + request_id, + success); + } +} + +void PPB_Instance_Proxy::OnHostMsgDecoderDeinitializeDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->DecoderDeinitializeDone(instance, + decoder_type, + request_id); +} + +void PPB_Instance_Proxy::OnHostMsgDecoderResetDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->DecoderResetDone(instance, decoder_type, request_id); +} + +void PPB_Instance_Proxy::OnHostMsgDeliverFrame( + PP_Instance instance, + PP_Resource decrypted_frame, + const std::string& serialized_frame_info) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + PP_DecryptedFrameInfo frame_info; + if (!DeserializeBlockInfo(serialized_frame_info, &frame_info)) + return; + + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->DeliverFrame(instance, decrypted_frame, &frame_info); +} + +void PPB_Instance_Proxy::OnHostMsgDeliverSamples( + PP_Instance instance, + PP_Resource audio_frames, + const std::string& serialized_block_info) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE)) + return; + PP_DecryptedBlockInfo block_info; + if (!DeserializeBlockInfo(serialized_block_info, &block_info)) + return; + + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->DeliverSamples(instance, audio_frames, &block_info); +} + +void PPB_Instance_Proxy::OnHostMsgSetCursor( + PP_Instance instance, + int32_t type, + const ppapi::HostResource& custom_image, + const PP_Point& hot_spot) { + // This API serves PPB_CursorControl_Dev and PPB_MouseCursor, so is public. + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->SetCursor( + instance, static_cast<PP_MouseCursor_Type>(type), + custom_image.host_resource(), &hot_spot); + } +} + +void PPB_Instance_Proxy::OnHostMsgSetTextInputType(PP_Instance instance, + PP_TextInput_Type type) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->SetTextInputType(instance, type); +} + +void PPB_Instance_Proxy::OnHostMsgUpdateCaretPosition( + PP_Instance instance, + const PP_Rect& caret, + const PP_Rect& bounding_box) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) + enter.functions()->UpdateCaretPosition(instance, caret, bounding_box); +} + +void PPB_Instance_Proxy::OnHostMsgCancelCompositionText(PP_Instance instance) { + EnterInstanceNoLock enter(instance); + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + if (enter.succeeded()) + enter.functions()->CancelCompositionText(instance); +} + +void PPB_Instance_Proxy::OnHostMsgUpdateSurroundingText( + PP_Instance instance, + const std::string& text, + uint32_t caret, + uint32_t anchor) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return; + EnterInstanceNoLock enter(instance); + if (enter.succeeded()) { + enter.functions()->UpdateSurroundingText(instance, text.c_str(), caret, + anchor); + } +} +#endif // !defined(OS_NACL) + +void PPB_Instance_Proxy::OnPluginMsgMouseLockComplete(PP_Instance instance, + int32_t result) { + if (!dispatcher()->IsPlugin()) + return; + + // Save the mouse callback on the instance data. + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + if (!data) + return; // Instance was probably deleted. + if (!TrackedCallback::IsPending(data->mouse_lock_callback)) { + NOTREACHED(); + return; + } + data->mouse_lock_callback->Run(result); +} + +#if !defined(OS_NACL) +void PPB_Instance_Proxy::MouseLockCompleteInHost(int32_t result, + PP_Instance instance) { + dispatcher()->Send(new PpapiMsg_PPBInstance_MouseLockComplete( + API_ID_PPB_INSTANCE, instance, result)); +} +#endif // !defined(OS_NACL) + +void PPB_Instance_Proxy::CancelAnyPendingRequestSurroundingText( + PP_Instance instance) { + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + if (!data) + return; // Instance was probably deleted. + data->should_do_request_surrounding_text = false; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_instance_proxy.h b/chromium/ppapi/proxy/ppb_instance_proxy.h new file mode 100644 index 00000000000..6df4f8d9eab --- /dev/null +++ b/chromium/ppapi/proxy/ppb_instance_proxy.h @@ -0,0 +1,276 @@ +// 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_PROXY_PPB_INSTANCE_PROXY_H_ +#define PPAPI_PROXY_PPB_INSTANCE_PROXY_H_ + +#include <string> + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_completion_callback_factory.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/ppb_instance_shared.h" +#include "ppapi/shared_impl/singleton_resource_id.h" +#include "ppapi/thunk/ppb_instance_api.h" +#include "ppapi/utility/completion_callback_factory.h" + +// Windows headers interfere with this file. +#ifdef PostMessage +#undef PostMessage +#endif + +struct PP_DecryptedBlockInfo; +struct PP_DecryptedFrameInfo; + +namespace ppapi { +namespace proxy { + +class SerializedVarReceiveInput; +class SerializedVarOutParam; +class SerializedVarReturnValue; + +class PPB_Instance_Proxy : public InterfaceProxy, + public PPB_Instance_Shared { + public: + PPB_Instance_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Instance_Proxy(); + + static const Info* GetInfoPrivate(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // 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 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 Resource* GetSingletonResource(PP_Instance instance, + 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<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 GetDocumentURL(PP_Instance instance, + PP_URLComponents_Dev* components) OVERRIDE; +#if !defined(OS_NACL) + 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 GetPluginInstanceURL( + PP_Instance instance, + PP_URLComponents_Dev* components) OVERRIDE; + 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; +#endif // !defined(OS_NACL) + + static const ApiID kApiID = API_ID_PPB_INSTANCE; + + private: + // Plugin -> Host message handlers. + void OnHostMsgGetWindowObject(PP_Instance instance, + SerializedVarReturnValue result); + void OnHostMsgGetOwnerElementObject(PP_Instance instance, + SerializedVarReturnValue result); + void OnHostMsgBindGraphics(PP_Instance instance, + PP_Resource device); + void OnHostMsgIsFullFrame(PP_Instance instance, PP_Bool* result); + void OnHostMsgExecuteScript(PP_Instance instance, + SerializedVarReceiveInput script, + SerializedVarOutParam out_exception, + SerializedVarReturnValue result); + void OnHostMsgGetAudioHardwareOutputSampleRate(PP_Instance instance, + uint32_t *result); + void OnHostMsgGetAudioHardwareOutputBufferSize(PP_Instance instance, + uint32_t *result); + void OnHostMsgGetDefaultCharSet(PP_Instance instance, + SerializedVarReturnValue result); + void OnHostMsgSetFullscreen(PP_Instance instance, + PP_Bool fullscreen, + PP_Bool* result); + void OnHostMsgGetScreenSize(PP_Instance instance, + PP_Bool* result, + PP_Size* size); + void OnHostMsgRequestInputEvents(PP_Instance instance, + bool is_filtering, + uint32_t event_classes); + void OnHostMsgClearInputEvents(PP_Instance instance, + uint32_t event_classes); + void OnHostMsgPostMessage(PP_Instance instance, + SerializedVarReceiveInput message); + void OnHostMsgLockMouse(PP_Instance instance); + void OnHostMsgUnlockMouse(PP_Instance instance); + void OnHostMsgSetCursor(PP_Instance instance, + int32_t type, + const ppapi::HostResource& custom_image, + const PP_Point& hot_spot); + void OnHostMsgSetTextInputType(PP_Instance instance, PP_TextInput_Type type); + void OnHostMsgUpdateCaretPosition(PP_Instance instance, + const PP_Rect& caret, + const PP_Rect& bounding_box); + void OnHostMsgCancelCompositionText(PP_Instance instance); + void OnHostMsgUpdateSurroundingText( + PP_Instance instance, + const std::string& text, + uint32_t caret, + uint32_t anchor); + void OnHostMsgGetDocumentURL(PP_Instance instance, + PP_URLComponents_Dev* components, + SerializedVarReturnValue result); + +#if !defined(OS_NACL) + void OnHostMsgResolveRelativeToDocument(PP_Instance instance, + SerializedVarReceiveInput relative, + SerializedVarReturnValue result); + void OnHostMsgDocumentCanRequest(PP_Instance instance, + SerializedVarReceiveInput url, + PP_Bool* result); + void OnHostMsgDocumentCanAccessDocument(PP_Instance active, + PP_Instance target, + PP_Bool* result); + void OnHostMsgGetPluginInstanceURL(PP_Instance instance, + SerializedVarReturnValue result); + virtual void OnHostMsgNeedKey(PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id, + SerializedVarReceiveInput init_data); + virtual void OnHostMsgKeyAdded(PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id); + virtual void OnHostMsgKeyMessage(PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id, + SerializedVarReceiveInput message, + SerializedVarReceiveInput default_url); + virtual void OnHostMsgKeyError(PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput session_id, + int32_t media_error, + int32_t system_code); + virtual void OnHostMsgDecoderInitializeDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id, + PP_Bool success); + virtual void OnHostMsgDecoderDeinitializeDone( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id); + virtual void OnHostMsgDecoderResetDone(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id); + virtual void OnHostMsgDeliverBlock(PP_Instance instance, + PP_Resource decrypted_block, + const std::string& serialized_block_info); + virtual void OnHostMsgDeliverFrame(PP_Instance instance, + PP_Resource decrypted_frame, + const std::string& serialized_block_info); + virtual void OnHostMsgDeliverSamples( + PP_Instance instance, + PP_Resource audio_frames, + const std::string& serialized_block_info); +#endif // !defined(OS_NACL) + + // Host -> Plugin message handlers. + void OnPluginMsgMouseLockComplete(PP_Instance instance, int32_t result); + + void MouseLockCompleteInHost(int32_t result, PP_Instance instance); + + // Other helpers. + void CancelAnyPendingRequestSurroundingText(PP_Instance instance); + + ProxyCompletionCallbackFactory<PPB_Instance_Proxy> callback_factory_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_INSTANCE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_message_loop_proxy.cc b/chromium/ppapi/proxy/ppb_message_loop_proxy.cc new file mode 100644 index 00000000000..7e2cdfa6559 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_message_loop_proxy.cc @@ -0,0 +1,274 @@ +// 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 "ppapi/proxy/ppb_message_loop_proxy.h" + +#include <vector> + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_proxy.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_message_loop.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/thunk/enter.h" + +using ppapi::thunk::PPB_MessageLoop_API; + +namespace ppapi { +namespace proxy { + +namespace { +typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop; +} + +MessageLoopResource::MessageLoopResource(PP_Instance instance) + : MessageLoopShared(instance), + nested_invocations_(0), + destroyed_(false), + should_destroy_(false), + is_main_thread_loop_(false) { +} + +MessageLoopResource::MessageLoopResource(ForMainThread for_main_thread) + : MessageLoopShared(for_main_thread), + nested_invocations_(0), + destroyed_(false), + should_destroy_(false), + is_main_thread_loop_(true) { + // We attach the main thread immediately. We can't use AttachToCurrentThread, + // because the MessageLoop already exists. + + // This must be called only once, so the slot must be empty. + CHECK(!PluginGlobals::Get()->msg_loop_slot()); + // We don't add a reference for TLS here, so we don't release it. Instead, + // this loop is owned by PluginGlobals. Contrast with AttachToCurrentThread + // where we register ReleaseMessageLoop with TLS and call AddRef. + base::ThreadLocalStorage::Slot* slot = new base::ThreadLocalStorage::Slot(); + PluginGlobals::Get()->set_msg_loop_slot(slot); + + slot->Set(this); + + loop_proxy_ = base::MessageLoopProxy::current(); +} + + +MessageLoopResource::~MessageLoopResource() { +} + +PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() { + return this; +} + +int32_t MessageLoopResource::AttachToCurrentThread() { + if (is_main_thread_loop_) + return PP_ERROR_INPROGRESS; + + PluginGlobals* globals = PluginGlobals::Get(); + + base::ThreadLocalStorage::Slot* slot = globals->msg_loop_slot(); + if (!slot) { + slot = new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop); + globals->set_msg_loop_slot(slot); + } else { + if (slot->Get()) + return PP_ERROR_INPROGRESS; + } + // TODO(dmichael) check that the current thread can support a message loop. + + // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an + // internal ref and not a plugin ref so the plugin can't accidentally + // release it. This is released by ReleaseMessageLoop(). + AddRef(); + slot->Set(this); + + loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT)); + loop_proxy_ = base::MessageLoopProxy::current(); + + // Post all pending work to the message loop. + for (size_t i = 0; i < pending_tasks_.size(); i++) { + const TaskInfo& info = pending_tasks_[i]; + PostClosure(info.from_here, info.closure, info.delay_ms); + } + pending_tasks_.clear(); + + return PP_OK; +} + +int32_t MessageLoopResource::Run() { + if (!IsCurrent()) + return PP_ERROR_WRONG_THREAD; + if (is_main_thread_loop_) + return PP_ERROR_INPROGRESS; + + nested_invocations_++; + CallWhileUnlocked( + base::Bind(&base::MessageLoop::Run, base::Unretained(loop_.get()))); + nested_invocations_--; + + if (should_destroy_ && nested_invocations_ == 0) { + loop_proxy_ = NULL; + loop_.reset(); + destroyed_ = true; + } + return PP_OK; +} + +int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback, + int64_t delay_ms) { + if (!callback.func) + return PP_ERROR_BADARGUMENT; + if (destroyed_) + return PP_ERROR_FAILED; + PostClosure(FROM_HERE, + base::Bind(callback.func, callback.user_data, + static_cast<int32_t>(PP_OK)), + delay_ms); + return PP_OK; +} + +int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) { + if (is_main_thread_loop_) + return PP_ERROR_WRONG_THREAD; + + if (PP_ToBool(should_destroy)) + should_destroy_ = true; + + if (IsCurrent() && nested_invocations_ > 0) + loop_->Quit(); + else + PostClosure(FROM_HERE, base::MessageLoop::QuitClosure(), 0); + return PP_OK; +} + +// static +MessageLoopResource* MessageLoopResource::GetCurrent() { + PluginGlobals* globals = PluginGlobals::Get(); + if (!globals->msg_loop_slot()) + return NULL; + return reinterpret_cast<MessageLoopResource*>( + globals->msg_loop_slot()->Get()); +} + +void MessageLoopResource::DetachFromThread() { + // Note that the message loop must be destroyed on the thread it was created + // on. + loop_proxy_ = NULL; + loop_.reset(); + + // Cancel out the AddRef in AttachToCurrentThread(). + Release(); + // DANGER: may delete this. +} + +bool MessageLoopResource::IsCurrent() const { + PluginGlobals* globals = PluginGlobals::Get(); + if (!globals->msg_loop_slot()) + return false; // Can't be current if there's nothing in the slot. + return static_cast<const void*>(globals->msg_loop_slot()->Get()) == + static_cast<const void*>(this); +} + +void MessageLoopResource::PostClosure( + const tracked_objects::Location& from_here, + const base::Closure& closure, + int64 delay_ms) { + if (loop_proxy_.get()) { + loop_proxy_->PostDelayedTask( + from_here, closure, base::TimeDelta::FromMilliseconds(delay_ms)); + } else { + TaskInfo info; + info.from_here = FROM_HERE; + info.closure = closure; + info.delay_ms = delay_ms; + pending_tasks_.push_back(info); + } +} + +// static +void MessageLoopResource::ReleaseMessageLoop(void* value) { + static_cast<MessageLoopResource*>(value)->DetachFromThread(); +} + +// ----------------------------------------------------------------------------- + +PP_Resource Create(PP_Instance instance) { + ProxyAutoLock lock; + // Validate the instance. + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + return (new MessageLoopResource(instance))->GetReference(); +} + +PP_Resource GetForMainThread() { + ProxyAutoLock lock; + return PluginGlobals::Get()->loop_for_main_thread()->GetReference(); +} + +PP_Resource GetCurrent() { + ProxyAutoLock lock; + Resource* resource = MessageLoopResource::GetCurrent(); + if (resource) + return resource->GetReference(); + return 0; +} + +int32_t AttachToCurrentThread(PP_Resource message_loop) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->AttachToCurrentThread(); + return PP_ERROR_BADRESOURCE; +} + +int32_t Run(PP_Resource message_loop) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->Run(); + return PP_ERROR_BADRESOURCE; +} + +int32_t PostWork(PP_Resource message_loop, + PP_CompletionCallback callback, + int64_t delay_ms) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->PostWork(callback, delay_ms); + return PP_ERROR_BADRESOURCE; +} + +int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->PostQuit(should_destroy); + return PP_ERROR_BADRESOURCE; +} + +const PPB_MessageLoop_1_0 ppb_message_loop_interface = { + &Create, + &GetForMainThread, + &GetCurrent, + &AttachToCurrentThread, + &Run, + &PostWork, + &PostQuit +}; + +PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() { +} + +// static +const PPB_MessageLoop_1_0* PPB_MessageLoop_Proxy::GetInterface() { + return &ppb_message_loop_interface; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_message_loop_proxy.h b/chromium/ppapi/proxy/ppb_message_loop_proxy.h new file mode 100644 index 00000000000..4e3a9332286 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_message_loop_proxy.h @@ -0,0 +1,111 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_MESSAGE_LOOP_PROXY_H_ +#define PPAPI_PROXY_PPB_MESSAGE_LOOP_PROXY_H_ + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/ppb_message_loop_shared.h" +#include "ppapi/thunk/ppb_message_loop_api.h" + +struct PPB_MessageLoop_1_0; + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT MessageLoopResource : public MessageLoopShared { + public: + explicit MessageLoopResource(PP_Instance instance); + // Construct the one MessageLoopResource for the main thread. This must be + // invoked on the main thread. + explicit MessageLoopResource(ForMainThread); + virtual ~MessageLoopResource(); + + // Resource overrides. + virtual thunk::PPB_MessageLoop_API* AsPPB_MessageLoop_API() OVERRIDE; + + // PPB_MessageLoop_API implementation. + virtual int32_t AttachToCurrentThread() OVERRIDE; + virtual int32_t Run() OVERRIDE; + virtual int32_t PostWork(PP_CompletionCallback callback, + int64_t delay_ms) OVERRIDE; + virtual int32_t PostQuit(PP_Bool should_destroy) OVERRIDE; + + static MessageLoopResource* GetCurrent(); + void DetachFromThread(); + bool is_main_thread_loop() const { + return is_main_thread_loop_; + } + + private: + struct TaskInfo { + tracked_objects::Location from_here; + base::Closure closure; + int64 delay_ms; + }; + + // Returns true if the object is associated with the current thread. + bool IsCurrent() const; + + // Handles posting to the message loop if there is one, or the pending queue + // if there isn't. + // NOTE: The given closure will be run *WITHOUT* acquiring the Proxy lock. + // This only makes sense for user code and completely thread-safe + // proxy operations (e.g., MessageLoop::QuitClosure). + virtual void PostClosure(const tracked_objects::Location& from_here, + const base::Closure& closure, + int64 delay_ms) OVERRIDE; + + // TLS destructor function. + static void ReleaseMessageLoop(void* value); + + // Created when we attach to the current thread, since MessageLoop assumes + // that it's created on the thread it will run on. NULL for the main thread + // loop, since that's owned by somebody else. This is needed for Run and Quit. + // Any time we post tasks, we should post them using loop_proxy_. + scoped_ptr<base::MessageLoop> loop_; + scoped_refptr<base::MessageLoopProxy> loop_proxy_; + + // Number of invocations of Run currently on the stack. + int nested_invocations_; + + // Set to true when the message loop is destroyed to prevent forther + // posting of work. + bool destroyed_; + + // Set to true if all message loop invocations should exit and that the + // loop should be destroyed once it reaches the outermost Run invocation. + bool should_destroy_; + + bool is_main_thread_loop_; + + // Since we allow tasks to be posted before the message loop is actually + // created (when it's associated with a thread), we keep tasks posted here + // until that happens. Once the loop_ is created, this is unused. + std::vector<TaskInfo> pending_tasks_; + + DISALLOW_COPY_AND_ASSIGN(MessageLoopResource); +}; + +class PPB_MessageLoop_Proxy : public InterfaceProxy { + public: + explicit PPB_MessageLoop_Proxy(Dispatcher* dispatcher); + virtual ~PPB_MessageLoop_Proxy(); + + static const PPB_MessageLoop_1_0* GetInterface(); + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_MessageLoop_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_MESSAGE_LOOP_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_network_monitor_private_proxy.cc b/chromium/ppapi/proxy/ppb_network_monitor_private_proxy.cc new file mode 100644 index 00000000000..055ed2e3a7b --- /dev/null +++ b/chromium/ppapi/proxy/ppb_network_monitor_private_proxy.cc @@ -0,0 +1,156 @@ +// 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 "ppapi/proxy/ppb_network_monitor_private_proxy.h" + +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/thunk/ppb_network_monitor_private_api.h" + +namespace ppapi { +namespace proxy { + +class PPB_NetworkMonitor_Private_Proxy::NetworkMonitor + : public Resource, + public thunk::PPB_NetworkMonitor_Private_API, + public base::SupportsWeakPtr< + PPB_NetworkMonitor_Private_Proxy::NetworkMonitor> { + public: + NetworkMonitor(PP_Instance instance, + PPB_NetworkMonitor_Private_Proxy* proxy, + PPB_NetworkMonitor_Callback callback, + void* user_data) + : Resource(OBJECT_IS_PROXY, instance), + proxy_(proxy), + callback_(callback), + user_data_(user_data) { + } + + virtual ~NetworkMonitor() { + proxy_->OnNetworkMonitorDeleted(this, pp_instance()); + } + + + // Resource overrides. + virtual ppapi::thunk::PPB_NetworkMonitor_Private_API* + AsPPB_NetworkMonitor_Private_API() OVERRIDE { + return this; + } + + // This is invoked when a network list is received for this monitor (either + // initially or on a change). It acquires the ProxyLock inside because + // ObserverListThreadSafe does not support Bind/Closure, otherwise we would + // wrap the call with a lock using RunWhileLocked. + void OnNetworkListReceivedLocks( + const scoped_refptr<NetworkListStorage>& list) { + ProxyAutoLock lock; + PP_Resource list_resource = + PPB_NetworkList_Private_Shared::Create( + OBJECT_IS_PROXY, pp_instance(), list); + CallWhileUnlocked(callback_, user_data_, list_resource); + } + + private: + PPB_NetworkMonitor_Private_Proxy* proxy_; + PPB_NetworkMonitor_Callback callback_; + void* user_data_; + + DISALLOW_COPY_AND_ASSIGN(NetworkMonitor); +}; + +PPB_NetworkMonitor_Private_Proxy::PPB_NetworkMonitor_Private_Proxy( + Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + monitors_(new ObserverListThreadSafe<NetworkMonitor>()), + monitors_count_(0) { +} + +PPB_NetworkMonitor_Private_Proxy::~PPB_NetworkMonitor_Private_Proxy() { + monitors_->AssertEmpty(); +} + +// static +PP_Resource PPB_NetworkMonitor_Private_Proxy::CreateProxyResource( + PP_Instance instance, + PPB_NetworkMonitor_Callback callback, + void* user_data) { + // TODO(dmichael): Check that this thread has a valid message loop associated + // with it. + if (!callback) + return 0; + + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + PPB_NetworkMonitor_Private_Proxy* proxy = + static_cast<PPB_NetworkMonitor_Private_Proxy*>( + dispatcher->GetInterfaceProxy(kApiID)); + if (!proxy) + return 0; + + scoped_refptr<NetworkMonitor> result( + new NetworkMonitor(instance, proxy, callback, user_data)); + proxy->monitors_->AddObserver(result.get()); + + proxy->monitors_count_++; + if (proxy->monitors_count_ == 1) { + // If that is the first network monitor then send Start message. + PluginGlobals::Get()->GetBrowserSender()->Send( + new PpapiHostMsg_PPBNetworkMonitor_Start( + dispatcher->plugin_dispatcher_id())); + + // We could have received network list message after sending the + // previous Stop message. This list is stale now, so reset it + // here. + proxy->current_list_ = NULL; + } else if (proxy->current_list_.get()) { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&NetworkMonitor::OnNetworkListReceivedLocks, + result->AsWeakPtr(), + proxy->current_list_)); + } + + return result->GetReference(); +} + +bool PPB_NetworkMonitor_Private_Proxy::OnMessageReceived( + const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_NetworkMonitor_Private_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBNetworkMonitor_NetworkList, + OnPluginMsgNetworkList) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_NetworkMonitor_Private_Proxy::OnPluginMsgNetworkList( + uint32 plugin_dispatcher_id, + const ppapi::NetworkList& list) { + scoped_refptr<NetworkListStorage> list_storage(new NetworkListStorage(list)); + current_list_ = list_storage; + monitors_->Notify(&NetworkMonitor::OnNetworkListReceivedLocks, list_storage); +} + +void PPB_NetworkMonitor_Private_Proxy::OnNetworkMonitorDeleted( + NetworkMonitor* monitor, + PP_Instance instance) { + monitors_->RemoveObserver(monitor); + monitors_count_--; + if (monitors_count_ == 0) { + // Send Stop message if that was the last NetworkMonitor. + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (dispatcher) { + PluginGlobals::Get()->GetBrowserSender()->Send( + new PpapiHostMsg_PPBNetworkMonitor_Stop( + dispatcher->plugin_dispatcher_id())); + } + current_list_ = NULL; + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_network_monitor_private_proxy.h b/chromium/ppapi/proxy/ppb_network_monitor_private_proxy.h new file mode 100644 index 00000000000..e764b0cb34f --- /dev/null +++ b/chromium/ppapi/proxy/ppb_network_monitor_private_proxy.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 PPAPI_PROXY_PPB_NETWORK_MONITOR_PRIVATE_PROXY_H_ +#define PPAPI_PROXY_PPB_NETWORK_MONITOR_PRIVATE_PROXY_H_ + +#include <list> + +#include "base/observer_list_threadsafe.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/ppb_network_list_private_shared.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/thunk/ppb_network_monitor_private_api.h" + +namespace base { +class MessageLoopProxy; +} // namespace base + +namespace ppapi { +namespace proxy { + +class PPB_NetworkMonitor_Private_Proxy : public InterfaceProxy { + public: + explicit PPB_NetworkMonitor_Private_Proxy(Dispatcher* dispatcher); + virtual ~PPB_NetworkMonitor_Private_Proxy(); + + // Creates n NetworkManager object in the plugin process. + static PP_Resource CreateProxyResource(PP_Instance instance, + PPB_NetworkMonitor_Callback callback, + void* user_data); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_NETWORKMANAGER_PRIVATE; + + private: + class NetworkMonitor; + friend class NetworkMonitor; + + // IPC message handler for the messages received from the browser. + void OnPluginMsgNetworkList(uint32 plugin_dispatcher_id, + const ppapi::NetworkList& list); + + // Called by NetworkMonitor destructor. + void OnNetworkMonitorDeleted(NetworkMonitor* monitor, + PP_Instance instance); + + // We use ObserverListThreadSafe because we want to send notifications to the + // same thread that created the NetworkMonitor. + scoped_refptr<ObserverListThreadSafe<NetworkMonitor> > monitors_; + + int monitors_count_; + scoped_refptr<NetworkListStorage> current_list_; + + DISALLOW_COPY_AND_ASSIGN(PPB_NetworkMonitor_Private_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_NETWORK_MONITOR_PRIVATE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_tcp_socket_private_proxy.cc b/chromium/ppapi/proxy/ppb_tcp_socket_private_proxy.cc new file mode 100644 index 00000000000..58199fd140e --- /dev/null +++ b/chromium/ppapi/proxy/ppb_tcp_socket_private_proxy.cc @@ -0,0 +1,263 @@ +// 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 "ppapi/proxy/ppb_tcp_socket_private_proxy.h" + +#include <map> + +#include "base/logging.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" +#include "ppapi/shared_impl/private/tcp_socket_private_impl.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/socket_option_data.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef std::map<uint32, TCPSocketPrivateImpl*> IDToSocketMap; +IDToSocketMap* g_id_to_socket = NULL; + +class TCPSocket : public TCPSocketPrivateImpl { + public: + // C-tor for new sockets. + TCPSocket(const HostResource& resource, uint32 socket_id); + // C-tor for already connected sockets. + TCPSocket(const HostResource& resource, + uint32 socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); + virtual ~TCPSocket(); + + 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 SocketOptionData& value) OVERRIDE; + + private: + void SendToBrowser(IPC::Message* msg); + + DISALLOW_COPY_AND_ASSIGN(TCPSocket); +}; + +TCPSocket::TCPSocket(const HostResource& resource, uint32 socket_id) + : TCPSocketPrivateImpl(resource, socket_id) { + if (!g_id_to_socket) + g_id_to_socket = new IDToSocketMap(); + DCHECK(g_id_to_socket->find(socket_id) == g_id_to_socket->end()); + (*g_id_to_socket)[socket_id] = this; +} + +TCPSocket::TCPSocket(const HostResource& resource, + uint32 socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) + : TCPSocketPrivateImpl(resource, socket_id) { + if (!g_id_to_socket) + g_id_to_socket = new IDToSocketMap(); + DCHECK(g_id_to_socket->find(socket_id) == g_id_to_socket->end()); + + connection_state_ = CONNECTED; + local_addr_ = local_addr; + remote_addr_ = remote_addr; + + (*g_id_to_socket)[socket_id] = this; +} + +TCPSocket::~TCPSocket() { + Disconnect(); +} + +void TCPSocket::SendConnect(const std::string& host, uint16_t port) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Connect( + API_ID_PPB_TCPSOCKET_PRIVATE, socket_id_, host, port)); +} + +void TCPSocket::SendConnectWithNetAddress(const PP_NetAddress_Private& addr) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress( + API_ID_PPB_TCPSOCKET_PRIVATE, socket_id_, addr)); +} + +void TCPSocket::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) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_SSLHandshake( + socket_id_, server_name, server_port, trusted_certs, untrusted_certs)); +} + +void TCPSocket::SendRead(int32_t bytes_to_read) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Read(socket_id_, bytes_to_read)); +} + +void TCPSocket::SendWrite(const std::string& buffer) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Write(socket_id_, buffer)); +} + +void TCPSocket::SendDisconnect() { + // After removed from the mapping, this object won't receive any notifications + // from the proxy. + DCHECK(g_id_to_socket->find(socket_id_) != g_id_to_socket->end()); + g_id_to_socket->erase(socket_id_); + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Disconnect(socket_id_)); +} + +void TCPSocket::SendSetOption(PP_TCPSocket_Option name, + const SocketOptionData& value) { + SendToBrowser( + new PpapiHostMsg_PPBTCPSocket_SetOption(socket_id_, name, value)); +} + +void TCPSocket::SendToBrowser(IPC::Message* msg) { + PluginGlobals::Get()->GetBrowserSender()->Send(msg); +} + +} // namespace + +//------------------------------------------------------------------------------ + +PPB_TCPSocket_Private_Proxy::PPB_TCPSocket_Private_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_TCPSocket_Private_Proxy::~PPB_TCPSocket_Private_Proxy() { +} + +// static +PP_Resource PPB_TCPSocket_Private_Proxy::CreateProxyResource( + PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + uint32 socket_id = 0; + PluginGlobals::Get()->GetBrowserSender()->Send( + new PpapiHostMsg_PPBTCPSocket_CreatePrivate( + API_ID_PPB_TCPSOCKET_PRIVATE, dispatcher->plugin_dispatcher_id(), + &socket_id)); + if (socket_id == 0) + return 0; + return (new TCPSocket(HostResource::MakeInstanceOnly(instance), + socket_id))->GetReference(); +} + +// static +PP_Resource PPB_TCPSocket_Private_Proxy::CreateProxyResourceForConnectedSocket( + PP_Instance instance, + uint32 socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + return (new TCPSocket(HostResource::MakeInstanceOnly(instance), + socket_id, + local_addr, + remote_addr))->GetReference(); +} + +bool PPB_TCPSocket_Private_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_TCPSocket_Private_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ConnectACK, + OnMsgConnectACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_SSLHandshakeACK, + OnMsgSSLHandshakeACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ReadACK, OnMsgReadACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_WriteACK, OnMsgWriteACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_SetOptionACK, OnMsgSetOptionACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_TCPSocket_Private_Proxy::OnMsgConnectACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnConnectCompleted(result, local_addr, remote_addr); +} + +void PPB_TCPSocket_Private_Proxy::OnMsgSSLHandshakeACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + bool succeeded, + const PPB_X509Certificate_Fields& certificate_fields) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnSSLHandshakeCompleted(succeeded, certificate_fields); +} + +void PPB_TCPSocket_Private_Proxy::OnMsgReadACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result, + const std::string& data) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnReadCompleted(result, data); +} + +void PPB_TCPSocket_Private_Proxy::OnMsgWriteACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnWriteCompleted(result); +} + +void PPB_TCPSocket_Private_Proxy::OnMsgSetOptionACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnSetOptionCompleted(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_tcp_socket_private_proxy.h b/chromium/ppapi/proxy/ppb_tcp_socket_private_proxy.h new file mode 100644 index 00000000000..0813531a00e --- /dev/null +++ b/chromium/ppapi/proxy/ppb_tcp_socket_private_proxy.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_TCP_SOCKET_PRIVATE_PROXY_H_ +#define PPAPI_PROXY_PPB_TCP_SOCKET_PRIVATE_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/private/ppb_tcp_socket_private.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +namespace ppapi { + +class PPB_X509Certificate_Fields; + +namespace proxy { + +class PPB_TCPSocket_Private_Proxy : public InterfaceProxy { + public: + explicit PPB_TCPSocket_Private_Proxy(Dispatcher* dispatcher); + virtual ~PPB_TCPSocket_Private_Proxy(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + static PP_Resource CreateProxyResourceForConnectedSocket( + PP_Instance instance, + uint32 socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_TCPSOCKET_PRIVATE; + + private: + // Browser->plugin message handlers. + void OnMsgConnectACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); + void OnMsgSSLHandshakeACK( + uint32 plugin_dispatcher_id, + uint32 socket_id, + bool succeeded, + const PPB_X509Certificate_Fields& certificate_fields); + void OnMsgReadACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result, + const std::string& data); + void OnMsgWriteACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result); + void OnMsgSetOptionACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result); + + DISALLOW_COPY_AND_ASSIGN(PPB_TCPSocket_Private_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_TCP_SOCKET_PRIVATE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_tcp_socket_proxy.cc b/chromium/ppapi/proxy/ppb_tcp_socket_proxy.cc new file mode 100644 index 00000000000..2ec16603300 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_tcp_socket_proxy.cc @@ -0,0 +1,299 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_tcp_socket_proxy.h" + +#include <map> + +#include "base/logging.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/socket_option_data.h" +#include "ppapi/shared_impl/tcp_socket_shared.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_net_address_api.h" +#include "ppapi/thunk/ppb_tcp_socket_api.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef thunk::EnterResourceNoLock<thunk::PPB_NetAddress_API> + EnterNetAddressNoLock; + +typedef std::map<uint32, TCPSocketShared*> IDToSocketMap; +IDToSocketMap* g_id_to_socket = NULL; + +class TCPSocket : public thunk::PPB_TCPSocket_API, + public Resource, + public TCPSocketShared { + public: + TCPSocket(const HostResource& resource, uint32 socket_id); + virtual ~TCPSocket(); + + // Resource overrides. + virtual thunk::PPB_TCPSocket_API* AsPPB_TCPSocket_API() OVERRIDE; + + // thunk::PPB_TCPSocket_API implementation. + virtual int32_t Connect(PP_Resource addr, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Resource GetLocalAddress() OVERRIDE; + virtual PP_Resource GetRemoteAddress() OVERRIDE; + virtual int32_t Read(char* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Write(const char* buffer, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + virtual int32_t SetOption(PP_TCPSocket_Option name, + const PP_Var& value, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + // TCPSocketShared implementation. + 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 SocketOptionData& value) OVERRIDE; + virtual Resource* GetOwnerResource() OVERRIDE; + + private: + void SendToBrowser(IPC::Message* msg); + + DISALLOW_COPY_AND_ASSIGN(TCPSocket); +}; + +TCPSocket::TCPSocket(const HostResource& resource, uint32 socket_id) + : Resource(OBJECT_IS_PROXY, resource), + TCPSocketShared(OBJECT_IS_PROXY, socket_id) { + if (!g_id_to_socket) + g_id_to_socket = new IDToSocketMap(); + DCHECK(g_id_to_socket->find(socket_id) == g_id_to_socket->end()); + (*g_id_to_socket)[socket_id] = this; +} + +TCPSocket::~TCPSocket() { + DisconnectImpl(); +} + +thunk::PPB_TCPSocket_API* TCPSocket::AsPPB_TCPSocket_API() { + return this; +} + +int32_t TCPSocket::Connect(PP_Resource addr, + scoped_refptr<TrackedCallback> callback) { + EnterNetAddressNoLock enter(addr, true); + if (enter.failed()) + return PP_ERROR_BADARGUMENT; + + return ConnectWithNetAddressImpl(&enter.object()->GetNetAddressPrivate(), + callback); +} + +PP_Resource TCPSocket::GetLocalAddress() { + PP_NetAddress_Private addr_private; + if (!GetLocalAddressImpl(&addr_private)) + return 0; + + thunk::EnterResourceCreationNoLock enter(pp_instance()); + if (enter.failed()) + return 0; + return enter.functions()->CreateNetAddressFromNetAddressPrivate( + pp_instance(), addr_private); +} + +PP_Resource TCPSocket::GetRemoteAddress() { + PP_NetAddress_Private addr_private; + if (!GetRemoteAddressImpl(&addr_private)) + return 0; + + thunk::EnterResourceCreationNoLock enter(pp_instance()); + if (enter.failed()) + return 0; + return enter.functions()->CreateNetAddressFromNetAddressPrivate( + pp_instance(), addr_private); +} + +int32_t TCPSocket::Read(char* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) { + return ReadImpl(buffer, bytes_to_read, callback); +} + +int32_t TCPSocket::Write(const char* buffer, + int32_t bytes_to_write, + scoped_refptr<TrackedCallback> callback) { + return WriteImpl(buffer, bytes_to_write, callback); +} + +void TCPSocket::Close() { + DisconnectImpl(); +} + +int32_t TCPSocket::SetOption(PP_TCPSocket_Option name, + const PP_Var& value, + scoped_refptr<TrackedCallback> callback) { + return SetOptionImpl(name, value, callback); +} + +void TCPSocket::SendConnect(const std::string& host, uint16_t port) { + NOTREACHED(); +} + +void TCPSocket::SendConnectWithNetAddress(const PP_NetAddress_Private& addr) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress( + API_ID_PPB_TCPSOCKET, socket_id_, addr)); +} + +void TCPSocket::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) { + NOTREACHED(); +} + +void TCPSocket::SendRead(int32_t bytes_to_read) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Read(socket_id_, bytes_to_read)); +} + +void TCPSocket::SendWrite(const std::string& buffer) { + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Write(socket_id_, buffer)); +} + +void TCPSocket::SendDisconnect() { + // After removed from the mapping, this object won't receive any notifications + // from the proxy. + DCHECK(g_id_to_socket->find(socket_id_) != g_id_to_socket->end()); + g_id_to_socket->erase(socket_id_); + SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Disconnect(socket_id_)); +} + +void TCPSocket::SendSetOption(PP_TCPSocket_Option name, + const SocketOptionData& value) { + SendToBrowser( + new PpapiHostMsg_PPBTCPSocket_SetOption(socket_id_, name, value)); +} + +Resource* TCPSocket::GetOwnerResource() { + return this; +} + +void TCPSocket::SendToBrowser(IPC::Message* msg) { + PluginGlobals::Get()->GetBrowserSender()->Send(msg); +} + +} // namespace + +//------------------------------------------------------------------------------ + +PPB_TCPSocket_Proxy::PPB_TCPSocket_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_TCPSocket_Proxy::~PPB_TCPSocket_Proxy() { +} + +// static +PP_Resource PPB_TCPSocket_Proxy::CreateProxyResource(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + uint32 socket_id = 0; + PluginGlobals::Get()->GetBrowserSender()->Send( + new PpapiHostMsg_PPBTCPSocket_Create( + API_ID_PPB_TCPSOCKET, dispatcher->plugin_dispatcher_id(), + &socket_id)); + if (socket_id == 0) + return 0; + return (new TCPSocket(HostResource::MakeInstanceOnly(instance), + socket_id))->GetReference(); +} + +bool PPB_TCPSocket_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_TCPSocket_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ConnectACK, + OnMsgConnectACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ReadACK, OnMsgReadACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_WriteACK, OnMsgWriteACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_SetOptionACK, + OnMsgSetOptionACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_TCPSocket_Proxy::OnMsgConnectACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnConnectCompleted(result, local_addr, remote_addr); +} + +void PPB_TCPSocket_Proxy::OnMsgReadACK(uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result, + const std::string& data) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnReadCompleted(result, data); +} + +void PPB_TCPSocket_Proxy::OnMsgWriteACK(uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnWriteCompleted(result); +} + +void PPB_TCPSocket_Proxy::OnMsgSetOptionACK(uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + int32_t result) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnSetOptionCompleted(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_tcp_socket_proxy.h b/chromium/ppapi/proxy/ppb_tcp_socket_proxy.h new file mode 100644 index 00000000000..c5a3de8c721 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_tcp_socket_proxy.h @@ -0,0 +1,57 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_TCP_SOCKET_PROXY_H_ +#define PPAPI_PROXY_PPB_TCP_SOCKET_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +struct PP_NetAddress_Private; + +namespace ppapi { +namespace proxy { + +class PPB_TCPSocket_Proxy : public InterfaceProxy { + public: + explicit PPB_TCPSocket_Proxy(Dispatcher* dispatcher); + virtual ~PPB_TCPSocket_Proxy(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_TCPSOCKET; + + private: + // Browser->plugin message handlers. + void OnMsgConnectACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); + void OnMsgReadACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result, + const std::string& data); + void OnMsgWriteACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result); + void OnMsgSetOptionACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + int32_t result); + + DISALLOW_COPY_AND_ASSIGN(PPB_TCPSocket_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_TCP_SOCKET_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_testing_proxy.cc b/chromium/ppapi/proxy/ppb_testing_proxy.cc new file mode 100644 index 00000000000..f80e60cbf5a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_testing_proxy.cc @@ -0,0 +1,229 @@ +// 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 "ppapi/proxy/ppb_testing_proxy.h" + +#include "base/message_loop/message_loop.h" +#include "ppapi/c/dev/ppb_testing_dev.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_graphics_2d_api.h" +#include "ppapi/thunk/ppb_input_event_api.h" + +using ppapi::thunk::EnterInstance; +using ppapi::thunk::EnterResource; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Graphics2D_API; +using ppapi::thunk::PPB_InputEvent_API; + +namespace ppapi { +namespace proxy { + +namespace { + +PP_Bool ReadImageData(PP_Resource graphics_2d, + PP_Resource image, + const PP_Point* top_left) { + ProxyAutoLock lock; + Resource* image_object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(image); + if (!image_object) + return PP_FALSE; + Resource* graphics_2d_object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(graphics_2d); + if (!graphics_2d_object || + image_object->pp_instance() != graphics_2d_object->pp_instance()) + return PP_FALSE; + + EnterResourceNoLock<PPB_Graphics2D_API> enter(graphics_2d, true); + if (enter.failed()) + return PP_FALSE; + const HostResource& host_image = image_object->host_resource(); + return enter.object()->ReadImageData(host_image.host_resource(), top_left) ? + PP_TRUE : PP_FALSE; +} + +void RunMessageLoop(PP_Instance instance) { + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + CHECK(PpapiGlobals::Get()->GetMainThreadMessageLoop()-> + BelongsToCurrentThread()); + base::MessageLoop::current()->Run(); +} + +void QuitMessageLoop(PP_Instance instance) { + CHECK(PpapiGlobals::Get()->GetMainThreadMessageLoop()-> + BelongsToCurrentThread()); + base::MessageLoop::current()->QuitNow(); +} + +uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) { + ProxyAutoLock lock; + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return static_cast<uint32_t>(-1); + + uint32_t result = 0; + dispatcher->Send(new PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance( + API_ID_PPB_TESTING, instance_id, &result)); + return result; +} + +PP_Bool IsOutOfProcess() { + return PP_TRUE; +} + +void SimulateInputEvent(PP_Instance instance_id, PP_Resource input_event) { + ProxyAutoLock lock; + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return; + EnterResourceNoLock<PPB_InputEvent_API> enter(input_event, false); + if (enter.failed()) + return; + + const InputEventData& input_event_data = enter.object()->GetInputEventData(); + dispatcher->Send(new PpapiHostMsg_PPBTesting_SimulateInputEvent( + API_ID_PPB_TESTING, instance_id, input_event_data)); +} + +PP_Var GetDocumentURL(PP_Instance instance, PP_URLComponents_Dev* components) { + EnterInstance enter(instance); + if (enter.failed()) + return PP_MakeUndefined(); + return enter.functions()->GetDocumentURL(instance, components); +} + +// TODO(dmichael): Ideally we could get a way to check the number of vars in the +// host-side tracker when running out-of-process, to make sure the proxy does +// not leak host-side vars. +uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) { + ProxyAutoLock lock; + 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) { + ProxyAutoLock lock; + RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(threshold); + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + dispatcher->Send( + new PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem( + API_ID_PPB_TESTING, threshold)); +} + +const PPB_Testing_Dev testing_interface = { + &ReadImageData, + &RunMessageLoop, + &QuitMessageLoop, + &GetLiveObjectsForInstance, + &IsOutOfProcess, + &SimulateInputEvent, + &GetDocumentURL, + &GetLiveVars, + &SetMinimumArrayBufferSizeForShmem +}; + +InterfaceProxy* CreateTestingProxy(Dispatcher* dispatcher) { + return new PPB_Testing_Proxy(dispatcher); +} + +} // namespace + +PPB_Testing_Proxy::PPB_Testing_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppb_testing_impl_(NULL) { + if (!dispatcher->IsPlugin()) { + ppb_testing_impl_ = static_cast<const PPB_Testing_Dev*>( + dispatcher->local_get_interface()(PPB_TESTING_DEV_INTERFACE)); + } +} + +PPB_Testing_Proxy::~PPB_Testing_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Testing_Proxy::GetInfo() { + static const Info info = { + &testing_interface, + PPB_TESTING_DEV_INTERFACE, + API_ID_PPB_TESTING, + false, + &CreateTestingProxy, + }; + return &info; +} + +bool PPB_Testing_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_TESTING)) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Testing_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_ReadImageData, + OnMsgReadImageData) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, + OnMsgGetLiveObjectsForInstance) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_SimulateInputEvent, + OnMsgSimulateInputEvent) + IPC_MESSAGE_HANDLER( + PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem, + OnMsgSetMinimumArrayBufferSizeForShmem) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Testing_Proxy::OnMsgReadImageData( + const HostResource& device_context_2d, + const HostResource& image, + const PP_Point& top_left, + PP_Bool* result) { + *result = ppb_testing_impl_->ReadImageData( + device_context_2d.host_resource(), image.host_resource(), &top_left); +} + +void PPB_Testing_Proxy::OnMsgRunMessageLoop(PP_Instance instance) { + ppb_testing_impl_->RunMessageLoop(instance); +} + +void PPB_Testing_Proxy::OnMsgQuitMessageLoop(PP_Instance instance) { + ppb_testing_impl_->QuitMessageLoop(instance); +} + +void PPB_Testing_Proxy::OnMsgGetLiveObjectsForInstance(PP_Instance instance, + uint32_t* result) { + *result = ppb_testing_impl_->GetLiveObjectsForInstance(instance); +} + +void PPB_Testing_Proxy::OnMsgSimulateInputEvent( + PP_Instance instance, + const InputEventData& input_event) { + scoped_refptr<PPB_InputEvent_Shared> input_event_impl( + new PPB_InputEvent_Shared(OBJECT_IS_PROXY, instance, input_event)); + ppb_testing_impl_->SimulateInputEvent(instance, + input_event_impl->pp_resource()); +} + +void PPB_Testing_Proxy::OnMsgSetMinimumArrayBufferSizeForShmem( + uint32_t threshold) { + RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(threshold); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_testing_proxy.h b/chromium/ppapi/proxy/ppb_testing_proxy.h new file mode 100644 index 00000000000..61af47fcb00 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_testing_proxy.h @@ -0,0 +1,57 @@ +// 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_PROXY_PPB_TESTING_PROXY_H_ +#define PPAPI_PROXY_PPB_TESTING_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/dev/ppb_testing_dev.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/host_resource.h" + +struct PP_Point; + +namespace ppapi { + +struct InputEventData; + +namespace proxy { + +class PPB_Testing_Proxy : public InterfaceProxy { + public: + PPB_Testing_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Testing_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgReadImageData(const ppapi::HostResource& device_context_2d, + const ppapi::HostResource& image, + const PP_Point& top_left, + PP_Bool* result); + void OnMsgRunMessageLoop(PP_Instance instance); + void OnMsgQuitMessageLoop(PP_Instance instance); + void OnMsgGetLiveObjectsForInstance(PP_Instance instance, uint32_t* result); + void OnMsgSimulateInputEvent(PP_Instance instance, + const ppapi::InputEventData& input_event); + void OnMsgSetMinimumArrayBufferSizeForShmem(uint32_t threshold); + + // When this proxy is in the host side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the plugin, this value is always NULL. + const PPB_Testing_Dev* ppb_testing_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Testing_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_TESTING_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_var_deprecated_proxy.cc b/chromium/ppapi/proxy/ppb_var_deprecated_proxy.cc new file mode 100644 index 00000000000..43452ef019a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_var_deprecated_proxy.cc @@ -0,0 +1,538 @@ +// 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 "ppapi/proxy/ppb_var_deprecated_proxy.h" + +#include <stdlib.h> // For malloc + +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/proxy_object_var.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/ppb_var_shared.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// Used to do get the set-up information for calling a var object. If the +// exception is set, returns NULL. Otherwise, computes the dispatcher for the +// given var object. If the var is not a valid object, returns NULL and sets +// the exception. +PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object, + PP_Var* exception) { + // If an exception is already set, we don't need to do anything, just return + // an error to the caller. + if (exception && exception->type != PP_VARTYPE_UNDEFINED) + return NULL; + + + if (object.type == PP_VARTYPE_OBJECT) { + // Get the dispatcher for the object. + PluginDispatcher* dispatcher = + PluginGlobals::Get()->plugin_var_tracker()-> + DispatcherForPluginObject(object); + if (dispatcher) + return dispatcher; + } + + // The object is invalid. This means we can't figure out which dispatcher + // to use, which is OK because the call will fail anyway. Set the exception. + if (exception) { + *exception = StringVar::StringToPPVar( + std::string("Attempting to use an invalid object")); + } + return NULL; +} + +// PPB_Var_Deprecated plugin --------------------------------------------------- + +bool HasProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return false; + + ReceiveSerializedException se(dispatcher, exception); + PP_Bool result = PP_FALSE; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } + return PP_ToBool(result); +} + +bool HasMethod(PP_Var var, + PP_Var name, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return false; + + ReceiveSerializedException se(dispatcher, exception); + PP_Bool result = PP_FALSE; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } + return PP_ToBool(result); +} + +PP_Var GetProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedException se(dispatcher, exception); + ReceiveSerializedVarReturnValue result; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_GetProperty( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } + return result.Return(dispatcher); +} + +void EnumerateProperties(PP_Var var, + uint32_t* property_count, + PP_Var** properties, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) { + *property_count = 0; + *properties = NULL; + return; + } + + ReceiveSerializedVarVectorOutParam out_vector(dispatcher, + property_count, properties); + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_EnumerateProperties( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + out_vector.OutParam(), &se)); + } +} + +void SetProperty(PP_Var var, + PP_Var name, + PP_Var value, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return; + + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), + SerializedVarSendInput(dispatcher, value), &se)); + } +} + +void RemoveProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return; + + ReceiveSerializedException se(dispatcher, exception); + PP_Bool result = PP_FALSE; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_DeleteProperty( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } +} + +PP_Var Call(PP_Var object, + PP_Var method_name, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + std::vector<SerializedVar> argv_vect; + SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); + + dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, object), + SerializedVarSendInput(dispatcher, method_name), argv_vect, + &se, &result)); + } + return result.Return(dispatcher); +} + +PP_Var Construct(PP_Var object, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + std::vector<SerializedVar> argv_vect; + SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); + + dispatcher->Send(new PpapiHostMsg_PPBVar_Construct( + API_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, object), + argv_vect, &se, &result)); + } + return result.Return(dispatcher); +} + +bool IsInstanceOf(PP_Var var, + const PPP_Class_Deprecated* ppp_class, + void** ppp_class_data) { + ProxyAutoLock lock; + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL); + if (!dispatcher) + return false; + + PP_Bool result = PP_FALSE; + int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); + int64 class_data_int = 0; + dispatcher->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated( + API_ID_PPB_VAR_DEPRECATED, SerializedVarSendInput(dispatcher, var), + class_int, &class_data_int, &result)); + *ppp_class_data = + reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int)); + return PP_ToBool(result); +} + +PP_Var CreateObject(PP_Instance instance, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + ProxyAutoLock lock; + Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeUndefined(); + + PluginVarTracker* tracker = PluginGlobals::Get()->plugin_var_tracker(); + if (tracker->IsPluginImplementedObjectAlive(ppp_class_data)) + return PP_MakeUndefined(); // Object already exists with this user data. + + ReceiveSerializedVarReturnValue result; + int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); + int64 data_int = + static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class_data)); + dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated( + API_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int, + &result)); + PP_Var ret_var = result.Return(dispatcher); + + // Register this object as being implemented by the plugin. + if (ret_var.type == PP_VARTYPE_OBJECT) { + tracker->PluginImplementedObjectCreated(instance, ret_var, + ppp_class, ppp_class_data); + } + return ret_var; +} + +InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher) { + return new PPB_Var_Deprecated_Proxy(dispatcher ); +} + +} // namespace + +PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy( + Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + task_factory_(this), + ppb_var_impl_(NULL) { + if (!dispatcher->IsPlugin()) { + ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>( + dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE)); + } +} + +PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Var_Deprecated_Proxy::GetInfo() { + 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, + &HasProperty, + &HasMethod, + &GetProperty, + &EnumerateProperties, + &SetProperty, + &RemoveProperty, + &Call, + &Construct, + &IsInstanceOf, + &CreateObject + }; + + static const Info info = { + &var_deprecated_interface, + PPB_VAR_DEPRECATED_INTERFACE, + API_ID_PPB_VAR_DEPRECATED, + false, + &CreateVarDeprecatedProxy, + }; + return &info; +} + +bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return false; + + // Prevent the dispatcher from going away during a call to Call or other + // function that could mutate the DOM. This must happen OUTSIDE of + // the message handlers since the SerializedVars use the dispatcher upon + // return of the function (converting the SerializedVarReturnValue/OutParam + // to a SerializedVar in the destructor). + ScopedModuleReference death_grip(dispatcher()); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty, + OnMsgHasProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated, + OnMsgHasMethodDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty, + OnMsgGetProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty, + OnMsgDeleteProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties, + OnMsgEnumerateProperties) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated, + OnMsgSetPropertyDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated, + OnMsgCallDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct, + OnMsgConstruct) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated, + OnMsgIsInstanceOfDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated, + OnMsgCreateObjectDeprecated) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id, + int* /* unused */) { + PP_Var var = { PP_VARTYPE_OBJECT }; + var.value.as_id = object_id; + ppb_var_impl_->AddRef(var); +} + +void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64 object_id) { + // Ok, so this is super subtle. + // When the browser side sends a sync IPC message that returns a var, and the + // plugin wants to give ownership of that var to the browser, dropping all + // references, it may call ReleaseObject right after returning the result. + // However, the IPC system doesn't enforce strict ordering of messages in that + // case, where a message that is set to unblock (e.g. a sync message, or in + // our case all messages coming from the plugin) that is sent *after* the + // result may be dispatched on the browser side *before* the sync send + // returned (see ipc_sync_channel.cc). In this case, that means it could + // release the object before it is AddRef'ed on the browser side. + // To work around this, we post a task here, that will not execute before + // control goes back to the main message loop, that will ensure the sync send + // has returned and the browser side can take its reference before we Release. + // Note: if the instance is gone by the time the task is executed, then it + // will Release the objects itself and this Release will be a NOOP (aside of a + // spurious warning). + // TODO(piman): See if we can fix the IPC code to enforce strict ordering, and + // then remove this. + base::MessageLoop::current()->PostNonNestableTask( + FROM_HERE, + RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject, + task_factory_.GetWeakPtr(), + object_id))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgHasProperty( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result) { + SetAllowPluginReentrancy(); + *result = PP_FromBool(ppb_var_impl_->HasProperty( + var.Get(dispatcher()), + name.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result) { + SetAllowPluginReentrancy(); + *result = PP_FromBool(ppb_var_impl_->HasMethod( + var.Get(dispatcher()), + name.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgGetProperty( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + result.Return(dispatcher(), ppb_var_impl_->GetProperty( + var.Get(dispatcher()), name.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties( + SerializedVarReceiveInput var, + SerializedVarVectorOutParam props, + SerializedVarOutParam exception) { + SetAllowPluginReentrancy(); + ppb_var_impl_->GetAllPropertyNames(var.Get(dispatcher()), + props.CountOutParam(), props.ArrayOutParam(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarReceiveInput value, + SerializedVarOutParam exception) { + SetAllowPluginReentrancy(); + ppb_var_impl_->SetProperty(var.Get(dispatcher()), + name.Get(dispatcher()), + value.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result) { + SetAllowPluginReentrancy(); + ppb_var_impl_->RemoveProperty(var.Get(dispatcher()), + name.Get(dispatcher()), + exception.OutParam(dispatcher())); + // This deprecated function doesn't actually return a value, but we re-use + // the message from the non-deprecated interface with the return value. + *result = PP_TRUE; +} + +void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated( + SerializedVarReceiveInput object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), ppb_var_impl_->Call( + object.Get(dispatcher()), + method_name.Get(dispatcher()), + arg_count, args, + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgConstruct( + SerializedVarReceiveInput var, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), ppb_var_impl_->Construct( + var.Get(dispatcher()), arg_count, args, + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated( + SerializedVarReceiveInput var, + int64 ppp_class, + int64* ppp_class_data, + PP_Bool* result) { + SetAllowPluginReentrancy(); + *result = PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_, + var.Get(dispatcher()), + ppp_class, + ppp_class_data); +} + +void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated( + PP_Instance instance, + int64 ppp_class, + int64 class_data, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject( + ppb_var_impl_, dispatcher(), instance, ppp_class, class_data)); +} + +void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() { + if (dispatcher()->IsPlugin()) + NOTREACHED(); + else + static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); +} + +void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id) { + PP_Var var = { PP_VARTYPE_OBJECT }; + var.value.as_id = object_id; + ppb_var_impl_->Release(var); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_var_deprecated_proxy.h b/chromium/ppapi/proxy/ppb_var_deprecated_proxy.h new file mode 100644 index 00000000000..59400aede6e --- /dev/null +++ b/chromium/ppapi/proxy/ppb_var_deprecated_proxy.h @@ -0,0 +1,102 @@ +// 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 PPAPI_PROXY_PPB_VAR_DEPRECATED_PROXY_H_ +#define PPAPI_PROXY_PPB_VAR_DEPRECATED_PROXY_H_ + +#include <vector> + +#include "base/memory/weak_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Var_Deprecated; + +namespace ppapi { +namespace proxy { + +class SerializedVar; +class SerializedVarReceiveInput; +class SerializedVarVectorOutParam; +class SerializedVarVectorReceiveInput; +class SerializedVarOutParam; +class SerializedVarReturnValue; + +class PPB_Var_Deprecated_Proxy : public InterfaceProxy { + public: + explicit PPB_Var_Deprecated_Proxy(Dispatcher* dispatcher); + virtual ~PPB_Var_Deprecated_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgAddRefObject(int64 object_id, int* unused); + void OnMsgReleaseObject(int64 object_id); + void OnMsgHasProperty(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result); + void OnMsgHasMethodDeprecated(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result); + void OnMsgGetProperty(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgEnumerateProperties( + SerializedVarReceiveInput var, + SerializedVarVectorOutParam props, + SerializedVarOutParam exception); + void OnMsgSetPropertyDeprecated(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarReceiveInput value, + SerializedVarOutParam exception); + void OnMsgDeleteProperty(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result); + void OnMsgCall(SerializedVarReceiveInput object, + SerializedVarReceiveInput this_object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgCallDeprecated(SerializedVarReceiveInput object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgConstruct(SerializedVarReceiveInput var, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgIsInstanceOfDeprecated(SerializedVarReceiveInput var, + int64 ppp_class, + int64* ppp_class_data, + PP_Bool* result); + void OnMsgCreateObjectDeprecated(PP_Instance instance, + int64 ppp_class, + int64 ppp_class_data, + SerializedVarReturnValue result); + + // Call in the host for messages that can be reentered. + void SetAllowPluginReentrancy(); + + void DoReleaseObject(int64 object_id); + base::WeakPtrFactory<PPB_Var_Deprecated_Proxy> task_factory_; + + const PPB_Var_Deprecated* ppb_var_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Var_Deprecated_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_VAR_DEPRECATED_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_var_unittest.cc b/chromium/ppapi/proxy/ppb_var_unittest.cc new file mode 100644 index 00000000000..7315d00b72a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_var_unittest.cc @@ -0,0 +1,241 @@ +// 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 <string> +#include <vector> + +#include "base/strings/string_number_conversions.h" +#include "base/threading/platform_thread.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/ppb_var_shared.h" + +namespace { +std::string VarToString(const PP_Var& var, const PPB_Var* ppb_var) { + uint32_t len = 0; + const char* utf8 = ppb_var->VarToUtf8(var, &len); + return std::string(utf8, len); +} +const size_t kNumStrings = 100; +const size_t kNumThreads = 20; +const int kRefsToAdd = 20; +} // namespace + +namespace ppapi { +namespace proxy { + +class PPB_VarTest : public PluginProxyTest { + public: + PPB_VarTest() + : test_strings_(kNumStrings), vars_(kNumStrings), + ppb_var_(ppapi::PPB_Var_Shared::GetVarInterface1_1()) { + // Set the value of test_strings_[i] to "i". + for (size_t i = 0; i < kNumStrings; ++i) + test_strings_[i] = base::IntToString(i); + } + protected: + std::vector<std::string> test_strings_; + std::vector<PP_Var> vars_; + const PPB_Var* ppb_var_; +}; + +// Test basic String operations. +TEST_F(PPB_VarTest, Strings) { + for (size_t i = 0; i < kNumStrings; ++i) { + vars_[i] = ppb_var_->VarFromUtf8(test_strings_[i].c_str(), + test_strings_[i].length()); + EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_)); + } + // At this point, they should each have a ref count of 1. Add some more. + for (int ref = 0; ref < kRefsToAdd; ++ref) { + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var_->AddRef(vars_[i]); + // Make sure the string is still there with the right value. + EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_)); + } + } + for (int ref = 0; ref < kRefsToAdd; ++ref) { + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var_->Release(vars_[i]); + // Make sure the string is still there with the right value. + EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_)); + } + } + // Now remove the ref counts for each string and make sure they are gone. + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var_->Release(vars_[i]); + uint32_t len = 10; + const char* utf8 = ppb_var_->VarToUtf8(vars_[i], &len); + EXPECT_EQ(NULL, utf8); + EXPECT_EQ(0u, len); + } +} + +// PPB_VarTest.Threads tests string operations accessed by multiple threads. +namespace { +// These three delegate classes which precede the test are for use with +// PlatformThread. The test goes roughly like this: +// 1) Spawn kNumThreads 'CreateVar' threads, giving each a roughly equal subset +// of test_strings_ to 'create'. Each 'CreateVar' thread also converts its +// set of vars back in to strings so that the main test thread can verify +// their values were correctly converted. +// 2) Spawn kNumThreads 'ChangeRefVar' threads. Each of these threads will +// incremement & decrement the reference count of ALL vars kRefsToAdd times. +// Finally, each thread adds 1 ref count. This leaves each var with a ref- +// count of |kNumThreads + 1|. The main test thread removes a ref, leaving +// each var with a ref-count of |kNumThreads|. +// 3) Spawn kNumThreads 'RemoveVar' threads. Each of these threads releases each +// var once. Once all the threads have finished, there should be no vars +// left. +class CreateVarThreadDelegate : public base::PlatformThread::Delegate { + public: + // |strings_in|, |vars|, and |strings_out| are arrays, and size is their size. + // For each |strings_in[i]|, we will set |vars[i]| using that value. Then we + // read the var back out to |strings_out[i]|. + CreateVarThreadDelegate(PP_Module pp_module, const std::string* strings_in, + PP_Var* vars_out, std::string* strings_out, + size_t size) + : pp_module_(pp_module), strings_in_(strings_in), vars_out_(vars_out), + strings_out_(strings_out), size_(size) { + } + virtual ~CreateVarThreadDelegate() {} + virtual void ThreadMain() { + const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); + for (size_t i = 0; i < size_; ++i) { + vars_out_[i] = ppb_var->VarFromUtf8(strings_in_[i].c_str(), + strings_in_[i].length()); + strings_out_[i] = VarToString(vars_out_[i], ppb_var); + } + } + private: + PP_Module pp_module_; + const std::string* strings_in_; + PP_Var* vars_out_; + std::string* strings_out_; + size_t size_; +}; + +// A thread that will increment and decrement the reference count of every var +// multiple times. +class ChangeRefVarThreadDelegate : public base::PlatformThread::Delegate { + public: + ChangeRefVarThreadDelegate(const std::vector<PP_Var>& vars) : vars_(vars) { + } + virtual ~ChangeRefVarThreadDelegate() {} + virtual void ThreadMain() { + const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); + // Increment and decrement the reference count for each var kRefsToAdd + // times. Note that we always AddRef once before doing the matching Release, + // to ensure that we never accidentally release the last reference. + for (int ref = 0; ref < kRefsToAdd; ++ref) { + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var->AddRef(vars_[i]); + ppb_var->Release(vars_[i]); + } + } + // Now add 1 ref to each Var. The net result is that all Vars will have a + // ref-count of (kNumThreads + 1) after this. That will allow us to have all + // threads release all vars later. + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var->AddRef(vars_[i]); + } + } + private: + std::vector<PP_Var> vars_; +}; + +// A thread that will decrement the reference count of every var once. +class RemoveRefVarThreadDelegate : public base::PlatformThread::Delegate { + public: + RemoveRefVarThreadDelegate(const std::vector<PP_Var>& vars) : vars_(vars) { + } + virtual ~RemoveRefVarThreadDelegate() {} + virtual void ThreadMain() { + const PPB_Var* ppb_var = ppapi::PPB_Var_Shared::GetVarInterface1_1(); + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var->Release(vars_[i]); + } + } + private: + std::vector<PP_Var> vars_; +}; + +} // namespace + +TEST_F(PPB_VarTest, Threads) { + std::vector<base::PlatformThreadHandle> create_var_threads(kNumThreads); + std::vector<CreateVarThreadDelegate> create_var_delegates; + // The strings that the threads will re-extract from Vars (so we can check + // that they match the original strings). + std::vector<std::string> strings_out(kNumStrings); + size_t strings_per_thread = kNumStrings/kNumThreads; + // Give each thread an equal slice of strings to turn in to vars. (Except the + // last thread may get fewer if kNumStrings is not evenly divisible by + // kNumThreads). + for (size_t slice_start= 0; slice_start < kNumStrings; + slice_start += strings_per_thread) { + create_var_delegates.push_back( + CreateVarThreadDelegate(pp_module(), + &test_strings_[slice_start], + &vars_[slice_start], + &strings_out[slice_start], + std::min(strings_per_thread, + kNumStrings - slice_start))); + } + // Now run then join all the threads. + for (size_t i = 0; i < kNumThreads; ++i) + base::PlatformThread::Create(0, &create_var_delegates[i], + &create_var_threads[i]); + for (size_t i = 0; i < kNumThreads; ++i) + base::PlatformThread::Join(create_var_threads[i]); + // Now check that the strings have the expected values. + EXPECT_EQ(test_strings_, strings_out); + + // Tinker with the reference counts in a multithreaded way. + std::vector<base::PlatformThreadHandle> change_ref_var_threads(kNumThreads); + std::vector<ChangeRefVarThreadDelegate> change_ref_var_delegates; + for (size_t i = 0; i < kNumThreads; ++i) + change_ref_var_delegates.push_back(ChangeRefVarThreadDelegate(vars_)); + for (size_t i = 0; i < kNumThreads; ++i) { + base::PlatformThread::Create(0, &change_ref_var_delegates[i], + &change_ref_var_threads[i]); + } + for (size_t i = 0; i < kNumThreads; ++i) + base::PlatformThread::Join(change_ref_var_threads[i]); + + // Now each var has a refcount of (kNumThreads + 1). Let's decrement each var + // once so that every 'RemoveRef' thread (spawned below) owns 1 reference, and + // when the last one removes a ref, the Var will be deleted. + for (size_t i = 0; i < kNumStrings; ++i) { + ppb_var_->Release(vars_[i]); + } + + // Check that all vars are still valid and have the values we expect. + for (size_t i = 0; i < kNumStrings; ++i) + EXPECT_EQ(test_strings_[i], VarToString(vars_[i], ppb_var_)); + + // Remove the last reference counts for all vars. + std::vector<base::PlatformThreadHandle> remove_ref_var_threads(kNumThreads); + std::vector<RemoveRefVarThreadDelegate> remove_ref_var_delegates; + for (size_t i = 0; i < kNumThreads; ++i) + remove_ref_var_delegates.push_back(RemoveRefVarThreadDelegate(vars_)); + for (size_t i = 0; i < kNumThreads; ++i) { + base::PlatformThread::Create(0, &remove_ref_var_delegates[i], + &remove_ref_var_threads[i]); + } + for (size_t i = 0; i < kNumThreads; ++i) + base::PlatformThread::Join(remove_ref_var_threads[i]); + + // All the vars should no longer represent valid strings. + for (size_t i = 0; i < kNumStrings; ++i) { + uint32_t len = 10; + const char* utf8 = ppb_var_->VarToUtf8(vars_[i], &len); + EXPECT_EQ(NULL, utf8); + EXPECT_EQ(0u, len); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_video_decoder_proxy.cc b/chromium/ppapi/proxy/ppb_video_decoder_proxy.cc new file mode 100644 index 00000000000..2a00674f416 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_video_decoder_proxy.cc @@ -0,0 +1,320 @@ +// 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 "ppapi/proxy/ppb_video_decoder_proxy.h" + +#include "base/logging.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/ppb_graphics_3d_proxy.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Buffer_API; +using ppapi::thunk::PPB_Graphics3D_API; +using ppapi::thunk::PPB_VideoDecoder_API; + +namespace ppapi { +namespace proxy { + +class VideoDecoder : public PPB_VideoDecoder_Shared { + public: + // You must call Init() before using this class. + explicit VideoDecoder(const HostResource& resource); + virtual ~VideoDecoder(); + + static VideoDecoder* Create(const HostResource& resource, + PP_Resource graphics_context, + PP_VideoDecoder_Profile profile); + + // PPB_VideoDecoder_API implementation. + virtual int32_t Decode(const PP_VideoBitstreamBuffer_Dev* bitstream_buffer, + scoped_refptr<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<TrackedCallback> callback) OVERRIDE; + virtual int32_t Reset(scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Destroy() OVERRIDE; + + private: + friend class PPB_VideoDecoder_Proxy; + + PluginDispatcher* GetDispatcher() const; + + // Run the callbacks that were passed into the plugin interface. + void FlushACK(int32_t result); + void ResetACK(int32_t result); + void EndOfBitstreamACK(int32_t buffer_id, int32_t result); + + DISALLOW_COPY_AND_ASSIGN(VideoDecoder); +}; + +VideoDecoder::VideoDecoder(const HostResource& decoder) + : PPB_VideoDecoder_Shared(decoder) { +} + +VideoDecoder::~VideoDecoder() { + FlushCommandBuffer(); + PPB_VideoDecoder_Shared::Destroy(); +} + +int32_t VideoDecoder::Decode( + const PP_VideoBitstreamBuffer_Dev* bitstream_buffer, + scoped_refptr<TrackedCallback> callback) { + EnterResourceNoLock<PPB_Buffer_API> + enter_buffer(bitstream_buffer->data, true); + if (enter_buffer.failed()) + return PP_ERROR_BADRESOURCE; + + if (!SetBitstreamBufferCallback(bitstream_buffer->id, callback)) + return PP_ERROR_BADARGUMENT; + + Buffer* ppb_buffer = + static_cast<Buffer*>(enter_buffer.object()); + HostResource host_buffer = ppb_buffer->host_resource(); + + FlushCommandBuffer(); + GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Decode( + API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), + host_buffer, bitstream_buffer->id, + bitstream_buffer->size)); + return PP_OK_COMPLETIONPENDING; +} + +void VideoDecoder::AssignPictureBuffers(uint32_t no_of_buffers, + const PP_PictureBuffer_Dev* buffers) { + std::vector<PP_PictureBuffer_Dev> buffer_list( + buffers, buffers + no_of_buffers); + FlushCommandBuffer(); + GetDispatcher()->Send( + new PpapiHostMsg_PPBVideoDecoder_AssignPictureBuffers( + API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), buffer_list)); +} + +void VideoDecoder::ReusePictureBuffer(int32_t picture_buffer_id) { + FlushCommandBuffer(); + GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_ReusePictureBuffer( + API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), picture_buffer_id)); +} + +int32_t VideoDecoder::Flush(scoped_refptr<TrackedCallback> callback) { + if (!SetFlushCallback(callback)) + return PP_ERROR_INPROGRESS; + + FlushCommandBuffer(); + GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Flush( + API_ID_PPB_VIDEO_DECODER_DEV, host_resource())); + return PP_OK_COMPLETIONPENDING; +} + +int32_t VideoDecoder::Reset(scoped_refptr<TrackedCallback> callback) { + if (!SetResetCallback(callback)) + return PP_ERROR_INPROGRESS; + + FlushCommandBuffer(); + GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Reset( + API_ID_PPB_VIDEO_DECODER_DEV, host_resource())); + return PP_OK_COMPLETIONPENDING; +} + +void VideoDecoder::Destroy() { + FlushCommandBuffer(); + GetDispatcher()->Send(new PpapiHostMsg_PPBVideoDecoder_Destroy( + API_ID_PPB_VIDEO_DECODER_DEV, host_resource())); + PPB_VideoDecoder_Shared::Destroy(); +} + +PluginDispatcher* VideoDecoder::GetDispatcher() const { + return PluginDispatcher::GetForResource(this); +} + +void VideoDecoder::ResetACK(int32_t result) { + RunResetCallback(result); +} + +void VideoDecoder::FlushACK(int32_t result) { + RunFlushCallback(result); +} + +void VideoDecoder::EndOfBitstreamACK( + int32_t bitstream_buffer_id, int32_t result) { + RunBitstreamBufferCallback(bitstream_buffer_id, result); +} + +PPB_VideoDecoder_Proxy::PPB_VideoDecoder_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + callback_factory_(this) { +} + +PPB_VideoDecoder_Proxy::~PPB_VideoDecoder_Proxy() { +} + +bool PPB_VideoDecoder_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_VideoDecoder_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Decode, OnMsgDecode) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_AssignPictureBuffers, + OnMsgAssignPictureBuffers) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_ReusePictureBuffer, + OnMsgReusePictureBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Flush, OnMsgFlush) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Reset, OnMsgReset) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVideoDecoder_Destroy, OnMsgDestroy) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBVideoDecoder_ResetACK, OnMsgResetACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBVideoDecoder_EndOfBitstreamACK, + OnMsgEndOfBitstreamACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBVideoDecoder_FlushACK, OnMsgFlushACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + DCHECK(handled); + return handled; +} + +PP_Resource PPB_VideoDecoder_Proxy::CreateProxyResource( + PP_Instance instance, + PP_Resource graphics_context, + PP_VideoDecoder_Profile profile) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + // Dispatcher is null if it cannot find the instance passed to it (i.e. if the + // client passes in an invalid instance). + if (!dispatcher) + return 0; + + EnterResourceNoLock<PPB_Graphics3D_API> enter_context(graphics_context, + true); + if (enter_context.failed()) + return 0; + + Graphics3D* context = static_cast<Graphics3D*>(enter_context.object()); + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBVideoDecoder_Create( + API_ID_PPB_VIDEO_DECODER_DEV, instance, + context->host_resource(), profile, &result)); + if (result.is_null()) + return 0; + + // Need a scoped_refptr to keep the object alive during the Init call. + scoped_refptr<VideoDecoder> decoder(new VideoDecoder(result)); + decoder->InitCommon(graphics_context, context->gles2_impl()); + return decoder->GetReference(); +} + +void PPB_VideoDecoder_Proxy::OnMsgCreate( + PP_Instance instance, const HostResource& graphics_context, + PP_VideoDecoder_Profile profile, + HostResource* result) { + thunk::EnterResourceCreation resource_creation(instance); + if (resource_creation.failed()) + return; + + // Make the resource and get the API pointer to its interface. + result->SetHostResource( + instance, resource_creation.functions()->CreateVideoDecoder( + instance, graphics_context.host_resource(), profile)); +} + +void PPB_VideoDecoder_Proxy::OnMsgDecode( + const HostResource& decoder, + const HostResource& buffer, int32 id, uint32 size) { + EnterHostFromHostResourceForceCallback<PPB_VideoDecoder_API> enter( + decoder, callback_factory_, + &PPB_VideoDecoder_Proxy::SendMsgEndOfBitstreamACKToPlugin, decoder, id); + if (enter.failed()) + return; + PP_VideoBitstreamBuffer_Dev bitstream = { id, buffer.host_resource(), size }; + enter.SetResult(enter.object()->Decode(&bitstream, enter.callback())); +} + +void PPB_VideoDecoder_Proxy::OnMsgAssignPictureBuffers( + const HostResource& decoder, + const std::vector<PP_PictureBuffer_Dev>& buffers) { + EnterHostFromHostResource<PPB_VideoDecoder_API> enter(decoder); + if (enter.succeeded() && !buffers.empty()) { + const PP_PictureBuffer_Dev* buffer_array = &buffers.front(); + enter.object()->AssignPictureBuffers(buffers.size(), buffer_array); + } +} + +void PPB_VideoDecoder_Proxy::OnMsgReusePictureBuffer( + const HostResource& decoder, int32 picture_buffer_id) { + EnterHostFromHostResource<PPB_VideoDecoder_API> enter(decoder); + if (enter.succeeded()) + enter.object()->ReusePictureBuffer(picture_buffer_id); +} + +void PPB_VideoDecoder_Proxy::OnMsgFlush(const HostResource& decoder) { + EnterHostFromHostResourceForceCallback<PPB_VideoDecoder_API> enter( + decoder, callback_factory_, + &PPB_VideoDecoder_Proxy::SendMsgFlushACKToPlugin, decoder); + if (enter.succeeded()) + enter.SetResult(enter.object()->Flush(enter.callback())); +} + +void PPB_VideoDecoder_Proxy::OnMsgReset(const HostResource& decoder) { + EnterHostFromHostResourceForceCallback<PPB_VideoDecoder_API> enter( + decoder, callback_factory_, + &PPB_VideoDecoder_Proxy::SendMsgResetACKToPlugin, decoder); + if (enter.succeeded()) + enter.SetResult(enter.object()->Reset(enter.callback())); +} + +void PPB_VideoDecoder_Proxy::OnMsgDestroy(const HostResource& decoder) { + EnterHostFromHostResource<PPB_VideoDecoder_API> enter(decoder); + if (enter.succeeded()) + enter.object()->Destroy(); +} + +void PPB_VideoDecoder_Proxy::SendMsgEndOfBitstreamACKToPlugin( + int32_t result, const HostResource& decoder, int32 id) { + dispatcher()->Send(new PpapiMsg_PPBVideoDecoder_EndOfBitstreamACK( + API_ID_PPB_VIDEO_DECODER_DEV, decoder, id, result)); +} + +void PPB_VideoDecoder_Proxy::SendMsgFlushACKToPlugin( + int32_t result, const HostResource& decoder) { + dispatcher()->Send(new PpapiMsg_PPBVideoDecoder_FlushACK( + API_ID_PPB_VIDEO_DECODER_DEV, decoder, result)); +} + +void PPB_VideoDecoder_Proxy::SendMsgResetACKToPlugin( + int32_t result, const HostResource& decoder) { + dispatcher()->Send(new PpapiMsg_PPBVideoDecoder_ResetACK( + API_ID_PPB_VIDEO_DECODER_DEV, decoder, result)); +} + +void PPB_VideoDecoder_Proxy::OnMsgEndOfBitstreamACK( + const HostResource& decoder, int32_t id, int32_t result) { + EnterPluginFromHostResource<PPB_VideoDecoder_API> enter(decoder); + if (enter.succeeded()) + static_cast<VideoDecoder*>(enter.object())->EndOfBitstreamACK(id, result); +} + +void PPB_VideoDecoder_Proxy::OnMsgFlushACK( + const HostResource& decoder, int32_t result) { + EnterPluginFromHostResource<PPB_VideoDecoder_API> enter(decoder); + if (enter.succeeded()) + static_cast<VideoDecoder*>(enter.object())->FlushACK(result); +} + +void PPB_VideoDecoder_Proxy::OnMsgResetACK( + const HostResource& decoder, int32_t result) { + EnterPluginFromHostResource<PPB_VideoDecoder_API> enter(decoder); + if (enter.succeeded()) + static_cast<VideoDecoder*>(enter.object())->ResetACK(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_video_decoder_proxy.h b/chromium/ppapi/proxy/ppb_video_decoder_proxy.h new file mode 100644 index 00000000000..e9127a7e63a --- /dev/null +++ b/chromium/ppapi/proxy/ppb_video_decoder_proxy.h @@ -0,0 +1,78 @@ +// 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 PPAPI_PROXY_PPB_VIDEO_DECODER_PROXY_H_ +#define PPAPI_PROXY_PPB_VIDEO_DECODER_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_completion_callback_factory.h" +#include "ppapi/shared_impl/ppb_video_decoder_shared.h" +#include "ppapi/thunk/ppb_video_decoder_api.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace ppapi { +namespace proxy { + +class PPB_VideoDecoder_Proxy : public InterfaceProxy { + public: + PPB_VideoDecoder_Proxy(Dispatcher* dispatcher); + virtual ~PPB_VideoDecoder_Proxy(); + + // Creates a VideoDecoder object in the plugin process. + static PP_Resource CreateProxyResource( + PP_Instance instance, + PP_Resource graphics_context, + PP_VideoDecoder_Profile profile); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + static const ApiID kApiID = API_ID_PPB_VIDEO_DECODER_DEV; + + private: + // Message handlers in the renderer process to receive messages from the + // plugin process. + void OnMsgCreate(PP_Instance instance, + const ppapi::HostResource& graphics_context, + PP_VideoDecoder_Profile profile, + ppapi::HostResource* result); + void OnMsgDecode( + const ppapi::HostResource& decoder, + const ppapi::HostResource& buffer, int32 id, uint32 size); + void OnMsgAssignPictureBuffers( + const ppapi::HostResource& decoder, + const std::vector<PP_PictureBuffer_Dev>& buffers); + void OnMsgReusePictureBuffer( + const ppapi::HostResource& decoder, + int32 picture_buffer_id); + void OnMsgFlush(const ppapi::HostResource& decoder); + void OnMsgReset(const ppapi::HostResource& decoder); + void OnMsgDestroy(const ppapi::HostResource& decoder); + + // Send a message from the renderer process to the plugin process to tell it + // to run its callback. + void SendMsgEndOfBitstreamACKToPlugin( + int32_t result, const ppapi::HostResource& decoder, int32 id); + void SendMsgFlushACKToPlugin( + int32_t result, const ppapi::HostResource& decoder); + void SendMsgResetACKToPlugin( + int32_t result, const ppapi::HostResource& decoder); + + // Message handlers in the plugin process to receive messages from the + // renderer process. + void OnMsgEndOfBitstreamACK(const ppapi::HostResource& decoder, + int32_t id, int32_t result); + void OnMsgFlushACK(const ppapi::HostResource& decoder, int32_t result); + void OnMsgResetACK(const ppapi::HostResource& decoder, int32_t result); + + ProxyCompletionCallbackFactory<PPB_VideoDecoder_Proxy> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_VideoDecoder_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_VIDEO_DECODER_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppb_x509_certificate_private_proxy.cc b/chromium/ppapi/proxy/ppb_x509_certificate_private_proxy.cc new file mode 100644 index 00000000000..7a9b01343f5 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_x509_certificate_private_proxy.cc @@ -0,0 +1,74 @@ +// 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 "ppapi/proxy/ppb_x509_certificate_private_proxy.h" + +#include "ppapi/c/private/ppb_x509_certificate_private.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" + +namespace ppapi { +namespace proxy { + +namespace { + +class X509CertificatePrivate : public PPB_X509Certificate_Private_Shared { + public: + X509CertificatePrivate(PP_Instance instance); + virtual ~X509CertificatePrivate(); + + virtual bool ParseDER(const std::vector<char>& der, + PPB_X509Certificate_Fields* result) OVERRIDE; + + private: + void SendToBrowser(IPC::Message* msg); + + DISALLOW_COPY_AND_ASSIGN(X509CertificatePrivate); +}; + +X509CertificatePrivate::X509CertificatePrivate(PP_Instance instance) + : PPB_X509Certificate_Private_Shared(OBJECT_IS_PROXY, instance) { +} + +X509CertificatePrivate::~X509CertificatePrivate() { +} + +bool X509CertificatePrivate::ParseDER(const std::vector<char>& der, + PPB_X509Certificate_Fields* result) { + bool succeeded = false; + SendToBrowser( + new PpapiHostMsg_PPBX509Certificate_ParseDER(der, &succeeded, result)); + return succeeded; +} + +void X509CertificatePrivate::SendToBrowser(IPC::Message* msg) { + PluginGlobals::Get()->GetBrowserSender()->Send(msg); +} + +} // namespace + +//------------------------------------------------------------------------------ + +PPB_X509Certificate_Private_Proxy::PPB_X509Certificate_Private_Proxy( + Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_X509Certificate_Private_Proxy::~PPB_X509Certificate_Private_Proxy() { +} + +// static +PP_Resource PPB_X509Certificate_Private_Proxy::CreateProxyResource( + PP_Instance instance) { + return (new X509CertificatePrivate(instance))->GetReference(); +} + +bool PPB_X509Certificate_Private_Proxy::OnMessageReceived( + const IPC::Message& msg) { + return false; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppb_x509_certificate_private_proxy.h b/chromium/ppapi/proxy/ppb_x509_certificate_private_proxy.h new file mode 100644 index 00000000000..4c51bab5617 --- /dev/null +++ b/chromium/ppapi/proxy/ppb_x509_certificate_private_proxy.h @@ -0,0 +1,36 @@ +// 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_PROXY_PPB_X509_CERTIFICATE_PRIVATE_PROXY_H_ +#define PPAPI_PROXY_PPB_X509_CERTIFICATE_PRIVATE_PROXY_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace ppapi { +namespace proxy { + +class PPB_X509Certificate_Private_Proxy + : public InterfaceProxy { + public: + explicit PPB_X509Certificate_Private_Proxy(Dispatcher* dispatcher); + virtual ~PPB_X509Certificate_Private_Proxy(); + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + static const ApiID kApiID = API_ID_PPB_X509_CERTIFICATE_PRIVATE; + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_X509Certificate_Private_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_X509_CERTIFICATE_PRIVATE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_class_proxy.cc b/chromium/ppapi/proxy/ppp_class_proxy.cc new file mode 100644 index 00000000000..3c28d0d54c0 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_class_proxy.cc @@ -0,0 +1,396 @@ +// 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 "ppapi/proxy/ppp_class_proxy.h" + +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/api_id.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// PPP_Class in the browser implementation ------------------------------------- + +// Represents a plugin-implemented class in the browser process. This just +// stores the data necessary to call back the plugin. +struct ObjectProxy { + ObjectProxy(Dispatcher* d, int64 p, int64 ud) + : dispatcher(d), + ppp_class(p), + user_data(ud) { + } + + Dispatcher* dispatcher; + int64 ppp_class; + int64 user_data; +}; + +ObjectProxy* ToObjectProxy(void* data) { + ObjectProxy* obj = reinterpret_cast<ObjectProxy*>(data); + if (!obj || !obj->dispatcher) + return NULL; + if (!obj->dispatcher->permissions().HasPermission(PERMISSION_DEV)) + return NULL; + return obj; +} + +bool HasProperty(void* object, PP_Var name, PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return false; + + bool result = false; + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_HasProperty( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, + SerializedVarSendInput(obj->dispatcher, name), &se, &result)); + return result; +} + +bool HasMethod(void* object, PP_Var name, PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return false; + + bool result = false; + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_HasMethod( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, + SerializedVarSendInput(obj->dispatcher, name), &se, &result)); + return result; +} + +PP_Var GetProperty(void* object, + PP_Var name, + PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return PP_MakeUndefined(); + + ReceiveSerializedException se(obj->dispatcher, exception); + ReceiveSerializedVarReturnValue result; + obj->dispatcher->Send(new PpapiMsg_PPPClass_GetProperty( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, + SerializedVarSendInput(obj->dispatcher, name), &se, &result)); + return result.Return(obj->dispatcher); +} + +void GetAllPropertyNames(void* object, + uint32_t* property_count, + PP_Var** properties, + PP_Var* exception) { + NOTIMPLEMENTED(); + // TODO(brettw) implement this. +} + +void SetProperty(void* object, + PP_Var name, + PP_Var value, + PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return; + + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_SetProperty( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, + SerializedVarSendInput(obj->dispatcher, name), + SerializedVarSendInput(obj->dispatcher, value), &se)); +} + +void RemoveProperty(void* object, + PP_Var name, + PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return; + + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_RemoveProperty( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, + SerializedVarSendInput(obj->dispatcher, name), &se)); +} + +PP_Var Call(void* object, + PP_Var method_name, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + ReceiveSerializedException se(obj->dispatcher, exception); + std::vector<SerializedVar> argv_vect; + SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc, + &argv_vect); + + obj->dispatcher->Send(new PpapiMsg_PPPClass_Call( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, + SerializedVarSendInput(obj->dispatcher, method_name), argv_vect, + &se, &result)); + return result.Return(obj->dispatcher); +} + +PP_Var Construct(void* object, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + ReceiveSerializedException se(obj->dispatcher, exception); + std::vector<SerializedVar> argv_vect; + SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc, + &argv_vect); + + obj->dispatcher->Send(new PpapiMsg_PPPClass_Construct( + API_ID_PPP_CLASS, + obj->ppp_class, obj->user_data, argv_vect, &se, &result)); + return result.Return(obj->dispatcher); +} + +void Deallocate(void* object) { + ObjectProxy* obj = ToObjectProxy(object); + if (!obj) + return; + + obj->dispatcher->Send(new PpapiMsg_PPPClass_Deallocate( + API_ID_PPP_CLASS, obj->ppp_class, obj->user_data)); + delete obj; +} + +const PPP_Class_Deprecated class_interface = { + &HasProperty, + &HasMethod, + &GetProperty, + &GetAllPropertyNames, + &SetProperty, + &RemoveProperty, + &Call, + &Construct, + &Deallocate +}; + +// Plugin helper functions ----------------------------------------------------- + +// Converts an int64 object from IPC to a PPP_Class* for calling into the +// plugin's implementation. +const PPP_Class_Deprecated* ToPPPClass(int64 value) { + return reinterpret_cast<const PPP_Class_Deprecated*>( + static_cast<intptr_t>(value)); +} + +// Converts an int64 object from IPC to a void* for calling into the plugin's +// implementation as the user data. +void* ToUserData(int64 value) { + return reinterpret_cast<void*>(static_cast<intptr_t>(value)); +} + +} // namespace + +// PPP_Class_Proxy ------------------------------------------------------------- + +PPP_Class_Proxy::PPP_Class_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPP_Class_Proxy::~PPP_Class_Proxy() { +} + +// static +InterfaceProxy* PPP_Class_Proxy::Create(Dispatcher* dispatcher) { + return new PPP_Class_Proxy(dispatcher); +} + +// static +PP_Var PPP_Class_Proxy::CreateProxiedObject(const PPB_Var_Deprecated* var, + Dispatcher* dispatcher, + PP_Instance instance_id, + int64 ppp_class, + int64 class_data) { + ObjectProxy* object_proxy = new ObjectProxy(dispatcher, + ppp_class, class_data); + return var->CreateObject(instance_id, &class_interface, object_proxy); +} + +// static +PP_Bool PPP_Class_Proxy::IsInstanceOf(const PPB_Var_Deprecated* ppb_var_impl, + const PP_Var& var, + int64 ppp_class, + int64* ppp_class_data) { + void* proxied_object = NULL; + if (ppb_var_impl->IsInstanceOf(var, + &class_interface, + &proxied_object)) { + if (static_cast<ObjectProxy*>(proxied_object)->ppp_class == ppp_class) { + DCHECK(ppp_class_data); + *ppp_class_data = static_cast<ObjectProxy*>(proxied_object)->user_data; + return PP_TRUE; + } + } + return PP_FALSE; +} + +bool PPP_Class_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; // These messages are only valid from host->plugin. + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Class_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasProperty, + OnMsgHasProperty) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasMethod, + OnMsgHasMethod) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_GetProperty, + OnMsgGetProperty) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_EnumerateProperties, + OnMsgEnumerateProperties) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_SetProperty, + OnMsgSetProperty) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Call, + OnMsgCall) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Construct, + OnMsgConstruct) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Deallocate, + OnMsgDeallocate) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Class_Proxy::OnMsgHasProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasProperty, + ToUserData(object), + property.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgHasMethod(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasMethod, + ToUserData(object), + property.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgGetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + result.Return(dispatcher(), CallWhileUnlocked( + ToPPPClass(ppp_class)->GetProperty, + ToUserData(object), property.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPP_Class_Proxy::OnMsgEnumerateProperties( + int64 ppp_class, int64 object, + std::vector<SerializedVar>* props, + SerializedVarOutParam exception) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + NOTIMPLEMENTED(); + // TODO(brettw) implement this. +} + +void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarReceiveInput value, + SerializedVarOutParam exception) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + CallWhileUnlocked(ToPPPClass(ppp_class)->SetProperty, + ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgRemoveProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + CallWhileUnlocked(ToPPPClass(ppp_class)->RemoveProperty, + ToUserData(object), property.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgCall( + int64 ppp_class, int64 object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), CallWhileUnlocked(ToPPPClass(ppp_class)->Call, + ToUserData(object), method_name.Get(dispatcher()), + arg_count, args, exception.OutParam(dispatcher()))); +} + +void PPP_Class_Proxy::OnMsgConstruct( + int64 ppp_class, int64 object, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + if (!ValidateUserData(ppp_class, object, &exception)) + return; + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), CallWhileUnlocked( + ToPPPClass(ppp_class)->Construct, + ToUserData(object), arg_count, args, exception.OutParam(dispatcher()))); +} + +void PPP_Class_Proxy::OnMsgDeallocate(int64 ppp_class, int64 object) { + if (!ValidateUserData(ppp_class, object, NULL)) + return; + PluginGlobals::Get()->plugin_var_tracker()->PluginImplementedObjectDestroyed( + ToUserData(object)); + CallWhileUnlocked(ToPPPClass(ppp_class)->Deallocate, ToUserData(object)); +} + +bool PPP_Class_Proxy::ValidateUserData(int64 ppp_class, int64 class_data, + SerializedVarOutParam* exception) { + if (!PluginGlobals::Get()->plugin_var_tracker()->ValidatePluginObjectCall( + ToPPPClass(ppp_class), ToUserData(class_data))) { + // Set the exception. This is so the caller will know about the error and + // also that we won't assert that somebody forgot to call OutParam on the + // output parameter. Although this exception of "1" won't be very useful + // this shouldn't happen in normal usage, only when the renderer is being + // malicious. + if (exception) + *exception->OutParam(dispatcher()) = PP_MakeInt32(1); + return false; + } + return true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_class_proxy.h b/chromium/ppapi/proxy/ppp_class_proxy.h new file mode 100644 index 00000000000..f890b3ddf44 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_class_proxy.h @@ -0,0 +1,100 @@ +// 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_PROXY_PPP_CLASS_PROXY_H_ +#define PPAPI_PROXY_PPP_CLASS_PROXY_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Var_Deprecated; + +namespace ppapi { +namespace proxy { + +class SerializedVar; +class SerializedVarReceiveInput; +class SerializedVarVectorReceiveInput; +class SerializedVarOutParam; +class SerializedVarReturnValue; + +class PPP_Class_Proxy : public InterfaceProxy { + public: + // PPP_Class isn't a normal interface that you can query for, so this + // constructor doesn't take an interface pointer. + explicit PPP_Class_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Class_Proxy(); + + // Factory function used for registration (normal code can just use the + // constructor). + static InterfaceProxy* Create(Dispatcher* dispatcher); + + // Creates a proxied object in the browser process. This takes the browser's + // PPB_Var_Deprecated interface to use to create the object. The class and + static PP_Var CreateProxiedObject(const PPB_Var_Deprecated* var, + Dispatcher* dispatcher, + PP_Instance instance_id, + int64 ppp_class, + int64 class_data); + + static PP_Bool IsInstanceOf(const PPB_Var_Deprecated* ppb_var_impl, + const PP_Var& var, + int64 ppp_class, + int64* ppp_class_data); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // IPC message handlers. + void OnMsgHasProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result); + void OnMsgHasMethod(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result); + void OnMsgGetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgEnumerateProperties( + int64 ppp_class, int64 object, + std::vector<SerializedVar>* props, + SerializedVarOutParam exception); + void OnMsgSetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarReceiveInput value, + SerializedVarOutParam exception); + void OnMsgRemoveProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception); + void OnMsgCall(int64 ppp_class, int64 object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgConstruct(int64 ppp_class, int64 object, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgDeallocate(int64 ppp_class, int64 object); + + // Returns true if the given class/data points to a plugin-implemented + // object. On failure, the exception, if non-NULL, will also be set. + bool ValidateUserData(int64 ppp_class, int64 class_data, + SerializedVarOutParam* exception); + + DISALLOW_COPY_AND_ASSIGN(PPP_Class_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_CLASS_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_content_decryptor_private_proxy.cc b/chromium/ppapi/proxy/ppp_content_decryptor_private_proxy.cc new file mode 100644 index 00000000000..f986e7f8d72 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_content_decryptor_private_proxy.cc @@ -0,0 +1,581 @@ +// 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 "ppapi/proxy/ppp_content_decryptor_private_proxy.h" + +#include "base/platform_file.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/proxy/content_decryptor_private_serializer.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/shared_impl/var_tracker.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_buffer_api.h" +#include "ppapi/thunk/ppb_instance_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Buffer_API; +using ppapi::thunk::PPB_Instance_API; + +namespace ppapi { +namespace proxy { + +namespace { + +PP_Bool DescribeHostBufferResource(PP_Resource resource, uint32_t* size) { + EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); + if (enter.failed()) + return PP_FALSE; + return enter.object()->Describe(size); +} + +// TODO(dmichael): Refactor so this handle sharing code is in one place. +PP_Bool ShareHostBufferResourceToPlugin( + HostDispatcher* dispatcher, + PP_Resource resource, + base::SharedMemoryHandle* shared_mem_handle) { + if (!dispatcher || resource == 0 || !shared_mem_handle) + return PP_FALSE; + EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); + if (enter.failed()) + return PP_FALSE; + int handle; + int32_t result = enter.object()->GetSharedMemory(&handle); + if (result != PP_OK) + return PP_FALSE; + base::PlatformFile platform_file = + #if defined(OS_WIN) + reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle)); + #elif defined(OS_POSIX) + handle; + #else + #error Not implemented. + #endif + + *shared_mem_handle = dispatcher->ShareHandleWithRemote(platform_file, false); + return PP_TRUE; +} + +// SerializedVarReceiveInput will decrement the reference count, but we want +// to give the recipient a reference. This utility function takes care of that +// work for the message handlers defined below. +PP_Var ExtractReceivedVarAndAddRef(Dispatcher* dispatcher, + SerializedVarReceiveInput* serialized_var) { + PP_Var var = serialized_var->Get(dispatcher); + PpapiGlobals::Get()->GetVarTracker()->AddRefVar(var); + return var; +} + +bool InitializePppDecryptorBuffer(PP_Instance instance, + HostDispatcher* dispatcher, + PP_Resource resource, + PPPDecryptor_Buffer* buffer) { + if (!buffer) { + NOTREACHED(); + return false; + } + + if (resource == 0) { + buffer->resource = HostResource(); + buffer->handle = base::SharedMemoryHandle(); + buffer->size = 0; + return true; + } + + HostResource host_resource; + host_resource.SetHostResource(instance, resource); + + uint32_t size = 0; + if (DescribeHostBufferResource(resource, &size) == PP_FALSE) + return false; + + base::SharedMemoryHandle handle; + if (ShareHostBufferResourceToPlugin(dispatcher, + resource, + &handle) == PP_FALSE) + return false; + + buffer->resource = host_resource; + buffer->handle = handle; + buffer->size = size; + return true; +} + +void GenerateKeyRequest(PP_Instance instance, + PP_Var key_system, + PP_Var type, + PP_Var init_data) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_GenerateKeyRequest( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + SerializedVarSendInput(dispatcher, key_system), + SerializedVarSendInput(dispatcher, type), + SerializedVarSendInput(dispatcher, init_data))); +} + +void AddKey(PP_Instance instance, + PP_Var session_id, + PP_Var key, + PP_Var init_data) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_AddKey( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + SerializedVarSendInput(dispatcher, session_id), + SerializedVarSendInput(dispatcher, key), + SerializedVarSendInput(dispatcher, init_data))); +} + +void CancelKeyRequest(PP_Instance instance, PP_Var session_id) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_CancelKeyRequest( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + SerializedVarSendInput(dispatcher, session_id))); +} + +void Decrypt(PP_Instance instance, + PP_Resource encrypted_block, + const PP_EncryptedBlockInfo* encrypted_block_info) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + PPPDecryptor_Buffer buffer; + if (!InitializePppDecryptorBuffer(instance, + dispatcher, + encrypted_block, + &buffer)) { + NOTREACHED(); + return; + } + + std::string serialized_block_info; + if (!SerializeBlockInfo(*encrypted_block_info, &serialized_block_info)) { + NOTREACHED(); + return; + } + + // PluginResourceTracker in the plugin process assumes that resources that it + // tracks have been addrefed on behalf of the plugin at the renderer side. So + // we explicitly do it for |encryped_block| here. + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_block); + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_Decrypt( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + buffer, + serialized_block_info)); +} + +void InitializeAudioDecoder( + PP_Instance instance, + const PP_AudioDecoderConfig* decoder_config, + PP_Resource extra_data_buffer) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + std::string serialized_decoder_config; + if (!SerializeBlockInfo(*decoder_config, &serialized_decoder_config)) { + NOTREACHED(); + return; + } + + PPPDecryptor_Buffer buffer; + if (!InitializePppDecryptorBuffer(instance, + dispatcher, + extra_data_buffer, + &buffer)) { + NOTREACHED(); + return; + } + + // PluginResourceTracker in the plugin process assumes that resources that it + // tracks have been addrefed on behalf of the plugin at the renderer side. So + // we explicitly do it for |extra_data_buffer| here. + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer); + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + serialized_decoder_config, + buffer)); +} + +void InitializeVideoDecoder( + PP_Instance instance, + const PP_VideoDecoderConfig* decoder_config, + PP_Resource extra_data_buffer) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + std::string serialized_decoder_config; + if (!SerializeBlockInfo(*decoder_config, &serialized_decoder_config)) { + NOTREACHED(); + return; + } + + PPPDecryptor_Buffer buffer; + if (!InitializePppDecryptorBuffer(instance, + dispatcher, + extra_data_buffer, + &buffer)) { + NOTREACHED(); + return; + } + + // PluginResourceTracker in the plugin process assumes that resources that it + // tracks have been addrefed on behalf of the plugin at the renderer side. So + // we explicitly do it for |extra_data_buffer| here. + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer); + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + serialized_decoder_config, + buffer)); +} + + +void DeinitializeDecoder(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_DeinitializeDecoder( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + decoder_type, + request_id)); +} + +void ResetDecoder(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_ResetDecoder( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + decoder_type, + request_id)); +} + +void DecryptAndDecode(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + PP_Resource encrypted_buffer, + const PP_EncryptedBlockInfo* encrypted_block_info) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return; + } + + PPPDecryptor_Buffer buffer; + if (!InitializePppDecryptorBuffer(instance, + dispatcher, + encrypted_buffer, + &buffer)) { + NOTREACHED(); + return; + } + + std::string serialized_block_info; + if (!SerializeBlockInfo(*encrypted_block_info, &serialized_block_info)) { + NOTREACHED(); + return; + } + + // PluginResourceTracker in the plugin process assumes that resources that it + // tracks have been addrefed on behalf of the plugin at the renderer side. So + // we explicitly do it for |encrypted_buffer| here. + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_buffer); + + dispatcher->Send( + new PpapiMsg_PPPContentDecryptor_DecryptAndDecode( + API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, + instance, + decoder_type, + buffer, + serialized_block_info)); +} + +static const PPP_ContentDecryptor_Private content_decryptor_interface = { + &GenerateKeyRequest, + &AddKey, + &CancelKeyRequest, + &Decrypt, + &InitializeAudioDecoder, + &InitializeVideoDecoder, + &DeinitializeDecoder, + &ResetDecoder, + &DecryptAndDecode +}; + +} // namespace + +PPP_ContentDecryptor_Private_Proxy::PPP_ContentDecryptor_Private_Proxy( + Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_decryptor_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_decryptor_impl_ = static_cast<const PPP_ContentDecryptor_Private*>( + dispatcher->local_get_interface()( + PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE)); + } +} + +PPP_ContentDecryptor_Private_Proxy::~PPP_ContentDecryptor_Private_Proxy() { +} + +// static +const PPP_ContentDecryptor_Private* + PPP_ContentDecryptor_Private_Proxy::GetProxyInterface() { + return &content_decryptor_interface; +} + +bool PPP_ContentDecryptor_Private_Proxy::OnMessageReceived( + const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; // These are only valid from host->plugin. + // Don't allow the plugin to send these to the host. + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_ContentDecryptor_Private_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_GenerateKeyRequest, + OnMsgGenerateKeyRequest) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_AddKey, + OnMsgAddKey) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_CancelKeyRequest, + OnMsgCancelKeyRequest) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Decrypt, + OnMsgDecrypt) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder, + OnMsgInitializeAudioDecoder) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder, + OnMsgInitializeVideoDecoder) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DeinitializeDecoder, + OnMsgDeinitializeDecoder) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_ResetDecoder, + OnMsgResetDecoder) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DecryptAndDecode, + OnMsgDecryptAndDecode) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + DCHECK(handled); + return handled; +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgGenerateKeyRequest( + PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput type, + SerializedVarReceiveInput init_data) { + if (ppp_decryptor_impl_) { + CallWhileUnlocked(ppp_decryptor_impl_->GenerateKeyRequest, + instance, + ExtractReceivedVarAndAddRef(dispatcher(), &key_system), + ExtractReceivedVarAndAddRef(dispatcher(), &type), + ExtractReceivedVarAndAddRef(dispatcher(), &init_data)); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgAddKey( + PP_Instance instance, + SerializedVarReceiveInput session_id, + SerializedVarReceiveInput key, + SerializedVarReceiveInput init_data) { + if (ppp_decryptor_impl_) { + CallWhileUnlocked(ppp_decryptor_impl_->AddKey, + instance, + ExtractReceivedVarAndAddRef(dispatcher(), &session_id), + ExtractReceivedVarAndAddRef(dispatcher(), &key), + ExtractReceivedVarAndAddRef(dispatcher(), &init_data)); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgCancelKeyRequest( + PP_Instance instance, + SerializedVarReceiveInput session_id) { + if (ppp_decryptor_impl_) { + CallWhileUnlocked(ppp_decryptor_impl_->CancelKeyRequest, + instance, + ExtractReceivedVarAndAddRef(dispatcher(), &session_id)); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgDecrypt( + PP_Instance instance, + const PPPDecryptor_Buffer& encrypted_buffer, + const std::string& serialized_block_info) { + ScopedPPResource plugin_resource( + ScopedPPResource::PassRef(), + PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer.resource, + encrypted_buffer.handle, + encrypted_buffer.size)); + if (ppp_decryptor_impl_) { + PP_EncryptedBlockInfo block_info; + if (!DeserializeBlockInfo(serialized_block_info, &block_info)) + return; + CallWhileUnlocked(ppp_decryptor_impl_->Decrypt, + instance, + plugin_resource.get(), + const_cast<const PP_EncryptedBlockInfo*>(&block_info)); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeAudioDecoder( + PP_Instance instance, + const std::string& serialized_decoder_config, + const PPPDecryptor_Buffer& extra_data_buffer) { + ScopedPPResource plugin_resource; + if (extra_data_buffer.size > 0) { + plugin_resource = ScopedPPResource( + ScopedPPResource::PassRef(), + PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer.resource, + extra_data_buffer.handle, + extra_data_buffer.size)); + } + + PP_AudioDecoderConfig decoder_config; + if (!DeserializeBlockInfo(serialized_decoder_config, &decoder_config)) + return; + + if (ppp_decryptor_impl_) { + CallWhileUnlocked( + ppp_decryptor_impl_->InitializeAudioDecoder, + instance, + const_cast<const PP_AudioDecoderConfig*>(&decoder_config), + plugin_resource.get()); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeVideoDecoder( + PP_Instance instance, + const std::string& serialized_decoder_config, + const PPPDecryptor_Buffer& extra_data_buffer) { + ScopedPPResource plugin_resource; + if (extra_data_buffer.resource.host_resource() != 0) { + plugin_resource = ScopedPPResource( + ScopedPPResource::PassRef(), + PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer.resource, + extra_data_buffer.handle, + extra_data_buffer.size)); + } + + PP_VideoDecoderConfig decoder_config; + if (!DeserializeBlockInfo(serialized_decoder_config, &decoder_config)) + return; + + if (ppp_decryptor_impl_) { + CallWhileUnlocked( + ppp_decryptor_impl_->InitializeVideoDecoder, + instance, + const_cast<const PP_VideoDecoderConfig*>(&decoder_config), + plugin_resource.get()); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgDeinitializeDecoder( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + if (ppp_decryptor_impl_) { + CallWhileUnlocked( + ppp_decryptor_impl_->DeinitializeDecoder, + instance, + decoder_type, + request_id); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgResetDecoder( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id) { + if (ppp_decryptor_impl_) { + CallWhileUnlocked( + ppp_decryptor_impl_->ResetDecoder, + instance, + decoder_type, + request_id); + } +} + +void PPP_ContentDecryptor_Private_Proxy::OnMsgDecryptAndDecode( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + const PPPDecryptor_Buffer& encrypted_buffer, + const std::string& serialized_block_info) { + ScopedPPResource plugin_resource; + if (encrypted_buffer.resource.host_resource() != 0) { + plugin_resource = ScopedPPResource( + ScopedPPResource::PassRef(), + PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer.resource, + encrypted_buffer.handle, + encrypted_buffer.size)); + } + + if (ppp_decryptor_impl_) { + PP_EncryptedBlockInfo block_info; + if (!DeserializeBlockInfo(serialized_block_info, &block_info)) + return; + CallWhileUnlocked( + ppp_decryptor_impl_->DecryptAndDecode, + instance, + decoder_type, + plugin_resource.get(), + const_cast<const PP_EncryptedBlockInfo*>(&block_info)); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_content_decryptor_private_proxy.h b/chromium/ppapi/proxy/ppp_content_decryptor_private_proxy.h new file mode 100644 index 00000000000..5e7ecc85dba --- /dev/null +++ b/chromium/ppapi/proxy/ppp_content_decryptor_private_proxy.h @@ -0,0 +1,74 @@ +// 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_PROXY_PPP_CONTENT_DECRYPTOR_PRIVATE_PROXY_H_ +#define PPAPI_PROXY_PPP_CONTENT_DECRYPTOR_PRIVATE_PROXY_H_ + +#include <string> + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/private/ppp_content_decryptor_private.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/host_resource.h" + +namespace ppapi { +namespace proxy { + +class SerializedVarReceiveInput; + +class PPP_ContentDecryptor_Private_Proxy : public InterfaceProxy { + public: + explicit PPP_ContentDecryptor_Private_Proxy(Dispatcher* dispatcher); + virtual ~PPP_ContentDecryptor_Private_Proxy(); + + static const PPP_ContentDecryptor_Private* GetProxyInterface(); + + private: + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // Message handlers. + void OnMsgGenerateKeyRequest(PP_Instance instance, + SerializedVarReceiveInput key_system, + SerializedVarReceiveInput type, + SerializedVarReceiveInput init_data); + void OnMsgAddKey(PP_Instance instance, + SerializedVarReceiveInput session_id, + SerializedVarReceiveInput key, + SerializedVarReceiveInput init_data); + void OnMsgCancelKeyRequest(PP_Instance instance, + SerializedVarReceiveInput session_id); + void OnMsgDecrypt(PP_Instance instance, + const PPPDecryptor_Buffer& encrypted_buffer, + const std::string& serialized_encrypted_block_info); + void OnMsgInitializeAudioDecoder( + PP_Instance instance, + const std::string& decoder_config, + const PPPDecryptor_Buffer& extra_data_buffer); + void OnMsgInitializeVideoDecoder( + PP_Instance instance, + const std::string& decoder_config, + const PPPDecryptor_Buffer& extra_data_buffer); + void OnMsgDeinitializeDecoder(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id); + void OnMsgResetDecoder(PP_Instance instance, + PP_DecryptorStreamType decoder_type, + uint32_t request_id); + void OnMsgDecryptAndDecode( + PP_Instance instance, + PP_DecryptorStreamType decoder_type, + const PPPDecryptor_Buffer& encrypted_buffer, + const std::string& serialized_encrypted_block_info); + + const PPP_ContentDecryptor_Private* ppp_decryptor_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_ContentDecryptor_Private_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_CONTENT_DECRYPTOR_PRIVATE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_graphics_3d_proxy.cc b/chromium/ppapi/proxy/ppp_graphics_3d_proxy.cc new file mode 100644 index 00000000000..ee00a925ed0 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_graphics_3d_proxy.cc @@ -0,0 +1,81 @@ +// 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 "ppapi/proxy/ppp_graphics_3d_proxy.h" + +#include "ppapi/c/ppp_graphics_3d.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +#if !defined(OS_NACL) +void ContextLost(PP_Instance instance) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPGraphics3D_ContextLost(API_ID_PPP_GRAPHICS_3D, instance)); +} + +static const PPP_Graphics3D graphics_3d_interface = { + &ContextLost +}; +#else +// The NaCl plugin doesn't need the host side interface - stub it out. +static const PPP_Graphics3D graphics_3d_interface = {}; +#endif // !defined(OS_NACL) + +InterfaceProxy* CreateGraphics3DProxy(Dispatcher* dispatcher) { + return new PPP_Graphics3D_Proxy(dispatcher); +} + +} // namespace + +PPP_Graphics3D_Proxy::PPP_Graphics3D_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_graphics_3d_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_graphics_3d_impl_ = static_cast<const PPP_Graphics3D*>( + dispatcher->local_get_interface()(PPP_GRAPHICS_3D_INTERFACE)); + } +} + +PPP_Graphics3D_Proxy::~PPP_Graphics3D_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_Graphics3D_Proxy::GetInfo() { + static const Info info = { + &graphics_3d_interface, + PPP_GRAPHICS_3D_INTERFACE, + API_ID_PPP_GRAPHICS_3D, + false, + &CreateGraphics3DProxy, + }; + return &info; +} + +bool PPP_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Graphics3D_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPGraphics3D_ContextLost, + OnMsgContextLost) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Graphics3D_Proxy::OnMsgContextLost(PP_Instance instance) { + if (ppp_graphics_3d_impl_) + CallWhileUnlocked(ppp_graphics_3d_impl_->Graphics3DContextLost, instance); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_graphics_3d_proxy.h b/chromium/ppapi/proxy/ppp_graphics_3d_proxy.h new file mode 100644 index 00000000000..9b4d7a0fe67 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_graphics_3d_proxy.h @@ -0,0 +1,41 @@ +// 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_PROXY_PPP_GRAPHICS_3D_PROXY_H_ +#define PPAPI_PROXY_PPP_GRAPHICS_3D_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/ppp_graphics_3d.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/host_resource.h" + +namespace ppapi { +namespace proxy { + +class PPP_Graphics3D_Proxy : public InterfaceProxy { + public: + PPP_Graphics3D_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Graphics3D_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgContextLost(PP_Instance instance); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_Graphics3D* ppp_graphics_3d_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_Graphics3D_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_GRAPHICS_3D_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_input_event_proxy.cc b/chromium/ppapi/proxy/ppp_input_event_proxy.cc new file mode 100644 index 00000000000..8302dfd12db --- /dev/null +++ b/chromium/ppapi/proxy/ppp_input_event_proxy.cc @@ -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. + +#include "ppapi/proxy/ppp_input_event_proxy.h" + +#include "ppapi/c/ppp_input_event.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppb_input_event_shared.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_input_event_api.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_InputEvent_API; + +namespace ppapi { +namespace proxy { + +namespace { + +#if !defined(OS_NACL) +PP_Bool HandleInputEvent(PP_Instance instance, PP_Resource input_event) { + EnterResourceNoLock<PPB_InputEvent_API> enter(input_event, false); + if (enter.failed()) { + NOTREACHED(); + return PP_FALSE; + } + const InputEventData& data = enter.object()->GetInputEventData(); + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return PP_FALSE; + } + + // Need to send different messages depending on whether filtering is needed. + PP_Bool result = PP_FALSE; + if (data.is_filtered) { + dispatcher->Send(new PpapiMsg_PPPInputEvent_HandleFilteredInputEvent( + API_ID_PPP_INPUT_EVENT, instance, data, &result)); + } else { + dispatcher->Send(new PpapiMsg_PPPInputEvent_HandleInputEvent( + API_ID_PPP_INPUT_EVENT, instance, data)); + } + return result; +} + +static const PPP_InputEvent input_event_interface = { + &HandleInputEvent +}; +#else +// The NaCl plugin doesn't need the host side interface - stub it out. +static const PPP_InputEvent input_event_interface = {}; +#endif // !defined(OS_NACL) + +InterfaceProxy* CreateInputEventProxy(Dispatcher* dispatcher) { + return new PPP_InputEvent_Proxy(dispatcher); +} + +} // namespace + +PPP_InputEvent_Proxy::PPP_InputEvent_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_input_event_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_input_event_impl_ = static_cast<const PPP_InputEvent*>( + dispatcher->local_get_interface()(PPP_INPUT_EVENT_INTERFACE)); + } +} + +PPP_InputEvent_Proxy::~PPP_InputEvent_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_InputEvent_Proxy::GetInfo() { + static const Info info = { + &input_event_interface, + PPP_INPUT_EVENT_INTERFACE, + API_ID_PPP_INPUT_EVENT, + false, + &CreateInputEventProxy, + }; + return &info; +} + +bool PPP_InputEvent_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_InputEvent_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInputEvent_HandleInputEvent, + OnMsgHandleInputEvent) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInputEvent_HandleFilteredInputEvent, + OnMsgHandleFilteredInputEvent) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_InputEvent_Proxy::OnMsgHandleInputEvent(PP_Instance instance, + const InputEventData& data) { + scoped_refptr<PPB_InputEvent_Shared> resource(new PPB_InputEvent_Shared( + OBJECT_IS_PROXY, instance, data)); + CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent, + instance, + resource->pp_resource()); +} + +void PPP_InputEvent_Proxy::OnMsgHandleFilteredInputEvent( + PP_Instance instance, + const InputEventData& data, + PP_Bool* result) { + scoped_refptr<PPB_InputEvent_Shared> resource(new PPB_InputEvent_Shared( + OBJECT_IS_PROXY, instance, data)); + *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent, + instance, + resource->pp_resource()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_input_event_proxy.h b/chromium/ppapi/proxy/ppp_input_event_proxy.h new file mode 100644 index 00000000000..a7cc05455c9 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_input_event_proxy.h @@ -0,0 +1,47 @@ +// 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_PROXY_PPP_INPUT_EVENT_PROXY_H_ +#define PPAPI_PROXY_PPP_INPUT_EVENT_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/ppp_input_event.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace ppapi { + +struct InputEventData; + +namespace proxy { + +class PPP_InputEvent_Proxy : public InterfaceProxy { + public: + PPP_InputEvent_Proxy(Dispatcher* dispatcher); + virtual ~PPP_InputEvent_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgHandleInputEvent(PP_Instance instance, + const ppapi::InputEventData& data); + void OnMsgHandleFilteredInputEvent(PP_Instance instance, + const ppapi::InputEventData& data, + PP_Bool* result); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_InputEvent* ppp_input_event_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_InputEvent_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_INPUT_EVENT_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_instance_private_proxy.cc b/chromium/ppapi/proxy/ppp_instance_private_proxy.cc new file mode 100644 index 00000000000..1d8b8d753ca --- /dev/null +++ b/chromium/ppapi/proxy/ppp_instance_private_proxy.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 "ppapi/proxy/ppp_instance_private_proxy.h" + +#include <algorithm> + +#include "ppapi/c/pp_var.h" +#include "ppapi/c/private/ppp_instance_private.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +PP_Var GetInstanceObject(PP_Instance instance) { + Dispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher->permissions().HasPermission(PERMISSION_PRIVATE)) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiMsg_PPPInstancePrivate_GetInstanceObject( + API_ID_PPP_INSTANCE_PRIVATE, instance, &result)); + return result.Return(dispatcher); +} + +static const PPP_Instance_Private instance_private_interface = { + &GetInstanceObject +}; + +InterfaceProxy* CreateInstancePrivateProxy(Dispatcher* dispatcher) { + return new PPP_Instance_Private_Proxy(dispatcher); +} + +} // namespace + +PPP_Instance_Private_Proxy::PPP_Instance_Private_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_instance_private_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_instance_private_impl_ = static_cast<const PPP_Instance_Private*>( + dispatcher->local_get_interface()(PPP_INSTANCE_PRIVATE_INTERFACE)); + } +} + +PPP_Instance_Private_Proxy::~PPP_Instance_Private_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_Instance_Private_Proxy::GetInfo() { + static const Info info = { + &instance_private_interface, + PPP_INSTANCE_PRIVATE_INTERFACE, + API_ID_PPP_INSTANCE_PRIVATE, + false, + &CreateInstancePrivateProxy, + }; + return &info; +} + +bool PPP_Instance_Private_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Private_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstancePrivate_GetInstanceObject, + OnMsgGetInstanceObject) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Instance_Private_Proxy::OnMsgGetInstanceObject( + PP_Instance instance, + SerializedVarReturnValue result) { + result.Return(dispatcher(), + CallWhileUnlocked(ppp_instance_private_impl_->GetInstanceObject, + instance)); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_instance_private_proxy.h b/chromium/ppapi/proxy/ppp_instance_private_proxy.h new file mode 100644 index 00000000000..60d5ea9f1f3 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_instance_private_proxy.h @@ -0,0 +1,46 @@ +// 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 PPAPI_PROXY_PPP_INSTANCE_PRIVATE_PROXY_H_ +#define PPAPI_PROXY_PPP_INSTANCE_PRIVATE_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/private/ppp_instance_private.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/host_resource.h" + +namespace ppapi { +namespace proxy { + +class SerializedVarReturnValue; + +class PPP_Instance_Private_Proxy : public InterfaceProxy { + public: + PPP_Instance_Private_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Instance_Private_Proxy(); + + static const Info* GetInfo(); + + private: + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // Message handlers. + void OnMsgGetInstanceObject(PP_Instance instance, + SerializedVarReturnValue result); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_Instance_Private* ppp_instance_private_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_Instance_Private_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_INSTANCE_PRIVATE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_instance_private_proxy_unittest.cc b/chromium/ppapi/proxy/ppp_instance_private_proxy_unittest.cc new file mode 100644 index 00000000000..abafa87d0e8 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_instance_private_proxy_unittest.cc @@ -0,0 +1,210 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/test/test_timeouts.h" +#include "base/time/time.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/c/private/ppp_instance_private.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/interface_list.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/ppapi_permissions.h" +#include "ppapi/shared_impl/ppb_var_shared.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { + +// A fake version of NPObjectVar for testing. +class NPObjectVar : public ppapi::Var { + public: + NPObjectVar() {} + virtual ~NPObjectVar() {} + + // Var overrides. + virtual NPObjectVar* AsNPObjectVar() OVERRIDE { return this; } + virtual PP_VarType GetType() const OVERRIDE { return PP_VARTYPE_OBJECT; } +}; + +namespace proxy { + +namespace { +const PP_Instance kInstance = 0xdeadbeef; + +PP_Var GetPPVarNoAddRef(Var* var) { + PP_Var var_to_return = var->GetPPVar(); + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var_to_return); + return var_to_return; +} + +PluginDispatcher* plugin_dispatcher = NULL; +// Return the plugin-side proxy for PPB_Var_Deprecated. +const PPB_Var_Deprecated* plugin_var_deprecated_if() { + // The test code must set the plugin dispatcher. + CHECK(plugin_dispatcher); + // Grab the plugin-side proxy for PPB_Var_Deprecated (for CreateObject). + return static_cast<const PPB_Var_Deprecated*>( + plugin_dispatcher->GetBrowserInterface( + PPB_VAR_DEPRECATED_INTERFACE)); +} + +// Mock PPP_Instance_Private. +PP_Var instance_obj; +PP_Var GetInstanceObject(PP_Instance /*instance*/) { + // The 1 ref we got from CreateObject will be passed to the host. We want to + // have a ref of our own. + printf("GetInstanceObject called\n"); + plugin_var_deprecated_if()->AddRef(instance_obj); + return instance_obj; +} + +PPP_Instance_Private ppp_instance_private_mock = { + &GetInstanceObject +}; + +// We need to pass in a |PPP_Class_Deprecated| to +// |PPB_Var_Deprecated->CreateObject| for a mock |Deallocate| method. +void Deallocate(void* object) { +} + +const PPP_Class_Deprecated ppp_class_deprecated_mock = { + NULL, // HasProperty + NULL, // HasMethod + NULL, // GetProperty + NULL, // GetAllPropertyNames + NULL, // SetProperty + NULL, // RemoveProperty + NULL, // Call + NULL, // Construct + &Deallocate +}; + + +// We need to mock PPP_Instance, so that we can create and destroy the pretend +// instance that PPP_Instance_Private uses. +PP_Bool DidCreate(PP_Instance /*instance*/, uint32_t /*argc*/, + const char* /*argn*/[], const char* /*argv*/[]) { + // Create an object var. This should exercise the typical path for creating + // instance objects. + instance_obj = + plugin_var_deprecated_if()->CreateObject(kInstance, + &ppp_class_deprecated_mock, + NULL); + return PP_TRUE; +} + +void DidDestroy(PP_Instance /*instance*/) { + // Decrement the reference count for our instance object. It should be + // deleted. + plugin_var_deprecated_if()->Release(instance_obj); +} + +PPP_Instance_1_0 ppp_instance_mock = { &DidCreate, &DidDestroy }; + +// Mock PPB_Var_Deprecated, so that we can emulate creating an Object Var. +PP_Var CreateObject(PP_Instance /*instance*/, + const PPP_Class_Deprecated* /*ppp_class*/, + void* /*ppp_class_data*/) { + NPObjectVar* obj_var = new NPObjectVar; + return obj_var->GetPPVar(); +} + +const PPB_Var_Deprecated ppb_var_deprecated_mock = { + PPB_Var_Shared::GetVarInterface1_0()->AddRef, + PPB_Var_Shared::GetVarInterface1_0()->Release, + PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, + PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, + NULL, // HasProperty + NULL, // HasMethod + NULL, // GetProperty + NULL, // EnumerateProperties + NULL, // SetProperty + NULL, // RemoveProperty + NULL, // Call + NULL, // Construct + NULL, // IsInstanceOf + &CreateObject +}; + +class PPP_Instance_Private_ProxyTest : public TwoWayTest { + public: + PPP_Instance_Private_ProxyTest() + : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { + plugin().RegisterTestInterface(PPP_INSTANCE_PRIVATE_INTERFACE, + &ppp_instance_private_mock); + plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_1_0, + &ppp_instance_mock); + host().RegisterTestInterface(PPB_VAR_DEPRECATED_INTERFACE, + &ppb_var_deprecated_mock); + } +}; + +} // namespace + +TEST_F(PPP_Instance_Private_ProxyTest, PPPInstancePrivate) { + // This test controls its own instance; we can't use the one that + // PluginProxyTestHarness provides. + ASSERT_NE(kInstance, pp_instance()); + HostDispatcher::SetForInstance(kInstance, host().host_dispatcher()); + + // Requires dev interfaces. + InterfaceList::SetProcessGlobalPermissions( + PpapiPermissions::AllPermissions()); + + // This file-local global is used by the PPP_Instance mock above in order to + // access PPB_Var_Deprecated. + plugin_dispatcher = plugin().plugin_dispatcher(); + + // Grab the host-side proxy for PPP_Instance and PPP_Instance_Private. + const PPP_Instance_Private* ppp_instance_private = + static_cast<const PPP_Instance_Private*>( + host().host_dispatcher()->GetProxiedInterface( + PPP_INSTANCE_PRIVATE_INTERFACE)); + const PPP_Instance_1_1* ppp_instance = static_cast<const PPP_Instance_1_1*>( + host().host_dispatcher()->GetProxiedInterface( + PPP_INSTANCE_INTERFACE_1_1)); + + // Initialize an Instance, so that the plugin-side machinery will work + // properly. + EXPECT_EQ(PP_TRUE, ppp_instance->DidCreate(kInstance, 0, NULL, NULL)); + + // Check the plugin-side reference count. + EXPECT_EQ(1, plugin().var_tracker().GetRefCountForObject(instance_obj)); + // Check the host-side var exists with the expected id and has 1 refcount (the + // refcount on behalf of the plugin). + int32 expected_host_id = + plugin().var_tracker().GetHostObject(instance_obj).value.as_id; + Var* host_var = host().var_tracker().GetVar(expected_host_id); + ASSERT_TRUE(host_var); + EXPECT_EQ( + 1, + host().var_tracker().GetRefCountForObject(GetPPVarNoAddRef(host_var))); + + // Call from the browser side to get the instance object. + PP_Var host_pp_var = ppp_instance_private->GetInstanceObject(kInstance); + EXPECT_EQ(instance_obj.type, host_pp_var.type); + EXPECT_EQ(host_pp_var.value.as_id, expected_host_id); + EXPECT_EQ(1, plugin().var_tracker().GetRefCountForObject(instance_obj)); + // A reference is passed to the browser, which we consume here. + host().var_tracker().ReleaseVar(host_pp_var); + EXPECT_EQ(1, host().var_tracker().GetRefCountForObject(host_pp_var)); + + // The plugin is going away; generally, so will all references to its instance + // object. + host().var_tracker().ReleaseVar(host_pp_var); + // Destroy the instance. DidDestroy above decrements the reference count for + // instance_obj, so it should also be destroyed. + ppp_instance->DidDestroy(kInstance); + EXPECT_EQ(-1, plugin().var_tracker().GetRefCountForObject(instance_obj)); + EXPECT_EQ(-1, host().var_tracker().GetRefCountForObject(host_pp_var)); +} + +} // namespace proxy +} // namespace ppapi + diff --git a/chromium/ppapi/proxy/ppp_instance_proxy.cc b/chromium/ppapi/proxy/ppp_instance_proxy.cc new file mode 100644 index 00000000000..a7a0699508b --- /dev/null +++ b/chromium/ppapi/proxy/ppp_instance_proxy.cc @@ -0,0 +1,256 @@ +// 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 "ppapi/proxy/ppp_instance_proxy.h" + +#include <algorithm> + +#include "base/bind.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_fullscreen.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_proxy_delegate.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/url_loader_resource.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/ppb_view_shared.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_flash_fullscreen_api.h" +#include "ppapi/thunk/ppb_view_api.h" + +namespace ppapi { +namespace proxy { + +using thunk::EnterInstanceAPINoLock; +using thunk::EnterInstanceNoLock; +using thunk::EnterResourceNoLock; +using thunk::PPB_Flash_Fullscreen_API; +using thunk::PPB_Instance_API; +using thunk::PPB_View_API; + +namespace { + +#if !defined(OS_NACL) +PP_Bool DidCreate(PP_Instance instance, + uint32_t argc, + const char* argn[], + const char* argv[]) { + std::vector<std::string> argn_vect; + std::vector<std::string> argv_vect; + for (uint32_t i = 0; i < argc; i++) { + argn_vect.push_back(std::string(argn[i])); + argv_vect.push_back(std::string(argv[i])); + } + + PP_Bool result = PP_FALSE; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPInstance_DidCreate(API_ID_PPP_INSTANCE, instance, + argn_vect, argv_vect, &result)); + return result; +} + +void DidDestroy(PP_Instance instance) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPInstance_DidDestroy(API_ID_PPP_INSTANCE, instance)); +} + +void DidChangeView(PP_Instance instance, PP_Resource view_resource) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + + EnterResourceNoLock<PPB_View_API> enter_view(view_resource, false); + if (enter_view.failed()) { + NOTREACHED(); + return; + } + + PP_Bool flash_fullscreen = PP_FALSE; + EnterInstanceNoLock enter_instance(instance); + if (!enter_instance.failed()) + flash_fullscreen = enter_instance.functions()->FlashIsFullscreen(instance); + dispatcher->Send(new PpapiMsg_PPPInstance_DidChangeView( + API_ID_PPP_INSTANCE, instance, enter_view.object()->GetData(), + flash_fullscreen)); +} + +void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPInstance_DidChangeFocus(API_ID_PPP_INSTANCE, + instance, has_focus)); +} + +PP_Bool HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) { + // This should never get called. Out-of-process document loads are handled + // specially. + NOTREACHED(); + return PP_FALSE; +} + +static const PPP_Instance_1_1 instance_interface = { + &DidCreate, + &DidDestroy, + &DidChangeView, + &DidChangeFocus, + &HandleDocumentLoad +}; +#endif // !defined(OS_NACL) + +} // namespace + +PPP_Instance_Proxy::PPP_Instance_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { + if (dispatcher->IsPlugin()) { + // The PPP_Instance proxy works by always proxying the 1.1 version of the + // interface, and then detecting in the plugin process which one to use. + // PPP_Instance_Combined handles dispatching to whatever interface is + // supported. + // + // This means that if the plugin supports either 1.0 or 1.1 version of + // the interface, we want to say it supports the 1.1 version since we'll + // convert it here. This magic conversion code is hardcoded into + // PluginDispatcher::OnMsgSupportsInterface. + combined_interface_.reset(PPP_Instance_Combined::Create( + base::Bind(dispatcher->local_get_interface()))); + } +} + +PPP_Instance_Proxy::~PPP_Instance_Proxy() { +} + +#if !defined(OS_NACL) +// static +const PPP_Instance* PPP_Instance_Proxy::GetInstanceInterface() { + return &instance_interface; +} +#endif // !defined(OS_NACL) + +bool PPP_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate, + OnPluginMsgDidCreate) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidDestroy, + OnPluginMsgDidDestroy) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeView, + OnPluginMsgDidChangeView) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeFocus, + OnPluginMsgDidChangeFocus) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_HandleDocumentLoad, + OnPluginMsgHandleDocumentLoad) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Instance_Proxy::OnPluginMsgDidCreate( + PP_Instance instance, + const std::vector<std::string>& argn, + const std::vector<std::string>& argv, + PP_Bool* result) { + *result = PP_FALSE; + if (argn.size() != argv.size()) + return; + + // Set up the routing associating this new instance with the dispatcher we + // just got the message from. This must be done before calling into the + // plugin so it can in turn call PPAPI functions. + PluginDispatcher* plugin_dispatcher = + static_cast<PluginDispatcher*>(dispatcher()); + plugin_dispatcher->DidCreateInstance(instance); + PpapiGlobals::Get()->GetResourceTracker()->DidCreateInstance(instance); + + // Make sure the arrays always have at least one element so we can take the + // address below. + std::vector<const char*> argn_array( + std::max(static_cast<size_t>(1), argn.size())); + std::vector<const char*> argv_array( + std::max(static_cast<size_t>(1), argn.size())); + for (size_t i = 0; i < argn.size(); i++) { + argn_array[i] = argn[i].c_str(); + argv_array[i] = argv[i].c_str(); + } + + DCHECK(combined_interface_.get()); + *result = combined_interface_->DidCreate(instance, + static_cast<uint32_t>(argn.size()), + &argn_array[0], &argv_array[0]); +} + +void PPP_Instance_Proxy::OnPluginMsgDidDestroy(PP_Instance instance) { + combined_interface_->DidDestroy(instance); + + PpapiGlobals* globals = PpapiGlobals::Get(); + globals->GetResourceTracker()->DidDeleteInstance(instance); + globals->GetVarTracker()->DidDeleteInstance(instance); + + static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance); +} + +void PPP_Instance_Proxy::OnPluginMsgDidChangeView( + PP_Instance instance, + const ViewData& new_data, + PP_Bool flash_fullscreen) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + InstanceData* data = dispatcher->GetInstanceData(instance); + if (!data) + return; + data->view = new_data; + +#if !defined(OS_NACL) + EnterInstanceAPINoLock<PPB_Flash_Fullscreen_API> enter(instance); + if (!enter.failed()) + enter.functions()->SetLocalIsFullscreen(instance, flash_fullscreen); +#endif // !defined(OS_NACL) + + ScopedPPResource resource( + ScopedPPResource::PassRef(), + (new PPB_View_Shared(OBJECT_IS_PROXY, + instance, new_data))->GetReference()); + + combined_interface_->DidChangeView(instance, resource, + &new_data.rect, + &new_data.clip_rect); +} + +void PPP_Instance_Proxy::OnPluginMsgDidChangeFocus(PP_Instance instance, + PP_Bool has_focus) { + combined_interface_->DidChangeFocus(instance, has_focus); +} + +void PPP_Instance_Proxy::OnPluginMsgHandleDocumentLoad( + PP_Instance instance, + int pending_loader_host_id, + const URLResponseInfoData& data) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + Connection connection(PluginGlobals::Get()->GetBrowserSender(), + dispatcher); + + scoped_refptr<URLLoaderResource> loader_resource( + new URLLoaderResource(connection, instance, + pending_loader_host_id, data)); + + PP_Resource loader_pp_resource = loader_resource->GetReference(); + if (!combined_interface_->HandleDocumentLoad(instance, loader_pp_resource)) + loader_resource->Close(); + // We don't pass a ref into the plugin, if it wants one, it will have taken + // an additional one. + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource( + loader_pp_resource); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_instance_proxy.h b/chromium/ppapi/proxy/ppp_instance_proxy.h new file mode 100644 index 00000000000..85ae55cbddb --- /dev/null +++ b/chromium/ppapi/proxy/ppp_instance_proxy.h @@ -0,0 +1,63 @@ +// 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 PPAPI_PROXY_PPP_INSTANCE_PROXY_H_ +#define PPAPI_PROXY_PPP_INSTANCE_PROXY_H_ + +#include <string> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/ppp_instance_combined.h" + +struct PP_Rect; + +namespace ppapi { + +struct URLResponseInfoData; +struct ViewData; + +namespace proxy { + +class PPP_Instance_Proxy : public InterfaceProxy { + public: + explicit PPP_Instance_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Instance_Proxy(); + + static const PPP_Instance* GetInstanceInterface(); + + PPP_Instance_Combined* ppp_instance_target() const { + return combined_interface_.get(); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnPluginMsgDidCreate(PP_Instance instance, + const std::vector<std::string>& argn, + const std::vector<std::string>& argv, + PP_Bool* result); + void OnPluginMsgDidDestroy(PP_Instance instance); + void OnPluginMsgDidChangeView(PP_Instance instance, + const ViewData& new_data, + PP_Bool flash_fullscreen); + void OnPluginMsgDidChangeFocus(PP_Instance instance, PP_Bool has_focus); + void OnPluginMsgHandleDocumentLoad(PP_Instance instance, + int pending_loader_host_id, + const URLResponseInfoData& data); + + scoped_ptr<PPP_Instance_Combined> combined_interface_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_INSTANCE_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_instance_proxy_unittest.cc b/chromium/ppapi/proxy/ppp_instance_proxy_unittest.cc new file mode 100644 index 00000000000..e2df26e250f --- /dev/null +++ b/chromium/ppapi/proxy/ppp_instance_proxy_unittest.cc @@ -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. + +#include "base/synchronization/waitable_event.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_fullscreen.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/c/private/ppb_flash_fullscreen.h" +#include "ppapi/proxy/locking_resource_releaser.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/ppb_view_shared.h" + +namespace ppapi { +namespace proxy { + +namespace { +// This is a poor man's mock of PPP_Instance using global variables. Eventually +// we should generalize making PPAPI interface mocks by using IDL or macro/ +// template magic. +PP_Instance received_instance; +uint32_t received_argc; +std::vector<std::string> received_argn; +std::vector<std::string> received_argv; +PP_Bool bool_to_return; +PP_Bool DidCreate(PP_Instance instance, uint32_t argc, const char* argn[], + const char* argv[]) { + received_instance = instance; + received_argc = argc; + received_argn.clear(); + received_argn.insert(received_argn.begin(), argn, argn + argc); + received_argv.clear(); + received_argv.insert(received_argv.begin(), argv, argv + argc); + return bool_to_return; +} + +void DidDestroy(PP_Instance instance) { + received_instance = instance; +} + +PP_Rect received_position; +PP_Rect received_clip; +// DidChangeView is asynchronous. We wait until the call has completed before +// proceeding on to the next test. +base::WaitableEvent did_change_view_called(false, false); +void DidChangeView(PP_Instance instance, const PP_Rect* position, + const PP_Rect* clip) { + received_instance = instance; + received_position = *position; + received_clip = *clip; + did_change_view_called.Signal(); +} + +PP_Bool received_has_focus; +base::WaitableEvent did_change_focus_called(false, false); +void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { + received_instance = instance; + received_has_focus = has_focus; + did_change_focus_called.Signal(); +} + +PP_Bool HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) { + // This one requires use of the PPB_URLLoader proxy and PPB_Core, plus a + // resource tracker for the url_loader resource. + // TODO(dmichael): Mock those out and test this function. + NOTREACHED(); + return PP_FALSE; +} + +// Clear all the 'received' values for our mock. Call this before you expect +// one of the functions to be invoked. TODO(dmichael): It would be better to +// have a flag also for each function, so we know the right one got called. +void ResetReceived() { + received_instance = 0; + received_argc = 0; + received_argn.clear(); + received_argv.clear(); + memset(&received_position, 0, sizeof(received_position)); + memset(&received_clip, 0, sizeof(received_clip)); + received_has_focus = PP_FALSE; +} + +PPP_Instance_1_0 ppp_instance_1_0 = { + &DidCreate, + &DidDestroy, + &DidChangeView, + &DidChangeFocus, + &HandleDocumentLoad +}; + +// PPP_Instance_Proxy::DidChangeView relies on PPB_(Flash)Fullscreen being +// available with a valid implementation of IsFullScreen, so we mock it. +PP_Bool IsFullscreen(PP_Instance instance) { + return PP_FALSE; +} +PPB_Fullscreen ppb_fullscreen = { &IsFullscreen }; +PPB_FlashFullscreen ppb_flash_fullscreen = { &IsFullscreen }; + +} // namespace + +class PPP_Instance_ProxyTest : public TwoWayTest { + public: + PPP_Instance_ProxyTest() + : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { + } +}; + +TEST_F(PPP_Instance_ProxyTest, PPPInstance1_0) { + plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_1_0, &ppp_instance_1_0); + host().RegisterTestInterface(PPB_FLASHFULLSCREEN_INTERFACE, + &ppb_flash_fullscreen); + host().RegisterTestInterface(PPB_FULLSCREEN_INTERFACE, + &ppb_fullscreen); + + // Grab the host-side proxy for the interface. The browser only speaks 1.1, + // while the proxy ensures support for the 1.0 version on the plugin side. + const PPP_Instance_1_1* ppp_instance = static_cast<const PPP_Instance_1_1*>( + host().host_dispatcher()->GetProxiedInterface( + PPP_INSTANCE_INTERFACE_1_1)); + + // Call each function in turn, make sure we get the expected values and + // returns. + // + // We don't test DidDestroy, because it has the side-effect of removing the + // PP_Instance from the PluginDispatcher, which will cause a failure later + // when the test is torn down. + PP_Instance expected_instance = pp_instance(); + std::vector<std::string> expected_argn, expected_argv; + expected_argn.push_back("Hello"); + expected_argn.push_back("world."); + expected_argv.push_back("elloHay"); + expected_argv.push_back("orldway."); + std::vector<const char*> argn_to_pass, argv_to_pass; + CHECK(expected_argn.size() == expected_argv.size()); + for (size_t i = 0; i < expected_argn.size(); ++i) { + argn_to_pass.push_back(expected_argn[i].c_str()); + argv_to_pass.push_back(expected_argv[i].c_str()); + } + uint32_t expected_argc = expected_argn.size(); + bool_to_return = PP_TRUE; + ResetReceived(); + // Tell the host resource tracker about the instance. + host().resource_tracker().DidCreateInstance(expected_instance); + EXPECT_EQ(bool_to_return, ppp_instance->DidCreate(expected_instance, + expected_argc, + &argn_to_pass[0], + &argv_to_pass[0])); + EXPECT_EQ(received_instance, expected_instance); + EXPECT_EQ(received_argc, expected_argc); + EXPECT_EQ(received_argn, expected_argn); + EXPECT_EQ(received_argv, expected_argv); + + PP_Rect expected_position = { {1, 2}, {3, 4} }; + PP_Rect expected_clip = { {5, 6}, {7, 8} }; + ViewData data; + data.rect = expected_position; + data.is_fullscreen = false; + data.is_page_visible = true; + data.clip_rect = expected_clip; + data.device_scale = 1.0f; + ResetReceived(); + LockingResourceReleaser view_resource( + (new PPB_View_Shared(OBJECT_IS_IMPL, + expected_instance, data))->GetReference()); + ppp_instance->DidChangeView(expected_instance, view_resource.get()); + did_change_view_called.Wait(); + EXPECT_EQ(received_instance, expected_instance); + EXPECT_EQ(received_position.point.x, expected_position.point.x); + EXPECT_EQ(received_position.point.y, expected_position.point.y); + EXPECT_EQ(received_position.size.width, expected_position.size.width); + EXPECT_EQ(received_position.size.height, expected_position.size.height); + EXPECT_EQ(received_clip.point.x, expected_clip.point.x); + EXPECT_EQ(received_clip.point.y, expected_clip.point.y); + EXPECT_EQ(received_clip.size.width, expected_clip.size.width); + EXPECT_EQ(received_clip.size.height, expected_clip.size.height); + + PP_Bool expected_has_focus = PP_TRUE; + ResetReceived(); + ppp_instance->DidChangeFocus(expected_instance, expected_has_focus); + did_change_focus_called.Wait(); + EXPECT_EQ(received_instance, expected_instance); + EXPECT_EQ(received_has_focus, expected_has_focus); + + // TODO(dmichael): Need to mock out a resource Tracker to be able to test + // HandleResourceLoad. It also requires + // PPB_Core.AddRefResource and for PPB_URLLoader to be + // registered. + + host().resource_tracker().DidDeleteInstance(expected_instance); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_messaging_proxy.cc b/chromium/ppapi/proxy/ppp_messaging_proxy.cc new file mode 100644 index 00000000000..5a12419f78a --- /dev/null +++ b/chromium/ppapi/proxy/ppp_messaging_proxy.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 "ppapi/proxy/ppp_messaging_proxy.h" + +#include <algorithm> + +#include "ppapi/c/ppp_messaging.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { +namespace proxy { + +namespace { + +#if !defined(OS_NACL) +void HandleMessage(PP_Instance instance, PP_Var message_data) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher || (message_data.type == PP_VARTYPE_OBJECT)) { + // The dispatcher should always be valid, and the browser should never send + // an 'object' var over PPP_Messaging. + NOTREACHED(); + return; + } + + dispatcher->Send(new PpapiMsg_PPPMessaging_HandleMessage( + API_ID_PPP_MESSAGING, + instance, + SerializedVarSendInputShmem(dispatcher, message_data, instance))); +} + +static const PPP_Messaging messaging_interface = { + &HandleMessage +}; +#else +// The NaCl plugin doesn't need the host side interface - stub it out. +static const PPP_Messaging messaging_interface = {}; +#endif // !defined(OS_NACL) + +InterfaceProxy* CreateMessagingProxy(Dispatcher* dispatcher) { + return new PPP_Messaging_Proxy(dispatcher); +} + +} // namespace + +PPP_Messaging_Proxy::PPP_Messaging_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_messaging_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_messaging_impl_ = static_cast<const PPP_Messaging*>( + dispatcher->local_get_interface()(PPP_MESSAGING_INTERFACE)); + } +} + +PPP_Messaging_Proxy::~PPP_Messaging_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_Messaging_Proxy::GetInfo() { + static const Info info = { + &messaging_interface, + PPP_MESSAGING_INTERFACE, + API_ID_PPP_MESSAGING, + false, + &CreateMessagingProxy, + }; + return &info; +} + +bool PPP_Messaging_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Messaging_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPMessaging_HandleMessage, + OnMsgHandleMessage) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Messaging_Proxy::OnMsgHandleMessage( + PP_Instance instance, SerializedVarReceiveInput message_data) { + PP_Var received_var(message_data.GetForInstance(dispatcher(), instance)); + // SerializedVarReceiveInput will decrement the reference count, but we want + // to give the recipient a reference. + PpapiGlobals::Get()->GetVarTracker()->AddRefVar(received_var); + CallWhileUnlocked(ppp_messaging_impl_->HandleMessage, + instance, + received_var); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_messaging_proxy.h b/chromium/ppapi/proxy/ppp_messaging_proxy.h new file mode 100644 index 00000000000..4b66f92c4f7 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_messaging_proxy.h @@ -0,0 +1,44 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPP_MESSAGING_PROXY_H_ +#define PPAPI_PROXY_PPP_MESSAGING_PROXY_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/ppp_messaging.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace ppapi { +namespace proxy { + +class SerializedVarReceiveInput; + +class PPP_Messaging_Proxy : public InterfaceProxy { + public: + PPP_Messaging_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Messaging_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + // Message handlers. + void OnMsgHandleMessage(PP_Instance instance, + SerializedVarReceiveInput data); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_Messaging* ppp_messaging_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_Messaging_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_MESSAGING_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_messaging_proxy_perftest.cc b/chromium/ppapi/proxy/ppp_messaging_proxy_perftest.cc new file mode 100644 index 00000000000..c52ea116687 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_messaging_proxy_perftest.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 "base/command_line.h" +#include "base/perftimer.h" +#include "base/strings/string_number_conversions.h" +#include "ppapi/c/ppp_messaging.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { +namespace proxy { +namespace { + +base::WaitableEvent handle_message_called(false, false); + +void HandleMessage(PP_Instance /* instance */, PP_Var message_data) { + StringVar* string_var = StringVar::FromPPVar(message_data); + DCHECK(string_var); + // Retrieve the string to make sure the proxy can't "optimize away" sending + // the actual contents of the string (e.g., by doing a lazy retrieve or + // something). Note that this test is for performance only, and assumes + // other tests check for correctness. + std::string s = string_var->value(); + // Do something simple with the string so the compiler won't complain. + if (s.length() > 0) + s[0] = 'a'; + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(message_data); + handle_message_called.Signal(); +} + +PPP_Messaging ppp_messaging_mock = { + &HandleMessage +}; + +class PppMessagingPerfTest : public TwoWayTest { + public: + PppMessagingPerfTest() : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { + plugin().RegisterTestInterface(PPP_MESSAGING_INTERFACE, + &ppp_messaging_mock); + } +}; + +} // namespace + +// Tests the performance of sending strings through the proxy. +TEST_F(PppMessagingPerfTest, StringPerformance) { + // Grab the host-side proxy of ppp_messaging. + const PPP_Messaging* ppp_messaging = static_cast<const PPP_Messaging*>( + host().host_dispatcher()->GetProxiedInterface( + PPP_MESSAGING_INTERFACE)); + const PP_Instance kTestInstance = pp_instance(); + int seed = 123; + int string_count = 1000; + int max_string_size = 1000000; + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line) { + if (command_line->HasSwitch("seed")) { + base::StringToInt(command_line->GetSwitchValueASCII("seed"), + &seed); + } + if (command_line->HasSwitch("string_count")) { + base::StringToInt(command_line->GetSwitchValueASCII("string_count"), + &string_count); + } + if (command_line->HasSwitch("max_string_size")) { + base::StringToInt(command_line->GetSwitchValueASCII("max_string_size"), + &max_string_size); + } + } + srand(seed); + PerfTimeLogger logger("PppMessagingPerfTest.StringPerformance"); + for (int i = 0; i < string_count; ++i) { + const std::string test_string(rand() % max_string_size, 'a'); + PP_Var host_string = StringVar::StringToPPVar(test_string); + ppp_messaging->HandleMessage(kTestInstance, host_string); + handle_message_called.Wait(); + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(host_string); + } +} + +} // namespace proxy +} // namespace ppapi + diff --git a/chromium/ppapi/proxy/ppp_messaging_proxy_unittest.cc b/chromium/ppapi/proxy/ppp_messaging_proxy_unittest.cc new file mode 100644 index 00000000000..1fe0ef71806 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_messaging_proxy_unittest.cc @@ -0,0 +1,136 @@ +// 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 <cstring> + +#include "base/synchronization/waitable_event.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/ppp_messaging.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// This is a poor man's mock of PPP_Messaging using global variables. Eventually +// we should generalize making PPAPI interface mocks by using IDL or macro/ +// template magic. +PP_Instance received_instance; +PP_Var received_var; +base::WaitableEvent handle_message_called(false, false); + +void HandleMessage(PP_Instance instance, PP_Var message_data) { + received_instance = instance; + received_var = message_data; + handle_message_called.Signal(); +} + +// Clear all the 'received' values for our mock. Call this before you expect +// one of the functions to be invoked. +void ResetReceived() { + received_instance = 0; + received_var.type = PP_VARTYPE_UNDEFINED; + received_var.value.as_id = 0; +} + +PPP_Messaging ppp_messaging_mock = { + &HandleMessage +}; + +class PPP_Messaging_ProxyTest : public TwoWayTest { + public: + PPP_Messaging_ProxyTest() + : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { + plugin().RegisterTestInterface(PPP_MESSAGING_INTERFACE, + &ppp_messaging_mock); + } +}; + +void CompareAndReleaseStringVar(PluginProxyTestHarness* plugin_harness, + PP_Var received_var, + const std::string& test_string) { + ProxyAutoLock lock; + Var* received_string = plugin_harness->var_tracker().GetVar(received_var); + ASSERT_TRUE(received_string); + ASSERT_TRUE(received_string->AsStringVar()); + EXPECT_EQ(test_string, received_string->AsStringVar()->value()); + // Now release the var, and the string should go away (because the ref + // count should be one). + plugin_harness->var_tracker().ReleaseVar(received_var); + EXPECT_FALSE(StringVar::FromPPVar(received_var)); +} + +} // namespace + +TEST_F(PPP_Messaging_ProxyTest, SendMessages) { + // Grab the host-side proxy of ppp_messaging. + const PPP_Messaging* ppp_messaging = static_cast<const PPP_Messaging*>( + host().host_dispatcher()->GetProxiedInterface( + PPP_MESSAGING_INTERFACE)); + + PP_Instance expected_instance = pp_instance(); + PP_Var expected_var = PP_MakeUndefined(); + ResetReceived(); + ppp_messaging->HandleMessage(expected_instance, expected_var); + handle_message_called.Wait(); + EXPECT_EQ(expected_instance, received_instance); + EXPECT_EQ(expected_var.type, received_var.type); + + expected_var = PP_MakeNull(); + ResetReceived(); + ppp_messaging->HandleMessage(expected_instance, expected_var); + handle_message_called.Wait(); + EXPECT_EQ(expected_instance, received_instance); + EXPECT_EQ(expected_var.type, received_var.type); + + expected_var = PP_MakeBool(PP_TRUE); + ResetReceived(); + ppp_messaging->HandleMessage(expected_instance, expected_var); + handle_message_called.Wait(); + EXPECT_EQ(expected_instance, received_instance); + EXPECT_EQ(expected_var.type, received_var.type); + EXPECT_EQ(expected_var.value.as_bool, received_var.value.as_bool); + + expected_var = PP_MakeInt32(12345); + ResetReceived(); + ppp_messaging->HandleMessage(expected_instance, expected_var); + handle_message_called.Wait(); + EXPECT_EQ(expected_instance, received_instance); + EXPECT_EQ(expected_var.type, received_var.type); + EXPECT_EQ(expected_var.value.as_int, received_var.value.as_int); + + expected_var = PP_MakeDouble(3.1415); + ResetReceived(); + ppp_messaging->HandleMessage(expected_instance, expected_var); + handle_message_called.Wait(); + EXPECT_EQ(expected_instance, received_instance); + EXPECT_EQ(expected_var.type, received_var.type); + EXPECT_EQ(expected_var.value.as_double, received_var.value.as_double); + + const std::string kTestString("Hello world!"); + expected_var = StringVar::StringToPPVar(kTestString); + ResetReceived(); + ppp_messaging->HandleMessage(expected_instance, expected_var); + // Now release the var, and the string should go away (because the ref + // count should be one). + host().var_tracker().ReleaseVar(expected_var); + EXPECT_FALSE(StringVar::FromPPVar(expected_var)); + + handle_message_called.Wait(); + EXPECT_EQ(expected_instance, received_instance); + EXPECT_EQ(expected_var.type, received_var.type); + PostTaskOnRemoteHarness( + base::Bind(CompareAndReleaseStringVar, + &plugin(), + received_var, + kTestString)); +} + +} // namespace proxy +} // namespace ppapi + diff --git a/chromium/ppapi/proxy/ppp_mouse_lock_proxy.cc b/chromium/ppapi/proxy/ppp_mouse_lock_proxy.cc new file mode 100644 index 00000000000..6fd746dc01f --- /dev/null +++ b/chromium/ppapi/proxy/ppp_mouse_lock_proxy.cc @@ -0,0 +1,87 @@ +// 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 "ppapi/proxy/ppp_mouse_lock_proxy.h" + +#include "ppapi/c/ppp_mouse_lock.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +#if !defined(OS_NACL) +void MouseLockLost(PP_Instance instance) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + // The dispatcher should always be valid. + NOTREACHED(); + return; + } + + dispatcher->Send(new PpapiMsg_PPPMouseLock_MouseLockLost( + API_ID_PPP_MOUSE_LOCK, instance)); +} + +static const PPP_MouseLock mouse_lock_interface = { + &MouseLockLost +}; +#else +// The NaCl plugin doesn't need the host side interface - stub it out. +static const PPP_MouseLock mouse_lock_interface = {}; +#endif // !defined(OS_NACL) + +InterfaceProxy* CreateMouseLockProxy(Dispatcher* dispatcher) { + return new PPP_MouseLock_Proxy(dispatcher); +} + +} // namespace + +PPP_MouseLock_Proxy::PPP_MouseLock_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_mouse_lock_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_mouse_lock_impl_ = static_cast<const PPP_MouseLock*>( + dispatcher->local_get_interface()(PPP_MOUSELOCK_INTERFACE)); + } +} + +PPP_MouseLock_Proxy::~PPP_MouseLock_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_MouseLock_Proxy::GetInfo() { + static const Info info = { + &mouse_lock_interface, + PPP_MOUSELOCK_INTERFACE, + API_ID_PPP_MOUSE_LOCK, + false, + &CreateMouseLockProxy, + }; + return &info; +} + +bool PPP_MouseLock_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_MouseLock_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPMouseLock_MouseLockLost, + OnMsgMouseLockLost) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_MouseLock_Proxy::OnMsgMouseLockLost(PP_Instance instance) { + if (ppp_mouse_lock_impl_) + CallWhileUnlocked(ppp_mouse_lock_impl_->MouseLockLost, instance); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_mouse_lock_proxy.h b/chromium/ppapi/proxy/ppp_mouse_lock_proxy.h new file mode 100644 index 00000000000..64f1b7a05d7 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_mouse_lock_proxy.h @@ -0,0 +1,41 @@ +// 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_PROXY_PPP_MOUSE_LOCK_PROXY_H_ +#define PPAPI_PROXY_PPP_MOUSE_LOCK_PROXY_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/ppp_mouse_lock.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace ppapi { +namespace proxy { + +class PPP_MouseLock_Proxy : public InterfaceProxy { + public: + PPP_MouseLock_Proxy(Dispatcher* dispatcher); + virtual ~PPP_MouseLock_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + // Message handlers. + void OnMsgMouseLockLost(PP_Instance instance); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_MouseLock* ppp_mouse_lock_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_MouseLock_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_MOUSE_LOCK_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_printing_proxy.cc b/chromium/ppapi/proxy/ppp_printing_proxy.cc new file mode 100644 index 00000000000..9d58c780111 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_printing_proxy.cc @@ -0,0 +1,214 @@ +// 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 "ppapi/proxy/ppp_printing_proxy.h" + +#include <string.h> + +#include "ppapi/c/dev/ppp_printing_dev.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource_tracker.h" + +namespace ppapi { +namespace proxy { + +namespace { + +#if !defined(OS_NACL) +bool HasPrintingPermission(PP_Instance instance) { + Dispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) + return false; + return dispatcher->permissions().HasPermission(PERMISSION_DEV); +} + +uint32_t QuerySupportedFormats(PP_Instance instance) { + if (!HasPrintingPermission(instance)) + return 0; + uint32_t result = 0; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPrinting_QuerySupportedFormats(API_ID_PPP_PRINTING, + instance, &result)); + return result; +} + +int32_t Begin(PP_Instance instance, + const struct PP_PrintSettings_Dev* print_settings) { + if (!HasPrintingPermission(instance)) + return 0; + // Settings is just serialized as a string. + std::string settings_string; + settings_string.resize(sizeof(*print_settings)); + memcpy(&settings_string[0], print_settings, sizeof(*print_settings)); + + int32_t result = 0; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPrinting_Begin(API_ID_PPP_PRINTING, instance, + settings_string, &result)); + return result; +} + +PP_Resource PrintPages(PP_Instance instance, + const PP_PrintPageNumberRange_Dev* page_ranges, + uint32_t page_range_count) { + if (!HasPrintingPermission(instance)) + return 0; + std::vector<PP_PrintPageNumberRange_Dev> pages( + page_ranges, page_ranges + page_range_count); + + HostResource result; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPrinting_PrintPages(API_ID_PPP_PRINTING, + instance, pages, &result)); + + // How refcounting works when returning a resource: + // + // The plugin in the plugin process makes a resource that it returns to the + // browser. The plugin proxy code returns that ref to us and asynchronously + // releases it. Before any release message associated with that operation + // comes, we'll get this reply. We need to add one ref since our caller + // expects us to add one ref for it to consume. + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource( + result.host_resource()); + return result.host_resource(); +} + +void End(PP_Instance instance) { + if (!HasPrintingPermission(instance)) + return; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPrinting_End(API_ID_PPP_PRINTING, instance)); +} + +PP_Bool IsScalingDisabled(PP_Instance instance) { + if (!HasPrintingPermission(instance)) + return PP_FALSE; + bool result = false; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPPrinting_IsScalingDisabled(API_ID_PPP_PRINTING, + instance, &result)); + return PP_FromBool(result); +} + +const PPP_Printing_Dev ppp_printing_interface = { + &QuerySupportedFormats, + &Begin, + &PrintPages, + &End, + &IsScalingDisabled +}; +#else +// The NaCl plugin doesn't need the host side interface - stub it out. +static const PPP_Printing_Dev ppp_printing_interface = {}; +#endif // !defined(OS_NACL) + +} // namespace + +PPP_Printing_Proxy::PPP_Printing_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_printing_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_printing_impl_ = static_cast<const PPP_Printing_Dev*>( + dispatcher->local_get_interface()(PPP_PRINTING_DEV_INTERFACE)); + } +} + +PPP_Printing_Proxy::~PPP_Printing_Proxy() { +} + +// static +const PPP_Printing_Dev* PPP_Printing_Proxy::GetProxyInterface() { + return &ppp_printing_interface; +} + +bool PPP_Printing_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Printing_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_QuerySupportedFormats, + OnPluginMsgQuerySupportedFormats) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_Begin, + OnPluginMsgBegin) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_PrintPages, + OnPluginMsgPrintPages) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_End, + OnPluginMsgEnd) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_IsScalingDisabled, + OnPluginMsgIsScalingDisabled) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Printing_Proxy::OnPluginMsgQuerySupportedFormats(PP_Instance instance, + uint32_t* result) { + if (ppp_printing_impl_) { + *result = CallWhileUnlocked(ppp_printing_impl_->QuerySupportedFormats, + instance); + } else { + *result = 0; + } +} + +void PPP_Printing_Proxy::OnPluginMsgBegin(PP_Instance instance, + const std::string& settings_string, + int32_t* result) { + *result = 0; + + PP_PrintSettings_Dev settings; + if (settings_string.size() != sizeof(settings)) + return; + memcpy(&settings, &settings_string[0], sizeof(settings)); + + if (ppp_printing_impl_) { + *result = CallWhileUnlocked(ppp_printing_impl_->Begin, + instance, + const_cast<const PP_PrintSettings_Dev*>(&settings)); + } +} + +void PPP_Printing_Proxy::OnPluginMsgPrintPages( + PP_Instance instance, + const std::vector<PP_PrintPageNumberRange_Dev>& pages, + HostResource* result) { + if (!ppp_printing_impl_ || pages.empty()) + return; + + PP_Resource plugin_resource = CallWhileUnlocked( + ppp_printing_impl_->PrintPages, + instance, &pages[0], static_cast<uint32_t>(pages.size())); + ResourceTracker* resource_tracker = PpapiGlobals::Get()->GetResourceTracker(); + Resource* resource_object = resource_tracker->GetResource(plugin_resource); + if (!resource_object) + return; + + *result = resource_object->host_resource(); + + // See PrintPages above for how refcounting works. + resource_tracker->ReleaseResourceSoon(plugin_resource); +} + +void PPP_Printing_Proxy::OnPluginMsgEnd(PP_Instance instance) { + if (ppp_printing_impl_) + CallWhileUnlocked(ppp_printing_impl_->End, instance); +} + +void PPP_Printing_Proxy::OnPluginMsgIsScalingDisabled(PP_Instance instance, + bool* result) { + if (ppp_printing_impl_) { + *result = PP_ToBool(CallWhileUnlocked(ppp_printing_impl_->IsScalingDisabled, + instance)); + } else { + *result = false; + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_printing_proxy.h b/chromium/ppapi/proxy/ppp_printing_proxy.h new file mode 100644 index 00000000000..03bebf7b6aa --- /dev/null +++ b/chromium/ppapi/proxy/ppp_printing_proxy.h @@ -0,0 +1,57 @@ +// 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_PROXY_PPP_PRINTING_PROXY_H_ +#define PPAPI_PROXY_PPP_PRINTING_PROXY_H_ + +#include <string> +#include <vector> + +#include "ppapi/c/dev/ppp_printing_dev.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PP_PrintPageNumberRange_Dev; + +namespace ppapi { + +class HostResource; + +namespace proxy { + +class PPP_Printing_Proxy : public InterfaceProxy { + public: + PPP_Printing_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Printing_Proxy(); + + static const PPP_Printing_Dev* GetProxyInterface(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnPluginMsgQuerySupportedFormats(PP_Instance instance, uint32_t* result); + void OnPluginMsgBegin(PP_Instance instance, + const std::string& settings_string, + int32_t* result); + void OnPluginMsgPrintPages( + PP_Instance instance, + const std::vector<PP_PrintPageNumberRange_Dev>& pages, + HostResource* result); + void OnPluginMsgEnd(PP_Instance instance); + void OnPluginMsgIsScalingDisabled(PP_Instance instance, bool* result); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_Printing_Dev* ppp_printing_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_Printing_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_PRINTING_PROXY_H_ + diff --git a/chromium/ppapi/proxy/ppp_text_input_proxy.cc b/chromium/ppapi/proxy/ppp_text_input_proxy.cc new file mode 100644 index 00000000000..061b73cd4fd --- /dev/null +++ b/chromium/ppapi/proxy/ppp_text_input_proxy.cc @@ -0,0 +1,81 @@ +// 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 "ppapi/proxy/ppp_text_input_proxy.h" + +#include "ppapi/c/dev/ppp_text_input_dev.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +#if !defined(OS_NACL) +void RequestSurroundingText(PP_Instance instance, + uint32_t desired_number_of_characters) { + proxy::HostDispatcher* dispatcher = + proxy::HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + // The dispatcher should always be valid. + NOTREACHED(); + return; + } + + dispatcher->Send(new PpapiMsg_PPPTextInput_RequestSurroundingText( + API_ID_PPP_TEXT_INPUT, instance, desired_number_of_characters)); +} + +const PPP_TextInput_Dev g_ppp_text_input_thunk = { + &RequestSurroundingText +}; +#else +// The NaCl plugin doesn't need the host side interface - stub it out. +static const PPP_TextInput_Dev g_ppp_text_input_thunk = {}; +#endif // !defined(OS_NACL) + +} // namespace + +// static +const PPP_TextInput_Dev* PPP_TextInput_Proxy::GetProxyInterface() { + return &g_ppp_text_input_thunk; +} + +PPP_TextInput_Proxy::PPP_TextInput_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_text_input_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_text_input_impl_ = static_cast<const PPP_TextInput_Dev*>( + dispatcher->local_get_interface()(PPP_TEXTINPUT_DEV_INTERFACE)); + } +} + +PPP_TextInput_Proxy::~PPP_TextInput_Proxy() { +} + +bool PPP_TextInput_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_TextInput_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPTextInput_RequestSurroundingText, + OnMsgRequestSurroundingText) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_TextInput_Proxy::OnMsgRequestSurroundingText( + PP_Instance instance, uint32_t desired_number_of_characters) { + if (ppp_text_input_impl_) { + CallWhileUnlocked(ppp_text_input_impl_->RequestSurroundingText, + instance, desired_number_of_characters); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_text_input_proxy.h b/chromium/ppapi/proxy/ppp_text_input_proxy.h new file mode 100644 index 00000000000..7ac0cacffab --- /dev/null +++ b/chromium/ppapi/proxy/ppp_text_input_proxy.h @@ -0,0 +1,42 @@ +// 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_PROXY_PPP_TEXT_INPUT_PROXY_H_ +#define PPAPI_PROXY_PPP_TEXT_INPUT_PROXY_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/dev/ppp_text_input_dev.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace ppapi { +namespace proxy { + +class PPP_TextInput_Proxy : public InterfaceProxy { + public: + PPP_TextInput_Proxy(Dispatcher* dispatcher); + virtual ~PPP_TextInput_Proxy(); + + static const PPP_TextInput_Dev* GetProxyInterface(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + // Message handlers. + void OnMsgRequestSurroundingText(PP_Instance instance, + uint32_t desired_number_of_characters); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_TextInput_Dev* ppp_text_input_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_TextInput_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_TEXT_INPUT_PROXY_H_ diff --git a/chromium/ppapi/proxy/ppp_video_decoder_proxy.cc b/chromium/ppapi/proxy/ppp_video_decoder_proxy.cc new file mode 100644 index 00000000000..f1a67212791 --- /dev/null +++ b/chromium/ppapi/proxy/ppp_video_decoder_proxy.cc @@ -0,0 +1,184 @@ +// 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 "ppapi/proxy/ppp_video_decoder_proxy.h" + +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_video_decoder_proxy.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_video_decoder_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::PPB_VideoDecoder_API; + +namespace ppapi { +namespace proxy { + +namespace { + +void ProvidePictureBuffers(PP_Instance instance, PP_Resource decoder, + uint32_t req_num_of_bufs, + const PP_Size* dimensions, + uint32_t texture_target) { + HostResource decoder_resource; + decoder_resource.SetHostResource(instance, decoder); + + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPVideoDecoder_ProvidePictureBuffers( + API_ID_PPP_VIDEO_DECODER_DEV, + decoder_resource, req_num_of_bufs, *dimensions, texture_target)); +} + +void DismissPictureBuffer(PP_Instance instance, PP_Resource decoder, + int32_t picture_buffer_id) { + HostResource decoder_resource; + decoder_resource.SetHostResource(instance, decoder); + + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPVideoDecoder_DismissPictureBuffer( + API_ID_PPP_VIDEO_DECODER_DEV, + decoder_resource, picture_buffer_id)); +} + +void PictureReady(PP_Instance instance, PP_Resource decoder, + const PP_Picture_Dev* picture) { + HostResource decoder_resource; + decoder_resource.SetHostResource(instance, decoder); + + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPVideoDecoder_PictureReady( + API_ID_PPP_VIDEO_DECODER_DEV, decoder_resource, *picture)); +} + +void NotifyError(PP_Instance instance, PP_Resource decoder, + PP_VideoDecodeError_Dev error) { + HostResource decoder_resource; + decoder_resource.SetHostResource(instance, decoder); + + // It's possible that the error we're being notified about is happening + // because the instance is shutting down. In this case, our instance may + // already have been removed from the HostDispatcher map. + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (dispatcher) { + dispatcher->Send( + new PpapiMsg_PPPVideoDecoder_NotifyError( + API_ID_PPP_VIDEO_DECODER_DEV, decoder_resource, error)); + } +} + +static const PPP_VideoDecoder_Dev video_decoder_interface = { + &ProvidePictureBuffers, + &DismissPictureBuffer, + &PictureReady, + &NotifyError +}; + +InterfaceProxy* CreateVideoDecoderPPPProxy(Dispatcher* dispatcher) { + return new PPP_VideoDecoder_Proxy(dispatcher); +} + +} // namespace + +PPP_VideoDecoder_Proxy::PPP_VideoDecoder_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher), + ppp_video_decoder_impl_(NULL) { + if (dispatcher->IsPlugin()) { + ppp_video_decoder_impl_ = static_cast<const PPP_VideoDecoder_Dev*>( + dispatcher->local_get_interface()(PPP_VIDEODECODER_DEV_INTERFACE)); + } +} + +PPP_VideoDecoder_Proxy::~PPP_VideoDecoder_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_VideoDecoder_Proxy::GetInfo() { + static const Info info = { + &video_decoder_interface, + PPP_VIDEODECODER_DEV_INTERFACE, + API_ID_PPP_VIDEO_DECODER_DEV, + false, + &CreateVideoDecoderPPPProxy, + }; + return &info; +} + +bool PPP_VideoDecoder_Proxy::OnMessageReceived(const IPC::Message& msg) { + if (!dispatcher()->IsPlugin()) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_VideoDecoder_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPVideoDecoder_ProvidePictureBuffers, + OnMsgProvidePictureBuffers) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPVideoDecoder_DismissPictureBuffer, + OnMsgDismissPictureBuffer) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPVideoDecoder_PictureReady, + OnMsgPictureReady) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPVideoDecoder_NotifyError, + OnMsgNotifyError) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + DCHECK(handled); + return handled; +} + +void PPP_VideoDecoder_Proxy::OnMsgProvidePictureBuffers( + const HostResource& decoder, + uint32_t req_num_of_bufs, + const PP_Size& dimensions, + uint32_t texture_target) { + PP_Resource plugin_decoder = PluginGlobals::Get()->plugin_resource_tracker()-> + PluginResourceForHostResource(decoder); + if (!plugin_decoder) + return; + CallWhileUnlocked(ppp_video_decoder_impl_->ProvidePictureBuffers, + decoder.instance(), + plugin_decoder, + req_num_of_bufs, + &dimensions, + texture_target); +} + +void PPP_VideoDecoder_Proxy::OnMsgDismissPictureBuffer( + const HostResource& decoder, int32_t picture_id) { + PP_Resource plugin_decoder = PluginGlobals::Get()->plugin_resource_tracker()-> + PluginResourceForHostResource(decoder); + if (!plugin_decoder) + return; + CallWhileUnlocked(ppp_video_decoder_impl_->DismissPictureBuffer, + decoder.instance(), + plugin_decoder, + picture_id); +} + +void PPP_VideoDecoder_Proxy::OnMsgPictureReady( + const HostResource& decoder, const PP_Picture_Dev& picture) { + PP_Resource plugin_decoder = PluginGlobals::Get()->plugin_resource_tracker()-> + PluginResourceForHostResource(decoder); + if (!plugin_decoder) + return; + CallWhileUnlocked(ppp_video_decoder_impl_->PictureReady, + decoder.instance(), + plugin_decoder, + &picture); +} + +void PPP_VideoDecoder_Proxy::OnMsgNotifyError( + const HostResource& decoder, PP_VideoDecodeError_Dev error) { + PP_Resource plugin_decoder = PluginGlobals::Get()->plugin_resource_tracker()-> + PluginResourceForHostResource(decoder); + if (!plugin_decoder) + return; + CallWhileUnlocked(ppp_video_decoder_impl_->NotifyError, + decoder.instance(), + plugin_decoder, + error); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/ppp_video_decoder_proxy.h b/chromium/ppapi/proxy/ppp_video_decoder_proxy.h new file mode 100644 index 00000000000..84d83a56b1a --- /dev/null +++ b/chromium/ppapi/proxy/ppp_video_decoder_proxy.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 PPAPI_PROXY_PPP_VIDEO_DECODER_PROXY_H_ +#define PPAPI_PROXY_PPP_VIDEO_DECODER_PROXY_H_ + +#include "ppapi/c/dev/ppp_video_decoder_dev.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/host_resource.h" + +struct PP_Picture_Dev; +struct PP_Size; + +namespace ppapi { +namespace proxy { + +class PPP_VideoDecoder_Proxy : public InterfaceProxy { + public: + PPP_VideoDecoder_Proxy(Dispatcher* dispatcher); + virtual ~PPP_VideoDecoder_Proxy(); + + static const Info* GetInfo(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgProvidePictureBuffers(const ppapi::HostResource& decoder, + uint32_t req_num_of_buffers, + const PP_Size& dimensions, + uint32_t texture_target); + void OnMsgDismissPictureBuffer(const ppapi::HostResource& decoder, + int32_t picture_id); + void OnMsgPictureReady(const ppapi::HostResource& decoder, + const PP_Picture_Dev& picture_buffer); + void OnMsgNotifyError(const ppapi::HostResource& decoder, + PP_VideoDecodeError_Dev error); + + // When this proxy is in the plugin side, this value caches the interface + // pointer so we don't have to retrieve it from the dispatcher each time. + // In the host, this value is always NULL. + const PPP_VideoDecoder_Dev* ppp_video_decoder_impl_; + + DISALLOW_COPY_AND_ASSIGN(PPP_VideoDecoder_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPP_VIDEO_DECODER_PROXY_H_ diff --git a/chromium/ppapi/proxy/printing_resource.cc b/chromium/ppapi/proxy/printing_resource.cc new file mode 100644 index 00000000000..d9be3b74301 --- /dev/null +++ b/chromium/ppapi/proxy/printing_resource.cc @@ -0,0 +1,58 @@ +// 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 "ppapi/proxy/printing_resource.h" + +#include "base/bind.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +PrintingResource::PrintingResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance) { +} + +PrintingResource::~PrintingResource() { +} + +thunk::PPB_Printing_API* PrintingResource::AsPPB_Printing_API() { + return this; +} + +int32_t PrintingResource::GetDefaultPrintSettings( + PP_PrintSettings_Dev* print_settings, + scoped_refptr<TrackedCallback> callback) { + if (!print_settings) + return PP_ERROR_BADARGUMENT; + + if (!sent_create_to_browser()) + SendCreate(BROWSER, PpapiHostMsg_Printing_Create()); + + Call<PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply>( + BROWSER, + PpapiHostMsg_Printing_GetDefaultPrintSettings(), + base::Bind(&PrintingResource::OnPluginMsgGetDefaultPrintSettingsReply, + this, print_settings, callback)); + return PP_OK_COMPLETIONPENDING; +} + +void PrintingResource::OnPluginMsgGetDefaultPrintSettingsReply( + PP_PrintSettings_Dev* settings_out, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const PP_PrintSettings_Dev& settings) { + if (params.result() == PP_OK) + *settings_out = settings; + + // Notify the plugin of the new data. + callback->Run(params.result()); + // DANGER: May delete |this|! +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/printing_resource.h b/chromium/ppapi/proxy/printing_resource.h new file mode 100644 index 00000000000..1f9216ba9ab --- /dev/null +++ b/chromium/ppapi/proxy/printing_resource.h @@ -0,0 +1,46 @@ +// 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_PROXY_PRINTING_RESOURCE_H_ +#define PPAPI_PROXY_PRINTING_RESOURCE_H_ + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_printing_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT PrintingResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_Printing_API) { + public: + PrintingResource(Connection connection, + PP_Instance instance); + virtual ~PrintingResource(); + + // Resource overrides. + virtual thunk::PPB_Printing_API* AsPPB_Printing_API() OVERRIDE; + + // PPB_Printing_API. + virtual int32_t GetDefaultPrintSettings( + PP_PrintSettings_Dev* print_settings, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + void OnPluginMsgGetDefaultPrintSettingsReply( + PP_PrintSettings_Dev* settings_out, + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params, + const PP_PrintSettings_Dev& settings); + + DISALLOW_COPY_AND_ASSIGN(PrintingResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PRINTING_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/printing_resource_unittest.cc b/chromium/ppapi/proxy/printing_resource_unittest.cc new file mode 100644 index 00000000000..af6c7420f27 --- /dev/null +++ b/chromium/ppapi/proxy/printing_resource_unittest.cc @@ -0,0 +1,102 @@ +// 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 <cstring> + +#include "base/message_loop/message_loop.h" +#include "ppapi/c/dev/ppb_printing_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/locking_resource_releaser.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/printing_resource.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest PrintingResourceTest; + +bool g_callback_called; +int32_t g_callback_result; + +void Callback(void* user_data, int32_t result) { + g_callback_called = true; + g_callback_result = result; +} + +bool PP_SizeEqual(const PP_Size& lhs, const PP_Size& rhs) { + return lhs.width == rhs.width && lhs.height == rhs.height; +} + +bool PP_RectEqual(const PP_Rect& lhs, const PP_Rect& rhs) { + return lhs.point.x == rhs.point.x && + lhs.point.y == rhs.point.y && + PP_SizeEqual(lhs.size, rhs.size); +} + +} // namespace + +// Does a full test of GetDefaultPrintSettings() and reply functionality in the +// plugin side using the public C interfaces. +TEST_F(PrintingResourceTest, GetDefaultPrintSettings) { + g_callback_called = false; + + const PPB_Printing_Dev_0_7* printing_iface = + thunk::GetPPB_Printing_Dev_0_7_Thunk(); + LockingResourceReleaser res(printing_iface->Create(pp_instance())); + + PP_PrintSettings_Dev output_settings; + + int32_t result = printing_iface->GetDefaultPrintSettings( + res.get(), &output_settings, PP_MakeCompletionCallback(&Callback, NULL)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + // Should have sent a "GetDefaultPrintSettings" message. + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_Printing_GetDefaultPrintSettings::ID, ¶ms, &msg)); + + // Synthesize a response with some random print settings. + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(PP_OK); + + PP_PrintSettings_Dev reply_settings = { + { { 0, 0 }, { 500, 515 } }, + { { 25, 35 }, { 300, 720 } }, + { 600, 700 }, + 200, + PP_PRINTORIENTATION_NORMAL, + PP_PRINTSCALINGOPTION_NONE, + PP_FALSE, + PP_PRINTOUTPUTFORMAT_PDF + }; + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply(reply_params, + PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply( + reply_settings)))); + + EXPECT_TRUE(PP_RectEqual(reply_settings.printable_area, + output_settings.printable_area)); + EXPECT_TRUE(PP_RectEqual(reply_settings.content_area, + output_settings.content_area)); + EXPECT_TRUE(PP_SizeEqual(reply_settings.paper_size, + output_settings.paper_size)); + EXPECT_EQ(reply_settings.dpi, output_settings.dpi); + EXPECT_EQ(reply_settings.orientation, output_settings.orientation); + EXPECT_EQ(reply_settings.print_scaling_option, + output_settings.print_scaling_option); + EXPECT_EQ(reply_settings.grayscale, output_settings.grayscale); + EXPECT_EQ(reply_settings.format, output_settings.format); + + EXPECT_EQ(g_callback_result, PP_OK); + EXPECT_EQ(g_callback_called, true); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/proxy_array_output.cc b/chromium/ppapi/proxy/proxy_array_output.cc new file mode 100644 index 00000000000..e550b1ceacf --- /dev/null +++ b/chromium/ppapi/proxy/proxy_array_output.cc @@ -0,0 +1,21 @@ +// 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 "ppapi/proxy/proxy_array_output.h" + +#include "base/logging.h" + +namespace ppapi { +namespace proxy { + +// static +void* ArrayOutputAdapterBase::GetDataBufferThunk(void* user_data, + uint32_t element_count, + uint32_t element_size) { + return static_cast<ArrayOutputAdapterBase*>(user_data)-> + GetDataBuffer(element_count, element_size); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/proxy_array_output.h b/chromium/ppapi/proxy/proxy_array_output.h new file mode 100644 index 00000000000..6d15e0b8358 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_array_output.h @@ -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. + +#ifndef PPAPI_PROXY_PROXY_ARRAY_OUTPUT_H_ +#define PPAPI_PROXY_PROXY_ARRAY_OUTPUT_H_ + +#include <vector> + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_array_output.h" + +// Like ppapi/cpp/array_output.h file in the C++ wrappers but for use in the +// proxy where we can't link to the C++ wrappers. This also adds a refcounted +// version. +// +// Use ArrayOutputAdapter when calling a function that synchronously returns +// an array of data. Use RefCountedArrayOutputAdapterWithStorage for +// asynchronous returns: +// +// void OnCallbackComplete( +// int32_t result, +// scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output) { +// // Vector is in output->output(). +// } +// +// void ScheduleCallback() { +// base::scoped_refptr<RefCountedArrayOutputAdapter<PP_Resource> > output; +// +// callback = factory.NewOptionalCallback(&OnCallbackComplete, output); +// DoSomethingAsynchronously(output->pp_array_output(), +// callback.pp_completion_callback()); +// ... +namespace ppapi { +namespace proxy { + +// Non-templatized base class for the array output conversion. It provides the +// C implementation of a PP_ArrayOutput whose callback function is implemented +// as a virtual call on a derived class. Do not use directly, use one of the +// derived classes below. +class ArrayOutputAdapterBase { + public: + ArrayOutputAdapterBase() { + pp_array_output_.GetDataBuffer = + &ArrayOutputAdapterBase::GetDataBufferThunk; + pp_array_output_.user_data = this; + } + virtual ~ArrayOutputAdapterBase() {} + + const PP_ArrayOutput& pp_array_output() { return pp_array_output_; } + + protected: + virtual void* GetDataBuffer(uint32_t element_count, + uint32_t element_size) = 0; + + private: + static void* GetDataBufferThunk(void* user_data, + uint32_t element_count, + uint32_t element_size); + + PP_ArrayOutput pp_array_output_; + + // Disallow copying and assignment. This will do the wrong thing for most + // subclasses. + ArrayOutputAdapterBase(const ArrayOutputAdapterBase&); + ArrayOutputAdapterBase& operator=(const ArrayOutputAdapterBase&); +}; + +// This adapter provides functionality for implementing a PP_ArrayOutput +// structure as writing to a given vector object. +// +// This is generally used internally in the C++ wrapper objects to +// write into an output parameter supplied by the plugin. If the element size +// that the browser is writing does not match the size of the type we're using +// this will assert and return NULL (which will cause the browser to fail the +// call). +// +// Example that allows the browser to write into a given vector: +// void DoFoo(std::vector<int>* results) { +// ArrayOutputAdapter<int> adapter(results); +// ppb_foo->DoFoo(adapter.pp_array_output()); +// } +template<typename T> +class ArrayOutputAdapter : public ArrayOutputAdapterBase { + public: + ArrayOutputAdapter(std::vector<T>* output) : output_(output) {} + + protected: + // Two-step init for the "with storage" version below. + ArrayOutputAdapter() : output_(NULL) {} + void set_output(std::vector<T>* output) { output_ = output; } + + // ArrayOutputAdapterBase implementation. + virtual void* GetDataBuffer(uint32_t element_count, uint32_t element_size) { + DCHECK(element_size == sizeof(T)); + if (element_count == 0 || element_size != sizeof(T)) + return NULL; + output_->resize(element_count); + return &(*output_)[0]; + } + + private: + std::vector<T>* output_; +}; + +template<typename T> +class ArrayOutputAdapterWithStorage : public ArrayOutputAdapter<T> { + public: + ArrayOutputAdapterWithStorage() { + // Note: "this->" is required due to two-phase name lookup where it isn't + // allowed to look in the base class during parsing. + this->set_output(&output_storage_); + } + + std::vector<T>& output() { return output_storage_; } + + private: + std::vector<T> output_storage_; +}; + +// A reference counted version of ArrayOutputAdapterWithStorage. Since it +// doesn't make much sense to heap-allocate one without storage, we don't +// call it "with storage" to keep the name length under control. +template<typename T> +class RefCountedArrayOutputAdapter + : public ArrayOutputAdapterWithStorage<T>, + public base::RefCounted<RefCountedArrayOutputAdapter<T> > { + public: + RefCountedArrayOutputAdapter() + : ArrayOutputAdapterWithStorage<T>() { + } +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PROXY_ARRAY_OUTPUT_H_ diff --git a/chromium/ppapi/proxy/proxy_channel.cc b/chromium/ppapi/proxy/proxy_channel.cc new file mode 100644 index 00000000000..b7f8a826ce3 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_channel.cc @@ -0,0 +1,92 @@ +// 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 "ppapi/proxy/proxy_channel.h" + +#include "base/logging.h" +#include "ipc/ipc_platform_file.h" +#include "ipc/ipc_test_sink.h" + +#if defined(OS_NACL) +#include <unistd.h> +#endif + +namespace ppapi { +namespace proxy { + +ProxyChannel::ProxyChannel() + : delegate_(NULL), + peer_pid_(base::kNullProcessId), + test_sink_(NULL) { +} + +ProxyChannel::~ProxyChannel() { + DVLOG(1) << "ProxyChannel::~ProxyChannel()"; +} + +bool ProxyChannel::InitWithChannel(Delegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + delegate_ = delegate; + peer_pid_ = peer_pid; + IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT + : IPC::Channel::MODE_SERVER; + channel_.reset(new IPC::SyncChannel(channel_handle, mode, this, + delegate->GetIPCMessageLoop(), true, + delegate->GetShutdownEvent())); + return true; +} + +void ProxyChannel::InitWithTestSink(IPC::TestSink* test_sink) { + DCHECK(!test_sink_); + test_sink_ = test_sink; +#if !defined(OS_NACL) + peer_pid_ = base::GetCurrentProcId(); +#endif +} + +void ProxyChannel::OnChannelError() { + channel_.reset(); +} + +#if defined(OS_POSIX) && !defined(OS_NACL) +int ProxyChannel::TakeRendererFD() { + DCHECK(channel()); + return channel()->TakeClientFileDescriptor(); +} +#endif + +IPC::PlatformFileForTransit ProxyChannel::ShareHandleWithRemote( + base::PlatformFile handle, + bool should_close_source) { + // Channel could be closed if the plugin crashes. + if (!channel_.get()) { + if (should_close_source) { +#if !defined(OS_NACL) + base::ClosePlatformFile(handle); +#else + close(handle); +#endif + } + return IPC::InvalidPlatformFileForTransit(); + } + DCHECK(peer_pid_ != base::kNullProcessId); + return delegate_->ShareHandleWithRemote(handle, peer_pid_, + should_close_source); +} + +bool ProxyChannel::Send(IPC::Message* msg) { + if (test_sink_) + return test_sink_->Send(msg); + if (channel_.get()) + return channel_->Send(msg); + + // Remote side crashed, drop this message. + delete msg; + return false; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/proxy_channel.h b/chromium/ppapi/proxy/proxy_channel.h new file mode 100644 index 00000000000..6c9f1f67f74 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_channel.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 PPAPI_PROXY_PROXY_CHANNEL_H_ +#define PPAPI_PROXY_PROXY_CHANNEL_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/process/process.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_platform_file.h" +#include "ipc/ipc_sender.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +namespace base { +class MessageLoopProxy; +class WaitableEvent; +} + +namespace IPC { +class TestSink; +} + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT ProxyChannel + : public IPC::Listener, + public IPC::Sender { + public: + class PPAPI_PROXY_EXPORT Delegate { + public: + virtual ~Delegate() {} + + // Returns the dedicated message loop for processing IPC requests. + virtual base::MessageLoopProxy* GetIPCMessageLoop() = 0; + + // Returns the event object that becomes signalled when the main thread's + // message loop exits. + virtual base::WaitableEvent* GetShutdownEvent() = 0; + + // Duplicates a handle to the provided object, returning one that is valid + // on the other side of the channel. This is part of the delegate interface + // because both sides of the channel may not have sufficient permission to + // duplicate handles directly. The implementation must provide the same + // guarantees as ProxyChannel::ShareHandleWithRemote below. + virtual IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + base::ProcessId remote_pid, + bool should_close_source) = 0; + }; + + virtual ~ProxyChannel(); + + // Alternative to InitWithChannel() for unit tests that want to send all + // messages sent via this channel to the given test sink. The test sink + // must outlive this class. In this case, the peer PID will be the current + // process ID. + void InitWithTestSink(IPC::TestSink* test_sink); + + // Shares a file handle (HANDLE / file descriptor) with the remote side. It + // returns a handle that should be sent in exactly one IPC message. Upon + // receipt, the remote side then owns that handle. Note: if sending the + // message fails, the returned handle is properly closed by the IPC system. If + // should_close_source is set to true, the original handle is closed by this + // operation and should not be used again. + IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + bool should_close_source); + + // IPC::Sender implementation. + virtual bool Send(IPC::Message* msg) OVERRIDE; + + // IPC::Listener implementation. + virtual void OnChannelError() OVERRIDE; + + // Will be NULL in some unit tests and if the remote side has crashed. + IPC::SyncChannel* channel() const { + return channel_.get(); + } + +#if defined(OS_POSIX) && !defined(OS_NACL) + int TakeRendererFD(); +#endif + + protected: + explicit ProxyChannel(); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitWithChannel(Delegate* delegate, + base::ProcessId peer_pid, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + ProxyChannel::Delegate* delegate() const { + return delegate_; + } + + private: + // Non-owning pointer. Guaranteed non-NULL after init is called. + ProxyChannel::Delegate* delegate_; + + // PID of the remote process. Use this instead of the Channel::peer_pid since + // this is set synchronously on construction rather than waiting on the + // "hello" message from the peer (which introduces a race condition). + base::ProcessId peer_pid_; + + // When we're unit testing, this will indicate the sink for the messages to + // be deposited so they can be inspected by the test. When non-NULL, this + // indicates that the channel should not be used. + IPC::TestSink* test_sink_; + + // Will be null for some tests when there is a test_sink_, and if the + // remote side has crashed. + scoped_ptr<IPC::SyncChannel> channel_; + + DISALLOW_COPY_AND_ASSIGN(ProxyChannel); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PROXY_CHANNEL_H_ diff --git a/chromium/ppapi/proxy/proxy_completion_callback_factory.h b/chromium/ppapi/proxy/proxy_completion_callback_factory.h new file mode 100644 index 00000000000..c8dabf183b4 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_completion_callback_factory.h @@ -0,0 +1,87 @@ +// 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_PROXY_PROXY_COMPLETION_CALLBACK_FACTORY_H_ +#define PPAPI_PROXY_PROXY_COMPLETION_CALLBACK_FACTORY_H_ + +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace ppapi { +namespace proxy { + +// This class is just like pp::NonThreadSafeThreadTraits but rather than using +// pp::Module::core (which doesn't exist), it uses Chrome threads which do. +class ProxyNonThreadSafeThreadTraits { + public: + class RefCount { + public: + RefCount() : ref_(0) { +#ifndef NDEBUG + message_loop_ = base::MessageLoop::current(); +#endif + } + + ~RefCount() { +#ifndef NDEBUG + DCHECK(message_loop_ == base::MessageLoop::current()); +#endif + } + + int32_t AddRef() { +#ifndef NDEBUG + DCHECK(message_loop_ == base::MessageLoop::current()); +#endif + return ++ref_; + } + + int32_t Release() { +#ifndef NDEBUG + DCHECK(message_loop_ == base::MessageLoop::current()); +#endif + DCHECK(ref_ > 0); + return --ref_; + } + + private: + int32_t ref_; +#ifndef NDEBUG + base::MessageLoop* message_loop_; +#endif + }; + + // No-op lock class. + class Lock { + public: + Lock() {} + ~Lock() {} + + void Acquire() {} + void Release() {} + }; + + // No-op AutoLock class. + class AutoLock { + public: + explicit AutoLock(Lock&) {} + ~AutoLock() {} + }; +}; + +template<typename T> +class ProxyCompletionCallbackFactory + : public pp::CompletionCallbackFactory<T, ProxyNonThreadSafeThreadTraits> { + public: + ProxyCompletionCallbackFactory() + : pp::CompletionCallbackFactory<T, ProxyNonThreadSafeThreadTraits>() {} + ProxyCompletionCallbackFactory(T* t) + : pp::CompletionCallbackFactory<T, ProxyNonThreadSafeThreadTraits>(t) {} +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PROXY_COMPLETION_CALLBACK_FACTORY_H_ diff --git a/chromium/ppapi/proxy/proxy_module.cc b/chromium/ppapi/proxy/proxy_module.cc new file mode 100644 index 00000000000..885552d72e0 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_module.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/proxy_module.h" + +#include "base/memory/singleton.h" + +namespace ppapi { +namespace proxy { + +ProxyModule::ProxyModule() { +} + +ProxyModule::~ProxyModule() { +} + +// static +ProxyModule* ProxyModule::GetInstance() { + return Singleton<ProxyModule>::get(); +} + +const std::string& ProxyModule::GetFlashCommandLineArgs() { + return flash_command_line_args_; +} + +void ProxyModule::SetFlashCommandLineArgs(const std::string& args) { + flash_command_line_args_ = args; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/proxy_module.h b/chromium/ppapi/proxy/proxy_module.h new file mode 100644 index 00000000000..1ee0b758261 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_module.h @@ -0,0 +1,43 @@ +// 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 PPAPI_PROXY_PROXY_MODULE_H_ +#define PPAPI_PROXY_PROXY_MODULE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT ProxyModule { + public: + // The global singleton getter. + static ProxyModule* GetInstance(); + + // TODO(viettrungluu): Generalize this for use with other plugins if it proves + // necessary. (Currently, we can't do this easily, since we can't tell from + // |PpapiPluginMain()| which plugin will be loaded.) + const std::string& GetFlashCommandLineArgs(); + void SetFlashCommandLineArgs(const std::string& args); + + private: + friend struct DefaultSingletonTraits<ProxyModule>; + + std::string flash_command_line_args_; + + ProxyModule(); + ~ProxyModule(); + + DISALLOW_COPY_AND_ASSIGN(ProxyModule); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PROXY_MODULE_H_ diff --git a/chromium/ppapi/proxy/proxy_object_var.cc b/chromium/ppapi/proxy/proxy_object_var.cc new file mode 100644 index 00000000000..cc0054faa13 --- /dev/null +++ b/chromium/ppapi/proxy/proxy_object_var.cc @@ -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. + +#include "ppapi/proxy/proxy_object_var.h" + +#include "base/logging.h" +#include "ppapi/c/pp_var.h" + +using ppapi::proxy::PluginDispatcher; + +namespace ppapi { + +ProxyObjectVar::ProxyObjectVar(PluginDispatcher* dispatcher, + int32 host_var_id) + : dispatcher_(dispatcher), + host_var_id_(host_var_id), + user_data_(NULL) { + // Should be given valid objects or we'll crash later. + DCHECK(host_var_id_); +} + +ProxyObjectVar::~ProxyObjectVar() { +} + +ProxyObjectVar* ProxyObjectVar::AsProxyObjectVar() { + return this; +} + +PP_VarType ProxyObjectVar::GetType() const { + return PP_VARTYPE_OBJECT; +} + +void ProxyObjectVar::AssignVarID(int32 id) { + return Var::AssignVarID(id); +} + +} // namespace ppapi diff --git a/chromium/ppapi/proxy/proxy_object_var.h b/chromium/ppapi/proxy/proxy_object_var.h new file mode 100644 index 00000000000..599105352ec --- /dev/null +++ b/chromium/ppapi/proxy/proxy_object_var.h @@ -0,0 +1,58 @@ +// 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 PPAPI_PROXY_PROXY_OBJECT_VAR_H_ +#define PPAPI_PROXY_PROXY_OBJECT_VAR_H_ + +#include "base/compiler_specific.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { + +namespace proxy { +class PluginDispatcher; +} // namespace proxy + +// Tracks a reference to an object var in the plugin side of the proxy. This +// just stores the dispatcher and host var ID, and provides the interface for +// integrating this with PP_Var creation. +class PPAPI_PROXY_EXPORT ProxyObjectVar : public Var { + public: + ProxyObjectVar(proxy::PluginDispatcher* dispatcher, + int32 host_var_id); + + virtual ~ProxyObjectVar(); + + // Var overrides. + virtual ProxyObjectVar* AsProxyObjectVar() OVERRIDE; + virtual PP_VarType GetType() const OVERRIDE; + + proxy::PluginDispatcher* dispatcher() const { return dispatcher_; } + int32 host_var_id() const { return host_var_id_; } + + void* user_data() const { return user_data_; } + void set_user_data(void* ud) { user_data_ = ud; } + + // Expose AssignVarID on Var so the PluginResourceTracker can call us when + // it's creating IDs. + void AssignVarID(int32 id); + + void clear_dispatcher() { dispatcher_ = NULL; } + + private: + proxy::PluginDispatcher* dispatcher_; + int32 host_var_id_; + + // When this object is created as representing a var implemented by the + // plugin, this stores the user data so that we can look it up later. See + // PluginVarTracker. + void* user_data_; + + DISALLOW_COPY_AND_ASSIGN(ProxyObjectVar); +}; + +} // namespace ppapi + +#endif // PPAPI_PROXY_PROXY_OBJECT_VAR_H_ diff --git a/chromium/ppapi/proxy/raw_var_data.cc b/chromium/ppapi/proxy/raw_var_data.cc new file mode 100644 index 00000000000..a550c3fca05 --- /dev/null +++ b/chromium/ppapi/proxy/raw_var_data.cc @@ -0,0 +1,665 @@ +// 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 "ppapi/proxy/raw_var_data.h" + +#include <stack> + +#include "base/containers/hash_tables.h" +#include "base/stl_util.h" +#include "ipc/ipc_message.h" +#include "ppapi/proxy/ppapi_param_traits.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/scoped_pp_var.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" + +using std::make_pair; + +namespace ppapi { +namespace proxy { + +namespace { + +// When sending array buffers, if the size is over 256K, we use shared +// memory instead of sending the data over IPC. Light testing suggests +// shared memory is much faster for 256K and larger messages. +static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024; +static uint32 g_minimum_array_buffer_size_for_shmem = + kMinimumArrayBufferSizeForShmem; + +struct StackEntry { + StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {} + PP_Var var; + size_t data_index; +}; + +// For a given PP_Var, returns the RawVarData associated with it, or creates a +// new one if there is no existing one. The data is appended to |data| if it +// is newly created. The index into |data| pointing to the result is returned. +// |visited_map| keeps track of RawVarDatas that have already been created. +size_t GetOrCreateRawVarData(const PP_Var& var, + base::hash_map<int64_t, size_t>* visited_map, + ScopedVector<RawVarData>* data) { + if (VarTracker::IsVarTypeRefcounted(var.type)) { + base::hash_map<int64_t, size_t>::iterator it = visited_map->find( + var.value.as_id); + if (it != visited_map->end()) { + return it->second; + } else { + data->push_back(RawVarData::Create(var.type)); + (*visited_map)[var.value.as_id] = data->size() - 1; + } + } else { + data->push_back(RawVarData::Create(var.type)); + } + return data->size() - 1; +} + +bool CanHaveChildren(PP_Var var) { + return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY; +} + +} // namespace + +// RawVarDataGraph ------------------------------------------------------------ +RawVarDataGraph::RawVarDataGraph() { +} + +RawVarDataGraph::~RawVarDataGraph() { +} + +// This function uses a stack-based DFS search to traverse the var graph. Each +// iteration, the top node on the stack examined. If the node has not been +// visited yet (i.e. !initialized()) then it is added to the list of +// |parent_ids| which contains all of the nodes on the path from the start node +// to the current node. Each of that nodes children are examined. If they appear +// in the list of |parent_ids| it means we have a cycle and we return NULL. +// Otherwise, if they haven't been visited yet 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 |parent_ids|. +// static +scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var, + PP_Instance instance) { + scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph); + // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph. + base::hash_map<int64_t, size_t> visited_map; + base::hash_set<int64_t> parent_ids; + + std::stack<StackEntry> stack; + stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map, + &graph->data_))); + + while (!stack.empty()) { + PP_Var current_var = stack.top().var; + RawVarData* current_var_data = graph->data_[stack.top().data_index]; + + if (current_var_data->initialized()) { + stack.pop(); + if (CanHaveChildren(current_var)) + parent_ids.erase(current_var.value.as_id); + continue; + } + + if (CanHaveChildren(current_var)) + parent_ids.insert(current_var.value.as_id); + if (!current_var_data->Init(current_var, instance)) { + NOTREACHED(); + return scoped_ptr<RawVarDataGraph>(); + } + + // Add child nodes to the stack. + if (current_var.type == PP_VARTYPE_ARRAY) { + ArrayVar* array_var = ArrayVar::FromPPVar(current_var); + if (!array_var) { + NOTREACHED(); + return scoped_ptr<RawVarDataGraph>(); + } + for (ArrayVar::ElementVector::const_iterator iter = + array_var->elements().begin(); + iter != array_var->elements().end(); + ++iter) { + const PP_Var& child = iter->get(); + // If a child of this node is already in parent_ids, we have a cycle so + // we just return null. + if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0) + return scoped_ptr<RawVarDataGraph>(); + size_t child_id = GetOrCreateRawVarData(child, &visited_map, + &graph->data_); + static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id); + if (!graph->data_[child_id]->initialized()) + stack.push(StackEntry(child, child_id)); + } + } else if (current_var.type == PP_VARTYPE_DICTIONARY) { + DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); + if (!dict_var) { + NOTREACHED(); + return scoped_ptr<RawVarDataGraph>(); + } + for (DictionaryVar::KeyValueMap::const_iterator iter = + dict_var->key_value_map().begin(); + iter != dict_var->key_value_map().end(); + ++iter) { + const PP_Var& child = iter->second.get(); + if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0) + return scoped_ptr<RawVarDataGraph>(); + size_t child_id = GetOrCreateRawVarData(child, &visited_map, + &graph->data_); + static_cast<DictionaryRawVarData*>( + current_var_data)->AddChild(iter->first, child_id); + if (!graph->data_[child_id]->initialized()) + stack.push(StackEntry(child, child_id)); + } + } + } + return graph.Pass(); +} + +PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) { + // Create and initialize each node in the graph. + std::vector<PP_Var> graph; + for (size_t i = 0; i < data_.size(); ++i) + graph.push_back(data_[i]->CreatePPVar(instance)); + for (size_t i = 0; i < data_.size(); ++i) + data_[i]->PopulatePPVar(graph[i], graph); + // Everything except the root will have one extra ref. Remove that ref. + for (size_t i = 1; i < data_.size(); ++i) + ScopedPPVar(ScopedPPVar::PassRef(), graph[i]); + // The first element is the root. + return graph[0]; +} + +void RawVarDataGraph::Write(IPC::Message* m, + const HandleWriter& handle_writer) { + // Write the size, followed by each node in the graph. + m->WriteUInt32(static_cast<uint32_t>(data_.size())); + for (size_t i = 0; i < data_.size(); ++i) { + m->WriteInt(data_[i]->Type()); + data_[i]->Write(m, handle_writer); + } +} + +// static +scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m, + PickleIterator* iter) { + scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph); + uint32_t size = 0; + if (!m->ReadUInt32(iter, &size)) + return scoped_ptr<RawVarDataGraph>(); + for (uint32_t i = 0; i < size; ++i) { + int32_t type; + if (!m->ReadInt(iter, &type)) + return scoped_ptr<RawVarDataGraph>(); + PP_VarType var_type = static_cast<PP_VarType>(type); + result->data_.push_back(RawVarData::Create(var_type)); + if (!result->data_.back()->Read(var_type, m, iter)) + return scoped_ptr<RawVarDataGraph>(); + } + return result.Pass(); +} + +std::vector<SerializedHandle*> RawVarDataGraph::GetHandles() { + std::vector<SerializedHandle*> result; + for (size_t i = 0; i < data_.size(); ++i) { + SerializedHandle* handle = data_[i]->GetHandle(); + if (handle) + result.push_back(handle); + } + return result; +} + +// static +void RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest( + uint32 threshold) { + if (threshold == 0) + g_minimum_array_buffer_size_for_shmem = kMinimumArrayBufferSizeForShmem; + else + g_minimum_array_buffer_size_for_shmem = threshold; +} + +// RawVarData ------------------------------------------------------------------ + +// static +RawVarData* RawVarData::Create(PP_VarType type) { + switch (type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + case PP_VARTYPE_BOOL: + case PP_VARTYPE_INT32: + case PP_VARTYPE_DOUBLE: + case PP_VARTYPE_OBJECT: + return new BasicRawVarData(); + case PP_VARTYPE_STRING: + return new StringRawVarData(); + case PP_VARTYPE_ARRAY_BUFFER: + return new ArrayBufferRawVarData(); + case PP_VARTYPE_ARRAY: + return new ArrayRawVarData(); + case PP_VARTYPE_DICTIONARY: + return new DictionaryRawVarData(); + } + NOTREACHED(); + return NULL; +} + +RawVarData::RawVarData() : initialized_(false) { +} + +RawVarData::~RawVarData() { +} + +SerializedHandle* RawVarData::GetHandle() { + return NULL; +} + +// BasicRawVarData ------------------------------------------------------------- +BasicRawVarData::BasicRawVarData() { +} + +BasicRawVarData::~BasicRawVarData() { +} + +PP_VarType BasicRawVarData::Type() { + return var_.type; +} + +bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { + var_ = var; + initialized_ = true; + return true; +} + +PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) { + return var_; +} + +void BasicRawVarData::PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) { +} + +void BasicRawVarData::Write( + IPC::Message* m, + const HandleWriter& handle_writer) { + switch (var_.type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + // These don't need any data associated with them other than the type we + // just serialized. + break; + case PP_VARTYPE_BOOL: + m->WriteBool(PP_ToBool(var_.value.as_bool)); + break; + case PP_VARTYPE_INT32: + m->WriteInt(var_.value.as_int); + break; + case PP_VARTYPE_DOUBLE: + IPC::ParamTraits<double>::Write(m, var_.value.as_double); + break; + case PP_VARTYPE_OBJECT: + m->WriteInt64(var_.value.as_id); + break; + default: + NOTREACHED(); + break; + } +} + +bool BasicRawVarData::Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) { + PP_Var result; + result.type = type; + switch (type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + // These don't have any data associated with them other than the type we + // just serialized. + break; + case PP_VARTYPE_BOOL: { + bool bool_value; + if (!m->ReadBool(iter, &bool_value)) + return false; + result.value.as_bool = PP_FromBool(bool_value); + break; + } + case PP_VARTYPE_INT32: + if (!m->ReadInt(iter, &result.value.as_int)) + return false; + break; + case PP_VARTYPE_DOUBLE: + if (!IPC::ParamTraits<double>::Read(m, iter, &result.value.as_double)) + return false; + break; + case PP_VARTYPE_OBJECT: + if (!m->ReadInt64(iter, &result.value.as_id)) + return false; + break; + default: + NOTREACHED(); + return false; + } + var_ = result; + return true; +} + +// StringRawVarData ------------------------------------------------------------ +StringRawVarData::StringRawVarData() { +} + +StringRawVarData::~StringRawVarData() { +} + +PP_VarType StringRawVarData::Type() { + return PP_VARTYPE_STRING; +} + +bool StringRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { + DCHECK(var.type == PP_VARTYPE_STRING); + StringVar* string_var = StringVar::FromPPVar(var); + if (!string_var) + return false; + data_ = string_var->value(); + initialized_ = true; + return true; +} + +PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) { + return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_); +} + +void StringRawVarData::PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) { +} + +void StringRawVarData::Write(IPC::Message* m, + const HandleWriter& handle_writer) { + m->WriteString(data_); +} + +bool StringRawVarData::Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) { + if (!m->ReadString(iter, &data_)) + return false; + return true; +} + +// ArrayBufferRawVarData ------------------------------------------------------- +ArrayBufferRawVarData::ArrayBufferRawVarData() { +} + +ArrayBufferRawVarData::~ArrayBufferRawVarData() { +} + +PP_VarType ArrayBufferRawVarData::Type() { + return PP_VARTYPE_ARRAY_BUFFER; +} + +bool ArrayBufferRawVarData::Init(const PP_Var& var, + PP_Instance instance) { + DCHECK(var.type == PP_VARTYPE_ARRAY_BUFFER); + ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var); + if (!buffer_var) + return false; + bool using_shmem = false; + if (buffer_var->ByteLength() >= g_minimum_array_buffer_size_for_shmem && + instance != 0) { + int host_handle_id; + base::SharedMemoryHandle plugin_handle; + using_shmem = buffer_var->CopyToNewShmem(instance, + &host_handle_id, + &plugin_handle); + if (using_shmem) { + if (host_handle_id != -1) { + DCHECK(!base::SharedMemory::IsHandleValid(plugin_handle)); + DCHECK(PpapiGlobals::Get()->IsPluginGlobals()); + type_ = ARRAY_BUFFER_SHMEM_HOST; + host_shm_handle_id_ = host_handle_id; + } else { + DCHECK(base::SharedMemory::IsHandleValid(plugin_handle)); + DCHECK(PpapiGlobals::Get()->IsHostGlobals()); + type_ = ARRAY_BUFFER_SHMEM_PLUGIN; + plugin_shm_handle_ = SerializedHandle(plugin_handle, + buffer_var->ByteLength()); + } + } + } + if (!using_shmem) { + type_ = ARRAY_BUFFER_NO_SHMEM; + data_ = std::string(static_cast<const char*>(buffer_var->Map()), + buffer_var->ByteLength()); + } + initialized_ = true; + return true; +} + +PP_Var ArrayBufferRawVarData::CreatePPVar(PP_Instance instance) { + PP_Var result = PP_MakeUndefined(); + switch (type_) { + case ARRAY_BUFFER_SHMEM_HOST: { + base::SharedMemoryHandle host_handle; + uint32 size_in_bytes; + bool ok = PpapiGlobals::Get()->GetVarTracker()-> + StopTrackingSharedMemoryHandle(host_shm_handle_id_, + instance, + &host_handle, + &size_in_bytes); + if (ok) { + result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + size_in_bytes, host_handle); + } else { + LOG(ERROR) << "Couldn't find array buffer id: " << host_shm_handle_id_; + return PP_MakeUndefined(); + } + break; + } + case ARRAY_BUFFER_SHMEM_PLUGIN: { + result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + plugin_shm_handle_.size(), + plugin_shm_handle_.shmem()); + break; + } + case ARRAY_BUFFER_NO_SHMEM: { + result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + static_cast<uint32>(data_.size()), data_.data()); + break; + } + default: + NOTREACHED(); + return PP_MakeUndefined(); + } + DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER); + return result; +} + +void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) { +} + +void ArrayBufferRawVarData::Write( + IPC::Message* m, + const HandleWriter& handle_writer) { + m->WriteInt(type_); + switch (type_) { + case ARRAY_BUFFER_SHMEM_HOST: + m->WriteInt(host_shm_handle_id_); + break; + case ARRAY_BUFFER_SHMEM_PLUGIN: + handle_writer.Run(m, plugin_shm_handle_); + break; + case ARRAY_BUFFER_NO_SHMEM: + m->WriteString(data_); + break; + } +} + +bool ArrayBufferRawVarData::Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) { + int shmem_type; + if (!m->ReadInt(iter, &shmem_type)) + return false; + type_ = static_cast<ShmemType>(shmem_type); + switch (type_) { + case ARRAY_BUFFER_SHMEM_HOST: + if (!m->ReadInt(iter, &host_shm_handle_id_)) + return false; + break; + case ARRAY_BUFFER_SHMEM_PLUGIN: + if (!IPC::ParamTraits<SerializedHandle>::Read( + m, iter, &plugin_shm_handle_)) { + return false; + } + break; + case ARRAY_BUFFER_NO_SHMEM: + if (!m->ReadString(iter, &data_)) + return false; + break; + default: + // We read an invalid ID. + NOTREACHED(); + return false; + } + return true; +} + +SerializedHandle* ArrayBufferRawVarData::GetHandle() { + if (type_ == ARRAY_BUFFER_SHMEM_PLUGIN && plugin_shm_handle_.size() != 0) + return &plugin_shm_handle_; + return NULL; +} + +// ArrayRawVarData ------------------------------------------------------------- +ArrayRawVarData::ArrayRawVarData() { +} + +ArrayRawVarData::~ArrayRawVarData() { +} + +void ArrayRawVarData::AddChild(size_t element) { + children_.push_back(element); +} + +PP_VarType ArrayRawVarData::Type() { + return PP_VARTYPE_ARRAY; +} + +bool ArrayRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { + initialized_ = true; + DCHECK(var.type == PP_VARTYPE_ARRAY); + initialized_ = true; + return true; +} + +PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) { + return (new ArrayVar())->GetPPVar(); +} + +void ArrayRawVarData::PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) { + if (var.type != PP_VARTYPE_ARRAY) { + NOTREACHED(); + return; + } + ArrayVar* array_var = ArrayVar::FromPPVar(var); + DCHECK(array_var->elements().empty()); + for (size_t i = 0; i < children_.size(); ++i) + array_var->elements().push_back(ScopedPPVar(graph[children_[i]])); +} + +void ArrayRawVarData::Write(IPC::Message* m, + const HandleWriter& handle_writer) { + m->WriteUInt32(static_cast<uint32_t>(children_.size())); + for (size_t i = 0; i < children_.size(); ++i) + m->WriteUInt32(static_cast<uint32_t>(children_[i])); +} + +bool ArrayRawVarData::Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) { + uint32_t size; + if (!m->ReadUInt32(iter, &size)) + return false; + for (uint32_t i = 0; i < size; ++i) { + uint32_t index; + if (!m->ReadUInt32(iter, &index)) + return false; + children_.push_back(index); + } + return true; +} + +// DictionaryRawVarData -------------------------------------------------------- +DictionaryRawVarData::DictionaryRawVarData() { +} + +DictionaryRawVarData::~DictionaryRawVarData() { +} + +void DictionaryRawVarData::AddChild(const std::string& key, + size_t value) { + children_.push_back(make_pair(key, value)); +} + +PP_VarType DictionaryRawVarData::Type() { + return PP_VARTYPE_DICTIONARY; +} + +bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { + DCHECK(var.type == PP_VARTYPE_DICTIONARY); + initialized_ = true; + return true; +} + +PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) { + return (new DictionaryVar())->GetPPVar(); +} + +void DictionaryRawVarData::PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) { + if (var.type != PP_VARTYPE_DICTIONARY) { + NOTREACHED(); + return; + } + DictionaryVar* dictionary_var = DictionaryVar::FromPPVar(var); + DCHECK(dictionary_var->key_value_map().empty()); + for (size_t i = 0; i < children_.size(); ++i) { + bool success = dictionary_var->SetWithStringKey(children_[i].first, + graph[children_[i].second]); + DCHECK(success); + } +} + +void DictionaryRawVarData::Write( + IPC::Message* m, + const HandleWriter& handle_writer) { + m->WriteUInt32(static_cast<uint32_t>(children_.size())); + for (size_t i = 0; i < children_.size(); ++i) { + m->WriteString(children_[i].first); + m->WriteUInt32(static_cast<uint32_t>(children_[i].second)); + } +} + +bool DictionaryRawVarData::Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) { + uint32_t size; + if (!m->ReadUInt32(iter, &size)) + return false; + for (uint32_t i = 0; i < size; ++i) { + std::string key; + uint32_t value; + if (!m->ReadString(iter, &key)) + return false; + if (!m->ReadUInt32(iter, &value)) + return false; + children_.push_back(make_pair(key, value)); + } + return true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/raw_var_data.h b/chromium/ppapi/proxy/raw_var_data.h new file mode 100644 index 00000000000..c7981d38ff7 --- /dev/null +++ b/chromium/ppapi/proxy/raw_var_data.h @@ -0,0 +1,261 @@ +// 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 PPAPI_PROXY_RAW_VAR_DATA_H_ +#define PPAPI_PROXY_RAW_VAR_DATA_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/serialized_handle.h" + +class PickleIterator; + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace proxy { + +class RawVarData; + +typedef base::Callback<void(IPC::Message*, const SerializedHandle&)> + HandleWriter; + +// Contains the data associated with a graph of connected PP_Vars. Useful for +// serializing/deserializing a graph of PP_Vars. First we compute the transitive +// closure of the given PP_Var to find all PP_Vars which are referenced by that +// var. A RawVarData object is created for each of these vars. We then write +// data contained in each RawVarData to the message. The format looks like this: +// idx | size | (number of vars in the graph) +// 0 | var type | +// | var data | +// 1 | var type | +// | var data | +// 2 | var type | +// | var data | +// | .... | +// +// Vars that reference other vars (such as Arrays or Dictionaries) use indices +// into the message to denote which PP_Var is pointed to. +class PPAPI_PROXY_EXPORT RawVarDataGraph { + public: + // Construct a RawVarDataGraph from a given root PP_Var. A null pointer + // is returned upon failure. + static scoped_ptr<RawVarDataGraph> Create(const PP_Var& var, + PP_Instance instance); + + // Constructs an empty RawVarDataGraph. + RawVarDataGraph(); + ~RawVarDataGraph(); + + // Construct a new PP_Var from the graph. All of the PP_Vars referenced by + // the returned PP_Var are also constructed. Each PP_Var created has a + // ref-count equal to the number of references it has in the graph of vars. + // The returned var (the "root") has one additional reference. + PP_Var CreatePPVar(PP_Instance instance); + + // Write the graph to a message using the given HandleWriter. + void Write(IPC::Message* m, const HandleWriter& handle_writer); + + // Create a RawVarDataGraph from the given message. + static scoped_ptr<RawVarDataGraph> Read(const IPC::Message* m, + PickleIterator* iter); + + // Returns a vector of SerializedHandles associated with this RawVarDataGraph. + // Ownership of the pointers remains with the elements of the RawVarDataGraph. + std::vector<SerializedHandle*> GetHandles(); + + // Sets the threshold size at which point we switch from transmitting + // array buffers in IPC messages to using shared memory. This is only used + // for testing purposes where we need to transmit small buffers using shmem + // (in order to have fast tests). + static void SetMinimumArrayBufferSizeForShmemForTest(uint32 threshold); + + // A list of the nodes in the graph. + ScopedVector<RawVarData> data_; +}; + +// Abstract base class for the data contained in a PP_Var. +class RawVarData { + public: + // Create a new, empty RawVarData for the given type. + static RawVarData* Create(PP_VarType type); + RawVarData(); + virtual ~RawVarData(); + + // Returns the type of the PP_Var represented by the RawVarData. + virtual PP_VarType Type() = 0; + + // Initializes a RawVarData from a PP_Var. Returns true on success. + virtual bool Init(const PP_Var& var, PP_Instance instance) = 0; + + // Create a PP_Var from the raw data contained in this object. + virtual PP_Var CreatePPVar(PP_Instance instance) = 0; + // Some PP_Vars may require 2-step initialization. For example, they may + // reference other PP_Vars which had not yet been created when |CreatePPVar| + // was called. The original var created with |CreatePPVar| is passed back in, + // along with the graph it is a part of to be initialized. + virtual void PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) = 0; + + // Writes the RawVarData to a message. + virtual void Write(IPC::Message* m, + const HandleWriter& handle_writer) = 0; + // Reads the RawVarData from a message. Returns true on success. + virtual bool Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) = 0; + + // Returns a SerializedHandle associated with this RawVarData or NULL if none + // exists. Ownership of the pointer remains with the RawVarData. + virtual SerializedHandle* GetHandle(); + + bool initialized() { return initialized_; } + + protected: + bool initialized_; +}; + +// A RawVarData class for PP_Vars which are value types. +class BasicRawVarData : public RawVarData { + public: + BasicRawVarData(); + virtual ~BasicRawVarData(); + + // RawVarData implementation. + virtual PP_VarType Type() OVERRIDE; + virtual bool Init(const PP_Var& var, PP_Instance instance) OVERRIDE; + virtual PP_Var CreatePPVar(PP_Instance instance) OVERRIDE; + virtual void PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) OVERRIDE; + virtual void Write(IPC::Message* m, + const HandleWriter& handle_writer) OVERRIDE; + virtual bool Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) OVERRIDE; + + private: + PP_Var var_; +}; + +// A RawVarData class for string PP_Vars. +class StringRawVarData : public RawVarData { + public: + StringRawVarData(); + virtual ~StringRawVarData(); + + // RawVarData implementation. + virtual PP_VarType Type() OVERRIDE; + virtual bool Init(const PP_Var& var, PP_Instance instance) OVERRIDE; + virtual PP_Var CreatePPVar(PP_Instance instance) OVERRIDE; + virtual void PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) OVERRIDE; + virtual void Write(IPC::Message* m, + const HandleWriter& handle_writer) OVERRIDE; + virtual bool Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) OVERRIDE; + + private: + // The data in the string. + std::string data_; +}; + +// A RawVarData class for array buffer PP_Vars. +class ArrayBufferRawVarData : public RawVarData { + public: + // Enum for array buffer message types. + enum ShmemType { + ARRAY_BUFFER_NO_SHMEM, + ARRAY_BUFFER_SHMEM_HOST, + ARRAY_BUFFER_SHMEM_PLUGIN, + }; + + ArrayBufferRawVarData(); + virtual ~ArrayBufferRawVarData(); + + // RawVarData implementation. + virtual PP_VarType Type() OVERRIDE; + virtual bool Init(const PP_Var& var, PP_Instance instance) OVERRIDE; + virtual PP_Var CreatePPVar(PP_Instance instance) OVERRIDE; + virtual void PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) OVERRIDE; + virtual void Write(IPC::Message* m, + const HandleWriter& handle_writer) OVERRIDE; + virtual bool Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) OVERRIDE; + virtual SerializedHandle* GetHandle() OVERRIDE; + + private: + // The type of the storage underlying the array buffer. + ShmemType type_; + // The data in the buffer. Valid for |type_| == ARRAY_BUFFER_NO_SHMEM. + std::string data_; + // Host shmem handle. Valid for |type_| == ARRAY_BUFFER_SHMEM_HOST. + int host_shm_handle_id_; + // Plugin shmem handle. Valid for |type_| == ARRAY_BUFFER_SHMEM_PLUGIN. + SerializedHandle plugin_shm_handle_; +}; + +// A RawVarData class for array PP_Vars. +class ArrayRawVarData : public RawVarData { + public: + ArrayRawVarData(); + virtual ~ArrayRawVarData(); + + void AddChild(size_t element); + + // RawVarData implementation. + virtual PP_VarType Type() OVERRIDE; + virtual bool Init(const PP_Var& var, PP_Instance instance) OVERRIDE; + virtual PP_Var CreatePPVar(PP_Instance instance) OVERRIDE; + virtual void PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) OVERRIDE; + virtual void Write(IPC::Message* m, + const HandleWriter& handle_writer) OVERRIDE; + virtual bool Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) OVERRIDE; + + private: + std::vector<size_t> children_; +}; + +// A RawVarData class for dictionary PP_Vars. +class DictionaryRawVarData : public RawVarData { + public: + DictionaryRawVarData(); + virtual ~DictionaryRawVarData(); + + void AddChild(const std::string& key, size_t value); + + // RawVarData implementation. + virtual PP_VarType Type() OVERRIDE; + virtual bool Init(const PP_Var& var, PP_Instance instance) OVERRIDE; + virtual PP_Var CreatePPVar(PP_Instance instance) OVERRIDE; + virtual void PopulatePPVar(const PP_Var& var, + const std::vector<PP_Var>& graph) OVERRIDE; + virtual void Write(IPC::Message* m, + const HandleWriter& handle_writer) OVERRIDE; + virtual bool Read(PP_VarType type, + const IPC::Message* m, + PickleIterator* iter) OVERRIDE; + + private: + std::vector<std::pair<std::string, size_t> > children_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_RAW_VAR_DATA_H_ diff --git a/chromium/ppapi/proxy/raw_var_data_unittest.cc b/chromium/ppapi/proxy/raw_var_data_unittest.cc new file mode 100644 index 00000000000..2ee69144f61 --- /dev/null +++ b/chromium/ppapi/proxy/raw_var_data_unittest.cc @@ -0,0 +1,189 @@ +// 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 "ppapi/proxy/raw_var_data.h" + +#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" + +namespace ppapi { +namespace proxy { + +namespace { + +void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { + IPC::ParamTraits<SerializedHandle>::Write(m, handle); +} + +class RawVarDataTest : public testing::Test { + public: + RawVarDataTest() {} + ~RawVarDataTest() {} + + // testing::Test implementation. + virtual void SetUp() { + ProxyLock::Acquire(); + } + virtual void TearDown() { + ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); + ProxyLock::Release(); + } + + private: + TestGlobals globals_; +}; + +bool WriteAndRead(const PP_Var& var, PP_Var* result) { + PP_Instance dummy_instance = 1234; + scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create( + var, dummy_instance)); + if (!expected_data) + return false; + IPC::Message m; + expected_data->Write(&m, base::Bind(&DefaultHandleWriter)); + PickleIterator iter(m); + scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter)); + *result = actual_data->CreatePPVar(dummy_instance); + return true; +} + +// Assumes a ref for var. +bool WriteReadAndCompare(const PP_Var& var) { + ScopedPPVar expected(ScopedPPVar::PassRef(), var); + PP_Var result; + bool success = WriteAndRead(expected.get(), &result); + if (!success) + return false; + ScopedPPVar actual(ScopedPPVar::PassRef(), result); + return TestEqual(expected.get(), actual.get()); +} + +} // namespace + +TEST_F(RawVarDataTest, SimpleTest) { + EXPECT_TRUE(WriteReadAndCompare(PP_MakeUndefined())); + EXPECT_TRUE(WriteReadAndCompare(PP_MakeNull())); + EXPECT_TRUE(WriteReadAndCompare(PP_MakeInt32(100))); + EXPECT_TRUE(WriteReadAndCompare(PP_MakeBool(PP_TRUE))); + EXPECT_TRUE(WriteReadAndCompare(PP_MakeDouble(53.75))); + PP_Var object; + object.type = PP_VARTYPE_OBJECT; + object.value.as_id = 10; + EXPECT_TRUE(WriteReadAndCompare(object)); +} + +TEST_F(RawVarDataTest, StringTest) { + EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar(""))); + EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar("hello world!"))); +} + +TEST_F(RawVarDataTest, ArrayBufferTest) { + std::string data = "hello world!"; + PP_Var var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + data.size(), data.data()); + EXPECT_TRUE(WriteReadAndCompare(var)); + var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + 0, static_cast<void*>(NULL)); + EXPECT_TRUE(WriteReadAndCompare(var)); + // TODO(raymes): add tests for shmem type array buffers. +} + +TEST_F(RawVarDataTest, DictionaryArrayTest) { + // Empty array. + scoped_refptr<ArrayVar> array(new ArrayVar); + ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); + EXPECT_TRUE(WriteReadAndCompare(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(WriteReadAndCompare(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(WriteReadAndCompare(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(WriteReadAndCompare(array->GetPPVar())); + + // Empty dictionary. + scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); + ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), + dictionary->GetPPVar()); + EXPECT_TRUE(WriteReadAndCompare(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(WriteReadAndCompare(dictionary->GetPPVar())); + + // Dictionary with 2 references to the same string. + dictionary->SetWithStringKey("6", release_string.get()); + dictionary->SetWithStringKey("7", release_string.get()); + EXPECT_TRUE(WriteReadAndCompare(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(WriteReadAndCompare(dictionary->GetPPVar())); + + // Array with dictionary. + array->Set(index++, release_dictionary.get()); + EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); + + // Array with dictionary with array. + array2->Set(0, PP_MakeInt32(100)); + dictionary->SetWithStringKey("9", release_array2.get()); + EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); + + // Array <-> dictionary cycle. + dictionary->SetWithStringKey("10", release_array.get()); + PP_Var result; + ASSERT_FALSE(WriteAndRead(release_dictionary.get(), &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("10"); + + // Array with self references. + array->Set(index, release_array.get()); + ASSERT_FALSE(WriteAndRead(release_array.get(), &result)); + // Break the self reference. + array->Set(index, PP_MakeUndefined()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/resource_creation_proxy.cc b/chromium/ppapi/proxy/resource_creation_proxy.cc new file mode 100644 index 00000000000..53cade1e91a --- /dev/null +++ b/chromium/ppapi/proxy/resource_creation_proxy.cc @@ -0,0 +1,464 @@ +// 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 "ppapi/proxy/resource_creation_proxy.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/proxy/audio_input_resource.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/ext_crx_file_system_private_resource.h" +#include "ppapi/proxy/file_chooser_resource.h" +#include "ppapi/proxy/file_io_resource.h" +#include "ppapi/proxy/file_system_resource.h" +#include "ppapi/proxy/flash_drm_resource.h" +#include "ppapi/proxy/flash_font_file_resource.h" +#include "ppapi/proxy/flash_menu_resource.h" +#include "ppapi/proxy/graphics_2d_resource.h" +#include "ppapi/proxy/host_resolver_private_resource.h" +#include "ppapi/proxy/host_resolver_resource.h" +#include "ppapi/proxy/net_address_resource.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_audio_proxy.h" +#include "ppapi/proxy/ppb_broker_proxy.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/ppb_flash_message_loop_proxy.h" +#include "ppapi/proxy/ppb_graphics_3d_proxy.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/ppb_network_monitor_private_proxy.h" +#include "ppapi/proxy/ppb_tcp_socket_private_proxy.h" +#include "ppapi/proxy/ppb_tcp_socket_proxy.h" +#include "ppapi/proxy/ppb_video_decoder_proxy.h" +#include "ppapi/proxy/ppb_x509_certificate_private_proxy.h" +#include "ppapi/proxy/printing_resource.h" +#include "ppapi/proxy/talk_resource.h" +#include "ppapi/proxy/tcp_server_socket_private_resource.h" +#include "ppapi/proxy/truetype_font_resource.h" +#include "ppapi/proxy/udp_socket_private_resource.h" +#include "ppapi/proxy/udp_socket_resource.h" +#include "ppapi/proxy/url_loader_resource.h" +#include "ppapi/proxy/url_request_info_resource.h" +#include "ppapi/proxy/url_response_info_resource.h" +#include "ppapi/proxy/video_capture_resource.h" +#include "ppapi/proxy/video_destination_resource.h" +#include "ppapi/proxy/video_source_resource.h" +#include "ppapi/proxy/websocket_resource.h" +#include "ppapi/shared_impl/api_id.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/ppb_audio_config_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" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" + +using ppapi::thunk::ResourceCreationAPI; + +namespace ppapi { +namespace proxy { + +ResourceCreationProxy::ResourceCreationProxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +ResourceCreationProxy::~ResourceCreationProxy() { +} + +// static +InterfaceProxy* ResourceCreationProxy::Create(Dispatcher* dispatcher) { + return new ResourceCreationProxy(dispatcher); +} + +PP_Resource ResourceCreationProxy::CreateFileIO(PP_Instance instance) { + return (new FileIOResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateFileRef(PP_Instance instance, + PP_Resource file_system, + const char* path) { + return PPB_FileRef_Proxy::CreateProxyResource(instance, file_system, path); +} + +PP_Resource ResourceCreationProxy::CreateFileRef( + const PPB_FileRef_CreateInfo& create_info) { + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +PP_Resource ResourceCreationProxy::CreateFileSystem( + PP_Instance instance, + PP_FileSystemType type) { + return (new FileSystemResource(GetConnection(), instance, + type))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateIsolatedFileSystem( + PP_Instance instance, + const char* fsid) { + FileSystemResource* fs = new FileSystemResource( + GetConnection(), instance, PP_FILESYSTEMTYPE_ISOLATED); + fs->InitIsolatedFileSystem(fsid); + return fs->GetReference(); +} + +PP_Resource ResourceCreationProxy::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( + OBJECT_IS_PROXY, instance, type, time_stamp, text, segment_number, + segment_offsets, target_segment, selection_start, selection_end); +} + +PP_Resource ResourceCreationProxy::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( + OBJECT_IS_PROXY, instance, type, time_stamp, modifiers, key_code, + character_text); +} + +PP_Resource ResourceCreationProxy::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( + OBJECT_IS_PROXY, instance, type, time_stamp, modifiers, + mouse_button, mouse_position, click_count, mouse_movement); +} + +PP_Resource ResourceCreationProxy::CreateTouchInputEvent( + PP_Instance instance, + PP_InputEvent_Type type, + PP_TimeTicks time_stamp, + uint32_t modifiers) { + return PPB_InputEvent_Shared::CreateTouchInputEvent( + OBJECT_IS_PROXY, instance, type, time_stamp, modifiers); +} + +PP_Resource ResourceCreationProxy::CreateResourceArray( + PP_Instance instance, + const PP_Resource elements[], + uint32_t size) { + PPB_ResourceArray_Shared* object = new PPB_ResourceArray_Shared( + OBJECT_IS_PROXY, instance, elements, size); + return object->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateTrueTypeFont( + PP_Instance instance, + const PP_TrueTypeFontDesc_Dev* desc) { + return (new TrueTypeFontResource(GetConnection(), + instance, *desc))->GetReference(); + +} + +PP_Resource ResourceCreationProxy::CreateURLLoader(PP_Instance instance) { + return (new URLLoaderResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateURLRequestInfo( + PP_Instance instance) { + return (new URLRequestInfoResource( + GetConnection(), instance, URLRequestInfoData()))->GetReference(); +} + +PP_Resource ResourceCreationProxy::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( + OBJECT_IS_PROXY, instance, time_stamp, modifiers, + wheel_delta, wheel_ticks, scroll_by_page); +} + +PP_Resource ResourceCreationProxy::CreateAudio( + PP_Instance instance, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data) { + return PPB_Audio_Proxy::CreateProxyResource(instance, config_id, + audio_callback, user_data); +} + +PP_Resource ResourceCreationProxy::CreateAudioTrusted(PP_Instance instance) { + // Proxied plugins can't create trusted audio devices. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateAudioConfig( + PP_Instance instance, + PP_AudioSampleRate sample_rate, + uint32_t sample_frame_count) { + return PPB_AudioConfig_Shared::Create( + OBJECT_IS_PROXY, instance, sample_rate, sample_frame_count); +} + +PP_Resource ResourceCreationProxy::CreateFileChooser( + PP_Instance instance, + PP_FileChooserMode_Dev mode, + const PP_Var& accept_types) { + scoped_refptr<StringVar> string_var = StringVar::FromPPVar(accept_types); + std::string str = string_var.get() ? string_var->value() : std::string(); + return (new FileChooserResource(GetConnection(), instance, mode, str.c_str())) + ->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateGraphics2D(PP_Instance instance, + const PP_Size* size, + PP_Bool is_always_opaque) { + return (new Graphics2DResource(GetConnection(), instance, *size, + is_always_opaque))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateGraphics3D( + PP_Instance instance, + PP_Resource share_context, + const int32_t* attrib_list) { + return PPB_Graphics3D_Proxy::CreateProxyResource( + instance, share_context, attrib_list); +} + +PP_Resource ResourceCreationProxy::CreateGraphics3DRaw( + PP_Instance instance, + PP_Resource share_context, + const int32_t* attrib_list) { + // Not proxied. The raw creation function is used only in the implementation + // of the proxy on the host side. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateHostResolver(PP_Instance instance) { + return (new HostResolverResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateHostResolverPrivate( + PP_Instance instance) { + return (new HostResolverPrivateResource( + GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateImageData( + PP_Instance instance, + PP_ImageDataFormat format, + const PP_Size* size, + PP_Bool init_to_zero) { + // On the plugin side, we create PlatformImageData resources for trusted + // plugins and SimpleImageData resources for untrusted ones. + PPB_ImageData_Shared::ImageDataType type = +#if !defined(OS_NACL) + PPB_ImageData_Shared::PLATFORM; +#else + PPB_ImageData_Shared::SIMPLE; +#endif + return PPB_ImageData_Proxy::CreateProxyResource( + instance, type, + format, *size, init_to_zero); +} + +PP_Resource ResourceCreationProxy::CreateImageDataSimple( + PP_Instance instance, + PP_ImageDataFormat format, + const PP_Size* size, + PP_Bool init_to_zero) { + return PPB_ImageData_Proxy::CreateProxyResource( + instance, + PPB_ImageData_Shared::SIMPLE, + format, *size, init_to_zero); +} + +PP_Resource ResourceCreationProxy::CreateNetAddressFromIPv4Address( + PP_Instance instance, + const PP_NetAddress_IPv4* ipv4_addr) { + return (new NetAddressResource(GetConnection(), instance, + *ipv4_addr))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateNetAddressFromIPv6Address( + PP_Instance instance, + const PP_NetAddress_IPv6* ipv6_addr) { + return (new NetAddressResource(GetConnection(), instance, + *ipv6_addr))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateNetAddressFromNetAddressPrivate( + PP_Instance instance, + const PP_NetAddress_Private& private_addr) { + return (new NetAddressResource(GetConnection(), instance, + private_addr))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateNetworkMonitor( + PP_Instance instance, + PPB_NetworkMonitor_Callback callback, + void* user_data) { + return PPB_NetworkMonitor_Private_Proxy::CreateProxyResource( + instance, callback, user_data); +} + +PP_Resource ResourceCreationProxy::CreatePrinting(PP_Instance instance) { + return (new PrintingResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateTCPServerSocketPrivate( + PP_Instance instance) { + return (new TCPServerSocketPrivateResource(GetConnection(), instance))-> + GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateTCPSocket( + PP_Instance instance) { + return PPB_TCPSocket_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateTCPSocketPrivate( + PP_Instance instance) { + return PPB_TCPSocket_Private_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateUDPSocket(PP_Instance instance) { + return (new UDPSocketResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateUDPSocketPrivate( + PP_Instance instance) { + return (new UDPSocketPrivateResource( + GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateVideoDestination( + PP_Instance instance) { + return (new VideoDestinationResource(GetConnection(), + instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateVideoSource( + PP_Instance instance) { + return (new VideoSourceResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateWebSocket(PP_Instance instance) { + return (new WebSocketResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateX509CertificatePrivate( + PP_Instance instance) { + return PPB_X509Certificate_Private_Proxy::CreateProxyResource(instance); +} + +#if !defined(OS_NACL) +PP_Resource ResourceCreationProxy::CreateAudioInput( + PP_Instance instance) { + return (new AudioInputResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateBroker(PP_Instance instance) { + return PPB_Broker_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateBrowserFont( + PP_Instance instance, + const PP_BrowserFont_Trusted_Description* description) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + return PluginGlobals::Get()->CreateBrowserFont( + GetConnection(), instance, *description, dispatcher->preferences()); +} + +PP_Resource ResourceCreationProxy::CreateBuffer(PP_Instance instance, + uint32_t size) { + return PPB_Buffer_Proxy::CreateProxyResource(instance, size); +} + +PP_Resource ResourceCreationProxy::CreateFlashDRM(PP_Instance instance) { + return (new FlashDRMResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateFlashFontFile( + PP_Instance instance, + const PP_BrowserFont_Trusted_Description* description, + PP_PrivateFontCharset charset) { + return (new FlashFontFileResource( + GetConnection(), instance, description, charset))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateFlashMenu( + PP_Instance instance, + const PP_Flash_Menu* menu_data) { + scoped_refptr<FlashMenuResource> flash_menu( + new FlashMenuResource(GetConnection(), instance)); + if (!flash_menu->Initialize(menu_data)) + return 0; + return flash_menu->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateFlashMessageLoop( + PP_Instance instance) { + return PPB_Flash_MessageLoop_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateScrollbar(PP_Instance instance, + PP_Bool vertical) { + NOTIMPLEMENTED(); // Not proxied yet. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateTalk(PP_Instance instance) { + return (new TalkResource(GetConnection(), instance))->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateVideoCapture(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + return (new VideoCaptureResource(GetConnection(), instance, dispatcher)) + ->GetReference(); +} + +PP_Resource ResourceCreationProxy::CreateVideoDecoder( + PP_Instance instance, + PP_Resource context3d_id, + PP_VideoDecoder_Profile profile) { + return PPB_VideoDecoder_Proxy::CreateProxyResource( + instance, context3d_id, profile); +} + +#endif // !defined(OS_NACL) + +bool ResourceCreationProxy::Send(IPC::Message* msg) { + return dispatcher()->Send(msg); +} + +bool ResourceCreationProxy::OnMessageReceived(const IPC::Message& msg) { + return false; +} + +Connection ResourceCreationProxy::GetConnection() { + return Connection(PluginGlobals::Get()->GetBrowserSender(), dispatcher()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/resource_creation_proxy.h b/chromium/ppapi/proxy/resource_creation_proxy.h new file mode 100644 index 00000000000..47b40a83927 --- /dev/null +++ b/chromium/ppapi/proxy/resource_creation_proxy.h @@ -0,0 +1,191 @@ +// 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_PROXY_RESOURCE_CREATION_PROXY_H_ +#define PPAPI_PROXY_RESOURCE_CREATION_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ipc/ipc_channel.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/thunk/resource_creation_api.h" + +struct PP_Size; + +namespace ppapi { + +class HostResource; + +namespace proxy { + +struct Connection; +class Dispatcher; + +class ResourceCreationProxy : public InterfaceProxy, + public thunk::ResourceCreationAPI { + public: + explicit ResourceCreationProxy(Dispatcher* dispatcher); + virtual ~ResourceCreationProxy(); + + // Factory function used for registration (normal code can just use the + // constructor). + static InterfaceProxy* Create(Dispatcher* dispatcher); + + // ResourceCreationAPI (called in plugin). + virtual PP_Resource CreateFileIO(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateFileRef(PP_Instance instance, + PP_Resource file_system, + const char* path) OVERRIDE; + virtual PP_Resource CreateFileRef( + const PPB_FileRef_CreateInfo& create_info) OVERRIDE; + virtual PP_Resource CreateFileSystem(PP_Instance instance, + PP_FileSystemType type) OVERRIDE; + virtual PP_Resource CreateIsolatedFileSystem( + PP_Instance instance, + const char* fsid) 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 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 CreateTouchInputEvent( + PP_Instance instance, + PP_InputEvent_Type type, + PP_TimeTicks time_stamp, + uint32_t modifiers) OVERRIDE; + virtual PP_Resource CreateResourceArray(PP_Instance instance, + const PP_Resource elements[], + uint32_t size) OVERRIDE; + virtual PP_Resource CreateTrueTypeFont( + PP_Instance instance, + const PP_TrueTypeFontDesc_Dev* desc) OVERRIDE; + virtual PP_Resource CreateURLLoader(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateURLRequestInfo( + 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 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 CreateFileChooser(PP_Instance instance, + PP_FileChooserMode_Dev mode, + const PP_Var& accept_types) OVERRIDE; + virtual PP_Resource CreateGraphics2D(PP_Instance pp_instance, + const PP_Size* size, + PP_Bool is_always_opaque) 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 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 CreateNetworkMonitor( + PP_Instance instance, + PPB_NetworkMonitor_Callback callback, + void* user_data) OVERRIDE; + virtual PP_Resource CreatePrinting(PP_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 CreateVideoDestination(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateVideoSource(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateWebSocket(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateX509CertificatePrivate( + PP_Instance instance) OVERRIDE; +#if !defined(OS_NACL) + virtual PP_Resource CreateAudioInput(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateBroker(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateBrowserFont( + PP_Instance instance, + const PP_BrowserFont_Trusted_Description* description) OVERRIDE; + virtual PP_Resource CreateBuffer(PP_Instance instance, + uint32_t size) 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 CreateScrollbar(PP_Instance instance, + PP_Bool vertical) OVERRIDE; + virtual PP_Resource CreateTalk(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateVideoCapture(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateVideoDecoder( + PP_Instance instance, + PP_Resource context3d_id, + PP_VideoDecoder_Profile profile) OVERRIDE; +#endif // !defined(OS_NACL) + + virtual bool Send(IPC::Message* msg) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + Connection GetConnection(); + DISALLOW_COPY_AND_ASSIGN(ResourceCreationProxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_RESOURCE_CREATION_PROXY_H_ diff --git a/chromium/ppapi/proxy/resource_message_params.cc b/chromium/ppapi/proxy/resource_message_params.cc new file mode 100644 index 00000000000..e4858da55f3 --- /dev/null +++ b/chromium/ppapi/proxy/resource_message_params.cc @@ -0,0 +1,204 @@ +// 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 "ppapi/proxy/resource_message_params.h" + +#include "base/logging.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +ResourceMessageParams::SerializedHandles::SerializedHandles() + : should_close_(false) { +} + +ResourceMessageParams::SerializedHandles::~SerializedHandles() { + if (should_close_) { + for (std::vector<SerializedHandle>::iterator iter = data_.begin(); + iter != data_.end(); ++iter) { + iter->Close(); + } + } +} + +ResourceMessageParams::ResourceMessageParams() + : pp_resource_(0), + sequence_(0), + handles_(new SerializedHandles()) { +} + +ResourceMessageParams::ResourceMessageParams(PP_Resource resource, + int32_t sequence) + : pp_resource_(resource), + sequence_(sequence), + handles_(new SerializedHandles()) { +} + +ResourceMessageParams::~ResourceMessageParams() { +} + +void ResourceMessageParams::Serialize(IPC::Message* msg) const { + WriteHeader(msg); + WriteHandles(msg); +} + +bool ResourceMessageParams::Deserialize(const IPC::Message* msg, + PickleIterator* iter) { + return ReadHeader(msg, iter) && ReadHandles(msg, iter); +} + +void ResourceMessageParams::WriteHeader(IPC::Message* msg) const { + IPC::ParamTraits<PP_Resource>::Write(msg, pp_resource_); + IPC::ParamTraits<int32_t>::Write(msg, sequence_); +} + +void ResourceMessageParams::WriteHandles(IPC::Message* msg) const { + IPC::ParamTraits<std::vector<SerializedHandle> >::Write(msg, + handles_->data()); +} + +bool ResourceMessageParams::ReadHeader(const IPC::Message* msg, + PickleIterator* iter) { + DCHECK(handles_->data().empty()); + handles_->set_should_close(true); + return IPC::ParamTraits<PP_Resource>::Read(msg, iter, &pp_resource_) && + IPC::ParamTraits<int32_t>::Read(msg, iter, &sequence_); +} + +bool ResourceMessageParams::ReadHandles(const IPC::Message* msg, + PickleIterator* iter) { + return IPC::ParamTraits<std::vector<SerializedHandle> >::Read( + msg, iter, &handles_->data()); +} + +void ResourceMessageParams::ConsumeHandles() const { + // Note: we must not invalidate the handles. This is used for converting + // handles from the host OS to NaCl, and that conversion will not work if we + // invalidate the handles (see HandleConverter). + handles_->set_should_close(false); +} + +SerializedHandle ResourceMessageParams::TakeHandleOfTypeAtIndex( + size_t index, + SerializedHandle::Type type) const { + SerializedHandle handle; + std::vector<SerializedHandle>& data = handles_->data(); + if (index < data.size() && data[index].type() == type) { + handle = data[index]; + data[index] = SerializedHandle(); + } + return handle; +} + +bool ResourceMessageParams::TakeSharedMemoryHandleAtIndex( + size_t index, + base::SharedMemoryHandle* handle) const { + SerializedHandle serialized = TakeHandleOfTypeAtIndex( + index, SerializedHandle::SHARED_MEMORY); + if (!serialized.is_shmem()) + return false; + *handle = serialized.shmem(); + return true; +} + +bool ResourceMessageParams::TakeSocketHandleAtIndex( + size_t index, + IPC::PlatformFileForTransit* handle) const { + SerializedHandle serialized = TakeHandleOfTypeAtIndex( + index, SerializedHandle::SOCKET); + if (!serialized.is_socket()) + return false; + *handle = serialized.descriptor(); + return true; +} + +bool ResourceMessageParams::TakeFileHandleAtIndex( + size_t index, + IPC::PlatformFileForTransit* handle) const { + SerializedHandle serialized = TakeHandleOfTypeAtIndex( + index, SerializedHandle::FILE); + if (!serialized.is_file()) + return false; + *handle = serialized.descriptor(); + return true; +} + +void ResourceMessageParams::TakeAllSharedMemoryHandles( + std::vector<base::SharedMemoryHandle>* handles) const { + for (size_t i = 0; i < handles_->data().size(); ++i) { + base::SharedMemoryHandle handle; + if (TakeSharedMemoryHandleAtIndex(i, &handle)) + handles->push_back(handle); + } +} + +void ResourceMessageParams::AppendHandle(const SerializedHandle& handle) const { + handles_->data().push_back(handle); +} + +ResourceMessageCallParams::ResourceMessageCallParams() + : ResourceMessageParams(), + has_callback_(0) { +} + +ResourceMessageCallParams::ResourceMessageCallParams(PP_Resource resource, + int32_t sequence) + : ResourceMessageParams(resource, sequence), + has_callback_(0) { +} + +ResourceMessageCallParams::~ResourceMessageCallParams() { +} + +void ResourceMessageCallParams::Serialize(IPC::Message* msg) const { + ResourceMessageParams::Serialize(msg); + IPC::ParamTraits<bool>::Write(msg, has_callback_); +} + +bool ResourceMessageCallParams::Deserialize(const IPC::Message* msg, + PickleIterator* iter) { + if (!ResourceMessageParams::Deserialize(msg, iter)) + return false; + return IPC::ParamTraits<bool>::Read(msg, iter, &has_callback_); +} + +ResourceMessageReplyParams::ResourceMessageReplyParams() + : ResourceMessageParams(), + result_(PP_OK) { +} + +ResourceMessageReplyParams::ResourceMessageReplyParams(PP_Resource resource, + int32_t sequence) + : ResourceMessageParams(resource, sequence), + result_(PP_OK) { +} + +ResourceMessageReplyParams::~ResourceMessageReplyParams() { +} + +void ResourceMessageReplyParams::Serialize(IPC::Message* msg) const { + // Rather than serialize all of ResourceMessageParams first, we serialize all + // non-handle data first, then the handles. When transferring to NaCl on + // Windows, we need to be able to translate Windows-style handles to POSIX- + // style handles, and it's easier to put all the regular stuff at the front. + WriteReplyHeader(msg); + WriteHandles(msg); +} + +bool ResourceMessageReplyParams::Deserialize(const IPC::Message* msg, + PickleIterator* iter) { + return (ReadHeader(msg, iter) && + IPC::ParamTraits<int32_t>::Read(msg, iter, &result_) && + ReadHandles(msg, iter)); +} + +void ResourceMessageReplyParams::WriteReplyHeader(IPC::Message* msg) const { + WriteHeader(msg); + IPC::ParamTraits<int32_t>::Write(msg, result_); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/resource_message_params.h b/chromium/ppapi/proxy/resource_message_params.h new file mode 100644 index 00000000000..21b0f73800b --- /dev/null +++ b/chromium/ppapi/proxy/resource_message_params.h @@ -0,0 +1,211 @@ +// 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_PROXY_RESOURCE_MESSAGE_PARAMS_H_ +#define PPAPI_PROXY_RESOURCE_MESSAGE_PARAMS_H_ + +#include <vector> + +#include "base/memory/ref_counted.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/serialized_handle.h" + +namespace ppapi { +namespace proxy { + +// Common parameters for resource call and reply params structures below. +class PPAPI_PROXY_EXPORT ResourceMessageParams { + public: + virtual ~ResourceMessageParams(); + + PP_Resource pp_resource() const { return pp_resource_; } + int32_t sequence() const { return sequence_; } + + // Note that the caller doesn't take ownership of the returned handles. + const std::vector<SerializedHandle>& handles() const { + return handles_->data(); + } + + // Makes ResourceMessageParams leave its handles open, even if they weren't + // taken using a Take.* function. After this call, no Take.* calls are + // allowed. + void ConsumeHandles() const; + + // Returns the handle at the given index if it exists and is of the given + // type. The corresponding slot in the list is set to an invalid handle. + // If the index doesn't exist or the handle isn't of the given type, returns + // an invalid handle. + // Note that the caller is responsible for closing the returned handle, if it + // is valid. + SerializedHandle TakeHandleOfTypeAtIndex(size_t index, + SerializedHandle::Type type) const; + + // Helper functions to return shared memory, socket or file handles passed in + // the params struct. + // If the index has a valid handle of the given type, it will be placed in the + // output parameter, the corresponding slot in the list will be set to an + // invalid handle, and the function will return true. If the handle doesn't + // exist or is a different type, the functions will return false and the + // output parameter will be untouched. + // + // Note: 1) the handle could still be a "null" or invalid handle of the right + // type and the functions will succeed. + // 2) the caller is responsible for closing the returned handle, if it + // is valid. + bool TakeSharedMemoryHandleAtIndex(size_t index, + base::SharedMemoryHandle* handle) const; + bool TakeSocketHandleAtIndex(size_t index, + IPC::PlatformFileForTransit* handle) const; + bool TakeFileHandleAtIndex(size_t index, + IPC::PlatformFileForTransit* handle) const; + void TakeAllSharedMemoryHandles( + std::vector<base::SharedMemoryHandle>* handles) const; + + // Appends the given handle to the list of handles sent with the call or + // reply. + void AppendHandle(const SerializedHandle& handle) const; + + protected: + ResourceMessageParams(); + ResourceMessageParams(PP_Resource resource, int32_t sequence); + + virtual void Serialize(IPC::Message* msg) const; + virtual bool Deserialize(const IPC::Message* msg, PickleIterator* iter); + + // Writes everything except the handles to |msg|. + void WriteHeader(IPC::Message* msg) const; + // Writes the handles to |msg|. + void WriteHandles(IPC::Message* msg) const; + // Matching deserialize helpers. + bool ReadHeader(const IPC::Message* msg, PickleIterator* iter); + bool ReadHandles(const IPC::Message* msg, PickleIterator* iter); + + private: + class SerializedHandles + : public base::RefCountedThreadSafe<SerializedHandles> { + public: + SerializedHandles(); + ~SerializedHandles(); + + void set_should_close(bool value) { should_close_ = value; } + std::vector<SerializedHandle>& data() { return data_; } + + private: + friend class base::RefCountedThreadSafe<SerializedHandles>; + + // Whether the handles stored in |data_| should be closed when this object + // goes away. + // + // It is set to true by ResourceMessageParams::Deserialize(), so that the + // receiving side of the params (the host side for + // ResourceMessageCallParams; the plugin side for + // ResourceMessageReplyParams) will close those handles which haven't been + // taken using any of the Take*() methods. + bool should_close_; + std::vector<SerializedHandle> data_; + }; + + PP_Resource pp_resource_; + + // Identifier for this message. Sequence numbers are quasi-unique within a + // resource, but will overlap between different resource objects. + // + // If you send a lot of messages, the ID may wrap around. This is OK. All IDs + // are valid and 0 and -1 aren't special, so those cases won't confuse us. + // In practice, if you send more than 4 billion messages for a resource, the + // old ones will be long gone and there will be no collisions. + // + // If there is a malicious plugin (or exceptionally bad luck) that causes a + // wraparound and collision the worst that will happen is that we can get + // confused between different callbacks. But since these can only cause + // confusion within the plugin and within callbacks on the same resource, + // there shouldn't be a security problem. + int32_t sequence_; + + // A list of all handles transferred in the message. Handles go here so that + // the NaCl adapter can extract them generally when it rewrites them to + // go between Windows and NaCl (Posix) apps. + // TODO(yzshen): Mark it as mutable so that we can take/append handles using a + // const reference. We need to change all the callers and make it not mutable. + mutable scoped_refptr<SerializedHandles> handles_; +}; + +// Parameters common to all ResourceMessage "Call" requests. +class PPAPI_PROXY_EXPORT ResourceMessageCallParams + : public ResourceMessageParams { + public: + ResourceMessageCallParams(); + ResourceMessageCallParams(PP_Resource resource, int32_t sequence); + virtual ~ResourceMessageCallParams(); + + void set_has_callback() { has_callback_ = true; } + bool has_callback() const { return has_callback_; } + + virtual void Serialize(IPC::Message* msg) const OVERRIDE; + virtual bool Deserialize(const IPC::Message* msg, + PickleIterator* iter) OVERRIDE; + + private: + bool has_callback_; +}; + +// Parameters common to all ResourceMessage "Reply" requests. +class PPAPI_PROXY_EXPORT ResourceMessageReplyParams + : public ResourceMessageParams { + public: + ResourceMessageReplyParams(); + ResourceMessageReplyParams(PP_Resource resource, int32_t sequence); + virtual ~ResourceMessageReplyParams(); + + void set_result(int32_t r) { result_ = r; } + int32_t result() const { return result_; } + + virtual void Serialize(IPC::Message* msg) const OVERRIDE; + virtual bool Deserialize(const IPC::Message* msg, + PickleIterator* iter) OVERRIDE; + + // Writes everything except the handles to |msg|. + void WriteReplyHeader(IPC::Message* msg) const; + + private: + // Pepper "result code" for the callback. + int32_t result_; +}; + +} // namespace proxy +} // namespace ppapi + +namespace IPC { + +template <> struct PPAPI_PROXY_EXPORT +ParamTraits<ppapi::proxy::ResourceMessageCallParams> { + typedef ppapi::proxy::ResourceMessageCallParams param_type; + static void Write(Message* m, const param_type& p) { + p.Serialize(m); + } + static bool Read(const Message* m, PickleIterator* iter, param_type* r) { + return r->Deserialize(m, iter); + } + static void Log(const param_type& p, std::string* l) { + } +}; + +template <> struct PPAPI_PROXY_EXPORT +ParamTraits<ppapi::proxy::ResourceMessageReplyParams> { + typedef ppapi::proxy::ResourceMessageReplyParams param_type; + static void Write(Message* m, const param_type& p) { + p.Serialize(m); + } + static bool Read(const Message* m, PickleIterator* iter, param_type* r) { + return r->Deserialize(m, iter); + } + static void Log(const param_type& p, std::string* l) { + } +}; + +} // namespace IPC + +#endif // PPAPI_PROXY_RESOURCE_MESSAGE_PARAMS_H_ diff --git a/chromium/ppapi/proxy/resource_message_test_sink.cc b/chromium/ppapi/proxy/resource_message_test_sink.cc new file mode 100644 index 00000000000..e76e32ac88e --- /dev/null +++ b/chromium/ppapi/proxy/resource_message_test_sink.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/resource_message_test_sink.h" + +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/serialized_handle.h" + +namespace ppapi { +namespace proxy { + +namespace { + +// Backend for GetFirstResource[Call|Reply]Matching. +template<class WrapperMessage, class Params> +bool GetFirstResourceMessageMatching(const ResourceMessageTestSink& sink, + uint32 id, + Params* params, + IPC::Message* nested_msg) { + for (size_t i = 0; i < sink.message_count(); i++) { + const IPC::Message* msg = sink.GetMessageAt(i); + if (msg->type() == WrapperMessage::ID) { + Params cur_params; + IPC::Message cur_msg; + WrapperMessage::Read(msg, &cur_params, &cur_msg); + if (cur_msg.type() == id) { + *params = cur_params; + *nested_msg = cur_msg; + return true; + } + } + } + return false; +} + +} // namespace + +ResourceMessageTestSink::ResourceMessageTestSink() { +} + +ResourceMessageTestSink::~ResourceMessageTestSink() { +} + +bool ResourceMessageTestSink::Send(IPC::Message* msg) { + int message_id = 0; + scoped_ptr<IPC::MessageReplyDeserializer> reply_deserializer; + if (msg->is_sync()) { + reply_deserializer.reset( + static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer()); + message_id = IPC::SyncMessage::GetMessageId(*msg); + } + bool result = IPC::TestSink::Send(msg); // Deletes |msg|. + if (sync_reply_msg_.get()) { + // |sync_reply_msg_| should always be a reply to the pending sync message. + DCHECK(IPC::SyncMessage::IsMessageReplyTo(*sync_reply_msg_.get(), + message_id)); + reply_deserializer->SerializeOutputParameters(*sync_reply_msg_.get()); + sync_reply_msg_.reset(NULL); + } + return result; +} + +void ResourceMessageTestSink::SetSyncReplyMessage(IPC::Message* reply_msg) { + DCHECK(!sync_reply_msg_.get()); + sync_reply_msg_.reset(reply_msg); +} + +bool ResourceMessageTestSink::GetFirstResourceCallMatching( + uint32 id, + ResourceMessageCallParams* params, + IPC::Message* nested_msg) const { + return GetFirstResourceMessageMatching<PpapiHostMsg_ResourceCall, + ResourceMessageCallParams>( + *this, id, params, nested_msg); +} + +bool ResourceMessageTestSink::GetFirstResourceReplyMatching( + uint32 id, + ResourceMessageReplyParams* params, + IPC::Message* nested_msg) { + return GetFirstResourceMessageMatching<PpapiPluginMsg_ResourceReply, + ResourceMessageReplyParams>( + *this, id, params, nested_msg); +} + +ResourceSyncCallHandler::ResourceSyncCallHandler( + ResourceMessageTestSink* test_sink, + uint32 incoming_type, + int32_t result, + const IPC::Message& reply_msg) + : test_sink_(test_sink), + incoming_type_(incoming_type), + result_(result), + serialized_handle_(NULL), + reply_msg_(reply_msg) { +} + +ResourceSyncCallHandler::~ResourceSyncCallHandler() { +} + +bool ResourceSyncCallHandler::OnMessageReceived(const IPC::Message& msg) { + if (msg.type() != PpapiHostMsg_ResourceSyncCall::ID) + return false; + PpapiHostMsg_ResourceSyncCall::Schema::SendParam send_params; + bool success = PpapiHostMsg_ResourceSyncCall::ReadSendParam( + &msg, &send_params); + DCHECK(success); + ResourceMessageCallParams call_params = send_params.a; + IPC::Message call_msg = send_params.b; + if (call_msg.type() != incoming_type_) + return false; + IPC::Message* wrapper_reply_msg = IPC::SyncMessage::GenerateReply(&msg); + ResourceMessageReplyParams reply_params(call_params.pp_resource(), + call_params.sequence()); + reply_params.set_result(result_); + if (serialized_handle_) + reply_params.AppendHandle(*serialized_handle_); + PpapiHostMsg_ResourceSyncCall::WriteReplyParams( + wrapper_reply_msg, reply_params, reply_msg_); + test_sink_->SetSyncReplyMessage(wrapper_reply_msg); + + // Stash a copy of the message for inspection later. + last_handled_msg_ = call_msg; + return true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/resource_message_test_sink.h b/chromium/ppapi/proxy/resource_message_test_sink.h new file mode 100644 index 00000000000..cbbece3134d --- /dev/null +++ b/chromium/ppapi/proxy/resource_message_test_sink.h @@ -0,0 +1,99 @@ +// 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_PROXY_RESOURCE_MESSAGE_TEST_SINK_H_ +#define PPAPI_PROXY_RESOURCE_MESSAGE_TEST_SINK_H_ + +#include "ipc/ipc_listener.h" +#include "ipc/ipc_test_sink.h" +#include "ppapi/c/pp_stdint.h" + +namespace ppapi { +namespace proxy { + +class ResourceMessageCallParams; +class ResourceMessageReplyParams; +class SerializedHandle; + +// Extends IPC::TestSink to add extra capabilities for searching for and +// decoding resource messages. +class ResourceMessageTestSink : public IPC::TestSink { + public: + ResourceMessageTestSink(); + virtual ~ResourceMessageTestSink(); + + // IPC::TestSink. + // Overridden to handle sync messages. + virtual bool Send(IPC::Message* msg) OVERRIDE; + + // Sets the reply message that will be returned to the next sync message sent. + // This test sink owns any reply messages passed into this method. + void SetSyncReplyMessage(IPC::Message* reply_msg); + + // Searches the queue for the first resource call message with a nested + // message matching the given ID. On success, returns true and populates the + // givem params and nested message. + bool GetFirstResourceCallMatching( + uint32 id, + ResourceMessageCallParams* params, + IPC::Message* nested_msg) const; + + // Like GetFirstResourceCallMatching except for replies. + bool GetFirstResourceReplyMatching( + uint32 id, + ResourceMessageReplyParams* params, + IPC::Message* nested_msg); + + private: + scoped_ptr<IPC::Message> sync_reply_msg_; +}; + +// This is a message handler which generates reply messages for synchronous +// resource calls. This allows unit testing of the plugin side of resources +// which send sync messages. If you want to reply to a sync message type named +// |PpapiHostMsg_X_Y| with |PpapiPluginMsg_X_YReply| then usage would be as +// follows (from within |PluginProxyTest|s): +// +// PpapiHostMsg_X_YReply my_reply; +// ResourceSyncCallHandler handler(&sink(), +// PpapiHostMsg_X_Y::ID, +// PP_OK, +// my_reply); +// sink().AddFilter(&handler); +// // Do stuff to send a sync message ... +// // You can check handler.last_handled_msg() to ensure the correct message was +// // handled. +// sink().RemoveFilter(&handler); +class ResourceSyncCallHandler : public IPC::Listener { + public: + ResourceSyncCallHandler(ResourceMessageTestSink* test_sink, + uint32 incoming_type, + int32_t result, + const IPC::Message& reply_msg); + virtual ~ResourceSyncCallHandler(); + + // IPC::Listener. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + IPC::Message last_handled_msg() { return last_handled_msg_; } + + // Sets a handle to be appended to the ReplyParams. The pointer is owned by + // the caller. + void set_serialized_handle(const SerializedHandle* serialized_handle) { + serialized_handle_ = serialized_handle; + } + + private: + ResourceMessageTestSink* test_sink_; + uint32 incoming_type_; + int32_t result_; + const SerializedHandle* serialized_handle_; // Non-owning pointer. + IPC::Message reply_msg_; + IPC::Message last_handled_msg_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_RESOURCE_MESSAGE_TEST_SINK_H_ diff --git a/chromium/ppapi/proxy/run_all_unittests.cc b/chromium/ppapi/proxy/run_all_unittests.cc new file mode 100644 index 00000000000..7fd6ef2e80e --- /dev/null +++ b/chromium/ppapi/proxy/run_all_unittests.cc @@ -0,0 +1,9 @@ +// 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 "base/test/test_suite.h" + +int main(int argc, char** argv) { + return base::TestSuite(argc, argv).Run(); +} diff --git a/chromium/ppapi/proxy/serialized_flash_menu.cc b/chromium/ppapi/proxy/serialized_flash_menu.cc new file mode 100644 index 00000000000..bbd698cc7b4 --- /dev/null +++ b/chromium/ppapi/proxy/serialized_flash_menu.cc @@ -0,0 +1,181 @@ +// 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 "ppapi/proxy/serialized_flash_menu.h" + +#include "ipc/ipc_message.h" +#include "ppapi/c/private/ppb_flash_menu.h" +#include "ppapi/proxy/ppapi_param_traits.h" + +namespace ppapi { +namespace proxy { + +namespace { +// Maximum depth of submenus allowed (e.g., 1 indicates that submenus are +// allowed, but not sub-submenus). +const int kMaxMenuDepth = 2; +const uint32_t kMaxMenuEntries = 1000; + +bool CheckMenu(int depth, const PP_Flash_Menu* menu); +void FreeMenu(const PP_Flash_Menu* menu); +void WriteMenu(IPC::Message* m, const PP_Flash_Menu* menu); +PP_Flash_Menu* ReadMenu(int depth, const IPC::Message* m, PickleIterator* iter); + +bool CheckMenuItem(int depth, const PP_Flash_MenuItem* item) { + if (item->type == PP_FLASH_MENUITEM_TYPE_SUBMENU) + return CheckMenu(depth, item->submenu); + return true; +} + +bool CheckMenu(int depth, const PP_Flash_Menu* menu) { + if (depth > kMaxMenuDepth || !menu) + return false; + ++depth; + + if (menu->count && !menu->items) + return false; + + for (uint32_t i = 0; i < menu->count; ++i) { + if (!CheckMenuItem(depth, menu->items + i)) + return false; + } + return true; +} + +void WriteMenuItem(IPC::Message* m, const PP_Flash_MenuItem* menu_item) { + PP_Flash_MenuItem_Type type = menu_item->type; + m->WriteUInt32(type); + m->WriteString(menu_item->name ? menu_item->name : ""); + m->WriteInt(menu_item->id); + IPC::ParamTraits<PP_Bool>::Write(m, menu_item->enabled); + IPC::ParamTraits<PP_Bool>::Write(m, menu_item->checked); + if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) + WriteMenu(m, menu_item->submenu); +} + +void WriteMenu(IPC::Message* m, const PP_Flash_Menu* menu) { + m->WriteUInt32(menu->count); + for (uint32_t i = 0; i < menu->count; ++i) + WriteMenuItem(m, menu->items + i); +} + +void FreeMenuItem(const PP_Flash_MenuItem* menu_item) { + if (menu_item->name) + delete [] menu_item->name; + if (menu_item->submenu) + FreeMenu(menu_item->submenu); +} + +void FreeMenu(const PP_Flash_Menu* menu) { + if (menu->items) { + for (uint32_t i = 0; i < menu->count; ++i) + FreeMenuItem(menu->items + i); + delete [] menu->items; + } + delete menu; +} + +bool ReadMenuItem(int depth, + const IPC::Message* m, + PickleIterator* iter, + PP_Flash_MenuItem* menu_item) { + uint32_t type; + if (!m->ReadUInt32(iter, &type)) + return false; + if (type > PP_FLASH_MENUITEM_TYPE_SUBMENU) + return false; + menu_item->type = static_cast<PP_Flash_MenuItem_Type>(type); + std::string name; + if (!m->ReadString(iter, &name)) + return false; + menu_item->name = new char[name.size() + 1]; + std::copy(name.begin(), name.end(), menu_item->name); + menu_item->name[name.size()] = 0; + if (!m->ReadInt(iter, &menu_item->id)) + return false; + if (!IPC::ParamTraits<PP_Bool>::Read(m, iter, &menu_item->enabled)) + return false; + if (!IPC::ParamTraits<PP_Bool>::Read(m, iter, &menu_item->checked)) + return false; + if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) { + menu_item->submenu = ReadMenu(depth, m, iter); + if (!menu_item->submenu) + return false; + } + return true; +} + +PP_Flash_Menu* ReadMenu(int depth, + const IPC::Message* m, + PickleIterator* iter) { + if (depth > kMaxMenuDepth) + return NULL; + ++depth; + + PP_Flash_Menu* menu = new PP_Flash_Menu; + menu->items = NULL; + + if (!m->ReadUInt32(iter, &menu->count)) { + FreeMenu(menu); + return NULL; + } + + if (menu->count == 0) + return menu; + + if (menu->count > kMaxMenuEntries) { + FreeMenu(menu); + return NULL; + } + + menu->items = new PP_Flash_MenuItem[menu->count]; + memset(menu->items, 0, sizeof(PP_Flash_MenuItem) * menu->count); + for (uint32_t i = 0; i < menu->count; ++i) { + if (!ReadMenuItem(depth, m, iter, menu->items + i)) { + FreeMenu(menu); + return NULL; + } + } + return menu; +} + +} // anonymous namespace + +SerializedFlashMenu::SerializedFlashMenu() + : pp_menu_(NULL), + own_menu_(false) { +} + +SerializedFlashMenu::~SerializedFlashMenu() { + if (own_menu_) + FreeMenu(pp_menu_); +} + +bool SerializedFlashMenu::SetPPMenu(const PP_Flash_Menu* menu) { + DCHECK(!pp_menu_); + if (!CheckMenu(0, menu)) + return false; + pp_menu_ = menu; + own_menu_ = false; + return true; +} + + +void SerializedFlashMenu::WriteToMessage(IPC::Message* m) const { + WriteMenu(m, pp_menu_); +} + +bool SerializedFlashMenu::ReadFromMessage(const IPC::Message* m, + PickleIterator* iter) { + DCHECK(!pp_menu_); + pp_menu_ = ReadMenu(0, m, iter); + if (!pp_menu_) + return false; + + own_menu_ = true; + return true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/serialized_flash_menu.h b/chromium/ppapi/proxy/serialized_flash_menu.h new file mode 100644 index 00000000000..271caba368b --- /dev/null +++ b/chromium/ppapi/proxy/serialized_flash_menu.h @@ -0,0 +1,46 @@ +// 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_PROXY_SERIALIZED_FLASH_MENU_H_ +#define PPAPI_PROXY_SERIALIZED_FLASH_MENU_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +class PickleIterator; + +struct PP_Flash_Menu; + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT SerializedFlashMenu { + public: + SerializedFlashMenu(); + ~SerializedFlashMenu(); + + bool SetPPMenu(const PP_Flash_Menu* menu); + + const PP_Flash_Menu* pp_menu() const { return pp_menu_; } + + void WriteToMessage(IPC::Message* m) const; + bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter); + + private: + const PP_Flash_Menu* pp_menu_; + bool own_menu_; + DISALLOW_COPY_AND_ASSIGN(SerializedFlashMenu); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_SERIALIZED_FLASH_MENU_H_ diff --git a/chromium/ppapi/proxy/serialized_handle.cc b/chromium/ppapi/proxy/serialized_handle.cc new file mode 100644 index 00000000000..c9ce13b41a9 --- /dev/null +++ b/chromium/ppapi/proxy/serialized_handle.cc @@ -0,0 +1,143 @@ +// 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 "ppapi/proxy/serialized_handle.h" + +#include "base/memory/shared_memory.h" +#include "base/pickle.h" +#include "base/platform_file.h" +#include "build/build_config.h" +#include "ipc/ipc_platform_file.h" + +#if defined(OS_NACL) +#include <unistd.h> +#endif + +namespace ppapi { +namespace proxy { + +SerializedHandle::SerializedHandle() + : type_(INVALID), + shm_handle_(base::SharedMemory::NULLHandle()), + size_(0), + descriptor_(IPC::InvalidPlatformFileForTransit()) { +} + +SerializedHandle::SerializedHandle(Type type_param) + : type_(type_param), + shm_handle_(base::SharedMemory::NULLHandle()), + size_(0), + descriptor_(IPC::InvalidPlatformFileForTransit()) { +} + +SerializedHandle::SerializedHandle(const base::SharedMemoryHandle& handle, + uint32 size) + : type_(SHARED_MEMORY), + shm_handle_(handle), + size_(size), + descriptor_(IPC::InvalidPlatformFileForTransit()) { +} + +SerializedHandle::SerializedHandle( + Type type, + const IPC::PlatformFileForTransit& socket_descriptor) + : type_(type), + shm_handle_(base::SharedMemory::NULLHandle()), + size_(0), + descriptor_(socket_descriptor) { +} + +bool SerializedHandle::IsHandleValid() const { + switch (type_) { + case SHARED_MEMORY: + return base::SharedMemory::IsHandleValid(shm_handle_); + case SOCKET: + case CHANNEL_HANDLE: + case FILE: + return !(IPC::InvalidPlatformFileForTransit() == descriptor_); + case INVALID: + return false; + // No default so the compiler will warn us if a new type is added. + } + return false; +} + +void SerializedHandle::Close() { + if (IsHandleValid()) { + switch (type_) { + case INVALID: + NOTREACHED(); + break; + case SHARED_MEMORY: + base::SharedMemory::CloseHandle(shm_handle_); + break; + case SOCKET: + case CHANNEL_HANDLE: + case FILE: + base::PlatformFile file = + IPC::PlatformFileForTransitToPlatformFile(descriptor_); +#if !defined(OS_NACL) + base::ClosePlatformFile(file); +#else + close(file); +#endif + break; + // No default so the compiler will warn us if a new type is added. + } + } + *this = SerializedHandle(); +} + +// static +bool SerializedHandle::WriteHeader(const Header& hdr, Pickle* pickle) { + if (!pickle->WriteInt(hdr.type)) + return false; + if (hdr.type == SHARED_MEMORY) { + if (!pickle->WriteUInt32(hdr.size)) + return false; + } + if (hdr.type == FILE) { + if (!pickle->WriteInt(hdr.open_flag)) + return false; + } + return true; +} + +// static +bool SerializedHandle::ReadHeader(PickleIterator* iter, Header* hdr) { + *hdr = Header(INVALID, 0, 0); + int type = 0; + if (!iter->ReadInt(&type)) + return false; + bool valid_type = false; + switch (type) { + case SHARED_MEMORY: { + uint32 size = 0; + if (!iter->ReadUInt32(&size)) + return false; + hdr->size = size; + valid_type = true; + break; + } + case FILE: { + int open_flag = 0; + if (!iter->ReadInt(&open_flag)) + return false; + hdr->open_flag = open_flag; + valid_type = true; + } + case SOCKET: + case CHANNEL_HANDLE: + case INVALID: + valid_type = true; + break; + // No default so the compiler will warn us if a new type is added. + } + if (valid_type) + hdr->type = Type(type); + return valid_type; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/serialized_handle.h b/chromium/ppapi/proxy/serialized_handle.h new file mode 100644 index 00000000000..91efa075b5d --- /dev/null +++ b/chromium/ppapi/proxy/serialized_handle.h @@ -0,0 +1,150 @@ +// 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 PPAPI_PROXY_SERIALIZED_HANDLES_H_ +#define PPAPI_PROXY_SERIALIZED_HANDLES_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/shared_memory.h" +#include "build/build_config.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/proxy/ppapi_proxy_export.h" + +class Pickle; + +namespace ppapi { +namespace proxy { + +// SerializedHandle is a unified structure for holding a handle (e.g., a shared +// memory handle, socket descriptor, etc). This is useful for passing handles in +// resource messages and also makes it easier to translate handles in +// NaClIPCAdapter for use in NaCl. +class PPAPI_PROXY_EXPORT SerializedHandle { + public: + enum Type { INVALID, SHARED_MEMORY, SOCKET, CHANNEL_HANDLE, FILE }; + struct Header { + Header() : type(INVALID), size(0), open_flag(0) {} + Header(Type type_arg, uint32 size_arg, int32 open_flag_arg) + : type(type_arg), size(size_arg), open_flag(open_flag_arg) { + } + Type type; + uint32 size; + int32 open_flag; + }; + + SerializedHandle(); + // Create an invalid handle of the given type. + explicit SerializedHandle(Type type); + + // Create a shared memory handle. + SerializedHandle(const base::SharedMemoryHandle& handle, uint32 size); + + // Create a socket, channel or file handle. + SerializedHandle(const Type type, + const IPC::PlatformFileForTransit& descriptor); + + Type type() const { return type_; } + bool is_shmem() const { return type_ == SHARED_MEMORY; } + bool is_socket() const { return type_ == SOCKET; } + bool is_channel_handle() const { return type_ == CHANNEL_HANDLE; } + bool is_file() const { return type_ == FILE; } + const base::SharedMemoryHandle& shmem() const { + DCHECK(is_shmem()); + return shm_handle_; + } + uint32 size() const { + DCHECK(is_shmem()); + return size_; + } + const IPC::PlatformFileForTransit& descriptor() const { + DCHECK(is_socket() || is_channel_handle() || is_file()); + return descriptor_; + } + int32 open_flag() const { + return open_flag_; + } + void set_shmem(const base::SharedMemoryHandle& handle, uint32 size) { + type_ = SHARED_MEMORY; + shm_handle_ = handle; + size_ = size; + + descriptor_ = IPC::InvalidPlatformFileForTransit(); + } + void set_socket(const IPC::PlatformFileForTransit& socket) { + type_ = SOCKET; + descriptor_ = socket; + + shm_handle_ = base::SharedMemory::NULLHandle(); + size_ = 0; + } + void set_channel_handle(const IPC::PlatformFileForTransit& descriptor) { + type_ = CHANNEL_HANDLE; + + descriptor_ = descriptor; + shm_handle_ = base::SharedMemory::NULLHandle(); + size_ = 0; + } + void set_file_handle(const IPC::PlatformFileForTransit& descriptor, + int32 open_flag) { + type_ = FILE; + + descriptor_ = descriptor; + shm_handle_ = base::SharedMemory::NULLHandle(); + size_ = 0; + open_flag_ = open_flag; + } + void set_null_shmem() { + set_shmem(base::SharedMemory::NULLHandle(), 0); + } + void set_null_socket() { + set_socket(IPC::InvalidPlatformFileForTransit()); + } + void set_null_channel_handle() { + set_channel_handle(IPC::InvalidPlatformFileForTransit()); + } + void set_null_file_handle() { + set_file_handle(IPC::InvalidPlatformFileForTransit(), 0); + } + bool IsHandleValid() const; + + Header header() const { + return Header(type_, size_, open_flag_); + } + + // Closes the handle and sets it to invalid. + void Close(); + + // Write/Read a Header, which contains all the data except the handle. This + // allows us to write the handle in a platform-specific way, as is necessary + // in NaClIPCAdapter to share handles with NaCl from Windows. + static bool WriteHeader(const Header& hdr, Pickle* pickle); + static bool ReadHeader(PickleIterator* iter, Header* hdr); + + private: + // The kind of handle we're holding. + Type type_; + + // We hold more members than we really need; we can't easily use a union, + // because we hold non-POD types. But these types are pretty light-weight. If + // we add more complex things later, we should come up with a more memory- + // efficient strategy. + // These are valid if type == SHARED_MEMORY. + base::SharedMemoryHandle shm_handle_; + uint32 size_; + + // This is valid if type == SOCKET || type == CHANNEL_HANDLE || type == FILE. + IPC::PlatformFileForTransit descriptor_; + + // This is valid if type == FILE. + int32 open_flag_; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_SERIALIZED_HANDLES_H_ diff --git a/chromium/ppapi/proxy/serialized_structs.cc b/chromium/ppapi/proxy/serialized_structs.cc new file mode 100644 index 00000000000..8c984d55dba --- /dev/null +++ b/chromium/ppapi/proxy/serialized_structs.cc @@ -0,0 +1,133 @@ +// 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 "ppapi/proxy/serialized_structs.h" + +#include "base/pickle.h" +#include "build/build_config.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/trusted/ppb_browser_font_trusted.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { +namespace proxy { + +SerializedFontDescription::SerializedFontDescription() + : face(), + family(0), + size(0), + weight(0), + italic(PP_FALSE), + small_caps(PP_FALSE), + letter_spacing(0), + word_spacing(0) { +} + +SerializedFontDescription::~SerializedFontDescription() {} + +void SerializedFontDescription::SetFromPPFontDescription( + const PP_FontDescription_Dev& desc) { + StringVar* string_var = StringVar::FromPPVar(desc.face); + face = string_var ? string_var->value() : std::string(); + + family = desc.family; + size = desc.size; + weight = desc.weight; + italic = desc.italic; + small_caps = desc.small_caps; + letter_spacing = desc.letter_spacing; + word_spacing = desc.word_spacing; +} + +void SerializedFontDescription::SetFromPPBrowserFontDescription( + const PP_BrowserFont_Trusted_Description& desc) { + StringVar* string_var = StringVar::FromPPVar(desc.face); + face = string_var ? string_var->value() : std::string(); + + family = desc.family; + size = desc.size; + weight = desc.weight; + italic = desc.italic; + small_caps = desc.small_caps; + letter_spacing = desc.letter_spacing; + word_spacing = desc.word_spacing; +} + +void SerializedFontDescription::SetToPPFontDescription( + PP_FontDescription_Dev* desc) const { + desc->face = StringVar::StringToPPVar(face); + desc->family = static_cast<PP_FontFamily_Dev>(family); + desc->size = size; + desc->weight = static_cast<PP_FontWeight_Dev>(weight); + desc->italic = italic; + desc->small_caps = small_caps; + desc->letter_spacing = letter_spacing; + desc->word_spacing = word_spacing; +} + +void SerializedFontDescription::SetToPPBrowserFontDescription( + PP_BrowserFont_Trusted_Description* desc) const { + desc->face = StringVar::StringToPPVar(face); + desc->family = static_cast<PP_BrowserFont_Trusted_Family>(family); + desc->size = size; + desc->weight = static_cast<PP_BrowserFont_Trusted_Weight>(weight); + desc->italic = italic; + desc->small_caps = small_caps; + desc->letter_spacing = letter_spacing; + desc->word_spacing = word_spacing; +} + +SerializedTrueTypeFontDesc::SerializedTrueTypeFontDesc() + : family(), + generic_family(), + style(), + weight(), + width(), + charset() { +} + +SerializedTrueTypeFontDesc::~SerializedTrueTypeFontDesc() {} + +void SerializedTrueTypeFontDesc::SetFromPPTrueTypeFontDesc( + const PP_TrueTypeFontDesc_Dev& desc) { + StringVar* string_var = StringVar::FromPPVar(desc.family); + family = string_var ? string_var->value() : std::string(); + + generic_family = desc.generic_family; + style = desc.style; + weight = desc.weight; + width = desc.width; + charset = desc.charset; +} + +void SerializedTrueTypeFontDesc::CopyToPPTrueTypeFontDesc( + PP_TrueTypeFontDesc_Dev* desc) const { + desc->family = StringVar::StringToPPVar(family); + + desc->generic_family = generic_family; + desc->style = style; + desc->weight = weight; + desc->width = width; + desc->charset = charset; +} + +PPBFlash_DrawGlyphs_Params::PPBFlash_DrawGlyphs_Params() + : instance(0), + font_desc(), + color(0) { + clip.point.x = 0; + clip.point.y = 0; + clip.size.height = 0; + clip.size.width = 0; + position.x = 0; + position.y = 0; + allow_subpixel_aa = PP_FALSE; +} + +PPBFlash_DrawGlyphs_Params::~PPBFlash_DrawGlyphs_Params() {} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/serialized_structs.h b/chromium/ppapi/proxy/serialized_structs.h new file mode 100644 index 00000000000..1f89ae2047c --- /dev/null +++ b/chromium/ppapi/proxy/serialized_structs.h @@ -0,0 +1,133 @@ +// 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_PROXY_SERIALIZED_STRUCTS_H_ +#define PPAPI_PROXY_SERIALIZED_STRUCTS_H_ + +#include <string> +#include <vector> + +#include "base/logging.h" +#include "base/memory/shared_memory.h" +#include "build/build_config.h" +#include "ppapi/c/dev/ppb_truetype_font_dev.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/host_resource.h" + +class Pickle; +struct PP_FontDescription_Dev; +struct PP_BrowserFont_Trusted_Description; + +namespace ppapi { +namespace proxy { + +// PP_FontDescription_Dev/PP_BrowserFontDescription (same definition, different +// names) has to be redefined with a string in place of the PP_Var used for the +// face name. +struct PPAPI_PROXY_EXPORT SerializedFontDescription { + SerializedFontDescription(); + ~SerializedFontDescription(); + + // Converts a PP_FontDescription_Dev to a SerializedFontDescription. + // + // The reference of |face| owned by the PP_FontDescription_Dev will be + // unchanged and the caller is responsible for freeing it. + void SetFromPPFontDescription(const PP_FontDescription_Dev& desc); + void SetFromPPBrowserFontDescription( + const PP_BrowserFont_Trusted_Description& desc); + + // Converts to a PP_FontDescription_Dev. The face name will have one ref + // assigned to it. The caller is responsible for freeing it. + void SetToPPFontDescription(PP_FontDescription_Dev* desc) const; + void SetToPPBrowserFontDescription( + PP_BrowserFont_Trusted_Description* desc) const; + + std::string face; + int32_t family; + uint32_t size; + int32_t weight; + PP_Bool italic; + PP_Bool small_caps; + int32_t letter_spacing; + int32_t word_spacing; +}; + +struct PPAPI_PROXY_EXPORT SerializedTrueTypeFontDesc { + SerializedTrueTypeFontDesc(); + ~SerializedTrueTypeFontDesc(); + + // Sets this to correspond to the contents of a PP_TrueTypeFontDesc_Dev. + // + // The reference count of the desc.family PP_Var will be unchanged and the + // caller is responsible for releasing it. + void SetFromPPTrueTypeFontDesc(const PP_TrueTypeFontDesc_Dev& desc); + + // Converts this to a PP_FontDescription_Dev. + // + // The desc.family PP_Var will have one reference assigned to it. The caller + // is responsible for releasing it. + void CopyToPPTrueTypeFontDesc(PP_TrueTypeFontDesc_Dev* desc) const; + + std::string family; + PP_TrueTypeFontFamily_Dev generic_family; + PP_TrueTypeFontStyle_Dev style; + PP_TrueTypeFontWeight_Dev weight; + PP_TrueTypeFontWidth_Dev width; + PP_TrueTypeFontCharset_Dev charset; +}; + +struct SerializedDirEntry { + std::string name; + bool is_dir; +}; + +struct PPAPI_PROXY_EXPORT PPBFlash_DrawGlyphs_Params { + PPBFlash_DrawGlyphs_Params(); + ~PPBFlash_DrawGlyphs_Params(); + + PP_Instance instance; + ppapi::HostResource image_data; + SerializedFontDescription font_desc; + uint32_t color; + PP_Point position; + PP_Rect clip; + float transformation[3][3]; + PP_Bool allow_subpixel_aa; + std::vector<uint16_t> glyph_indices; + std::vector<PP_Point> glyph_advances; +}; + +struct PPBURLLoader_UpdateProgress_Params { + PP_Instance instance; + ppapi::HostResource resource; + int64_t bytes_sent; + int64_t total_bytes_to_be_sent; + int64_t bytes_received; + int64_t total_bytes_to_be_received; +}; + +struct PPPDecryptor_Buffer { + ppapi::HostResource resource; + uint32_t size; + base::SharedMemoryHandle handle; +}; + +// TODO(raymes): Make ImageHandle compatible with SerializedHandle. +#if defined(OS_WIN) +typedef HANDLE ImageHandle; +#elif defined(TOOLKIT_GTK) +// On legacy X Windows this is a SysV shared memory key. +typedef int ImageHandle; +#else +typedef base::SharedMemoryHandle ImageHandle; +#endif + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_SERIALIZED_STRUCTS_H_ diff --git a/chromium/ppapi/proxy/serialized_var.cc b/chromium/ppapi/proxy/serialized_var.cc new file mode 100644 index 00000000000..72e7cc8ecbb --- /dev/null +++ b/chromium/ppapi/proxy/serialized_var.cc @@ -0,0 +1,467 @@ +// 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 "ppapi/proxy/serialized_var.h" + +#include "base/logging.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" + +namespace ppapi { +namespace proxy { + +namespace { +void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { + IPC::ParamTraits<SerializedHandle>::Write(m, handle); +} +} // namespace + +// SerializedVar::Inner -------------------------------------------------------- + +SerializedVar::Inner::Inner() + : serialization_rules_(NULL), + var_(PP_MakeUndefined()), + instance_(0), + cleanup_mode_(CLEANUP_NONE), + is_valid_var_(true) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules) + : serialization_rules_(serialization_rules), + var_(PP_MakeUndefined()), + instance_(0), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::~Inner() { + switch (cleanup_mode_) { + case END_SEND_PASS_REF: + serialization_rules_->EndSendPassRef(var_); + break; + case END_RECEIVE_CALLER_OWNED: + serialization_rules_->EndReceiveCallerOwned(var_); + break; + default: + break; + } +} + +PP_Var SerializedVar::Inner::GetVar() { + DCHECK(serialization_rules_.get()); + +#if defined(NACL_WIN64) + NOTREACHED(); + return PP_MakeUndefined(); +#endif + + if (raw_var_data_.get()) { + var_ = raw_var_data_->CreatePPVar(instance_); + raw_var_data_.reset(NULL); + } + + return var_; +} + +void SerializedVar::Inner::SetVar(PP_Var var) { + // Sanity check, when updating the var we should have received a + // serialization rules pointer already. + DCHECK(serialization_rules_.get()); + var_ = var; + raw_var_data_.reset(NULL); +} + +void SerializedVar::Inner::SetInstance(PP_Instance instance) { + instance_ = instance; +} + +void SerializedVar::Inner::ForceSetVarValueForTest(PP_Var value) { + var_ = value; + raw_var_data_.reset(NULL); +} + +void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { + // When writing to the IPC messages, a serialization rules handler should + // always have been set. + // + // When sending a message, it should be difficult to trigger this if you're + // using the SerializedVarSendInput class and giving a non-NULL dispatcher. + // Make sure you're using the proper "Send" helper class. + // + // It should be more common to see this when handling an incoming message + // that returns a var. This means the message handler didn't write to the + // output parameter, or possibly you used the wrong helper class + // (normally SerializedVarReturnValue). + DCHECK(serialization_rules_.get()); + +#ifndef NDEBUG + // We should only be serializing something once. + DCHECK(!has_been_serialized_); + has_been_serialized_ = true; +#endif + scoped_ptr<RawVarDataGraph> data = RawVarDataGraph::Create(var_, instance_); + if (data) { + m->WriteBool(true); // Success. + data->Write(m, base::Bind(&DefaultHandleWriter)); + } else { + m->WriteBool(false); // Failure. + } +} + +void SerializedVar::Inner::WriteDataToMessage( + IPC::Message* m, + const HandleWriter& handle_writer) const { + if (raw_var_data_) { + m->WriteBool(true); // Success. + raw_var_data_->Write(m, handle_writer); + } else { + m->WriteBool(false); // Failure. + } +} + +bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, + PickleIterator* iter) { +#ifndef NDEBUG + // We should only deserialize something once or will end up with leaked + // references. + // + // One place this has happened in the past is using + // std::vector<SerializedVar>.resize(). If you're doing this manually instead + // of using the helper classes for handling in/out vectors of vars, be + // sure you use the same pattern as the SerializedVarVector classes. + DCHECK(!has_been_deserialized_); + has_been_deserialized_ = true; +#endif + // When reading, the dispatcher should be set when we get a Deserialize + // call (which will supply a dispatcher). + if (!m->ReadBool(iter, &is_valid_var_)) + return false; + if (is_valid_var_) { + raw_var_data_ = RawVarDataGraph::Read(m, iter); + if (!raw_var_data_) + return false; + } + + return true; +} + +void SerializedVar::Inner::SetCleanupModeToEndSendPassRef() { + cleanup_mode_ = END_SEND_PASS_REF; +} + +void SerializedVar::Inner::SetCleanupModeToEndReceiveCallerOwned() { + cleanup_mode_ = END_RECEIVE_CALLER_OWNED; +} + +// SerializedVar --------------------------------------------------------------- + +SerializedVar::SerializedVar() : inner_(new Inner) { +} + +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules) + : inner_(new Inner(serialization_rules)) { +} + +SerializedVar::~SerializedVar() { +} + +// SerializedVarSendInput ------------------------------------------------------ + +SerializedVarSendInput::SerializedVarSendInput(Dispatcher* dispatcher, + const PP_Var& var) + : SerializedVar(dispatcher->serialization_rules()) { + inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned(var)); +} + +// static +void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, + const PP_Var* input, + size_t input_count, + std::vector<SerializedVar>* output) { + output->reserve(input_count); + for (size_t i = 0; i < input_count; i++) + output->push_back(SerializedVarSendInput(dispatcher, input[i])); +} + +// SerializedVarSendInputShmem ------------------------------------------------- + +SerializedVarSendInputShmem::SerializedVarSendInputShmem( + Dispatcher* dispatcher, + const PP_Var& var, + const PP_Instance& instance) + : SerializedVar(dispatcher->serialization_rules()) { + inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned(var)); + inner_->SetInstance(instance); +} + +// ReceiveSerializedVarReturnValue --------------------------------------------- + +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { +} + +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue( + const SerializedVar& serialized) + : SerializedVar(serialized) { +} + +PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) { + inner_->set_serialization_rules(dispatcher->serialization_rules()); + inner_->SetVar(inner_->serialization_rules()->ReceivePassRef( + inner_->GetVar())); + return inner_->GetVar(); +} + +// ReceiveSerializedException -------------------------------------------------- + +ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher, + PP_Var* exception) + : SerializedVar(dispatcher->serialization_rules()), + exception_(exception) { +} + +ReceiveSerializedException::~ReceiveSerializedException() { + if (exception_) { + // When an output exception is specified, it will take ownership of the + // reference. + inner_->SetVar( + inner_->serialization_rules()->ReceivePassRef(inner_->GetVar())); + *exception_ = inner_->GetVar(); + } else { + // When no output exception is specified, the browser thinks we have a ref + // to an object that we don't want (this will happen only in the plugin + // since the browser will always specify an out exception for the plugin to + // write into). + // + // Strings don't need this handling since we can just avoid creating a + // Var from the std::string in the first place. + if (inner_->GetVar().type == PP_VARTYPE_OBJECT) + inner_->serialization_rules()->ReleaseObjectRef(inner_->GetVar()); + } +} + +bool ReceiveSerializedException::IsThrown() const { + return exception_ && exception_->type != PP_VARTYPE_UNDEFINED; +} + +// ReceiveSerializedVarVectorOutParam ------------------------------------------ + +ReceiveSerializedVarVectorOutParam::ReceiveSerializedVarVectorOutParam( + Dispatcher* dispatcher, + uint32_t* output_count, + PP_Var** output) + : dispatcher_(dispatcher), + output_count_(output_count), + output_(output) { +} + +ReceiveSerializedVarVectorOutParam::~ReceiveSerializedVarVectorOutParam() { + *output_count_ = static_cast<uint32_t>(vector_.size()); + if (!vector_.size()) { + *output_ = NULL; + return; + } + + *output_ = static_cast<PP_Var*>(malloc(vector_.size() * sizeof(PP_Var))); + for (size_t i = 0; i < vector_.size(); i++) { + // Here we just mimic what happens when returning a value. + ReceiveSerializedVarReturnValue converted; + SerializedVar* serialized = &converted; + *serialized = vector_[i]; + (*output_)[i] = converted.Return(dispatcher_); + } +} + +std::vector<SerializedVar>* ReceiveSerializedVarVectorOutParam::OutParam() { + return &vector_; +} + +// SerializedVarReceiveInput --------------------------------------------------- + +SerializedVarReceiveInput::SerializedVarReceiveInput( + const SerializedVar& serialized) + : serialized_(serialized) { +} + +SerializedVarReceiveInput::~SerializedVarReceiveInput() { +} + +PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) { + serialized_.inner_->set_serialization_rules( + dispatcher->serialization_rules()); + + // Ensure that when the serialized var goes out of scope it cleans up the + // stuff we're making in BeginReceiveCallerOwned. + serialized_.inner_->SetCleanupModeToEndReceiveCallerOwned(); + + serialized_.inner_->SetVar( + serialized_.inner_->serialization_rules()->BeginReceiveCallerOwned( + serialized_.inner_->GetVar())); + return serialized_.inner_->GetVar(); +} + + +PP_Var SerializedVarReceiveInput::GetForInstance(Dispatcher* dispatcher, + PP_Instance instance) { + serialized_.inner_->SetInstance(instance); + return Get(dispatcher); +} + +// SerializedVarVectorReceiveInput --------------------------------------------- + +SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( + const std::vector<SerializedVar>& serialized) + : serialized_(serialized) { +} + +SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() { + for (size_t i = 0; i < deserialized_.size(); i++) { + serialized_[i].inner_->serialization_rules()->EndReceiveCallerOwned( + deserialized_[i]); + } +} + +PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher, + uint32_t* array_size) { + deserialized_.resize(serialized_.size()); + for (size_t i = 0; i < serialized_.size(); i++) { + // The vectors must be able to clean themselves up after this call is + // torn down. + serialized_[i].inner_->set_serialization_rules( + dispatcher->serialization_rules()); + + serialized_[i].inner_->SetVar( + serialized_[i].inner_->serialization_rules()->BeginReceiveCallerOwned( + serialized_[i].inner_->GetVar())); + deserialized_[i] = serialized_[i].inner_->GetVar(); + } + + *array_size = static_cast<uint32_t>(serialized_.size()); + return deserialized_.empty() ? NULL : &deserialized_[0]; +} + +// SerializedVarReturnValue ---------------------------------------------------- + +SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized) + : serialized_(serialized) { +} + +void SerializedVarReturnValue::Return(Dispatcher* dispatcher, + const PP_Var& var) { + serialized_->inner_->set_serialization_rules( + dispatcher->serialization_rules()); + + // Var must clean up after our BeginSendPassRef call. + serialized_->inner_->SetCleanupModeToEndSendPassRef(); + + serialized_->inner_->SetVar( + dispatcher->serialization_rules()->BeginSendPassRef(var)); +} + +// static +SerializedVar SerializedVarReturnValue::Convert(Dispatcher* dispatcher, + const PP_Var& var) { + // Mimic what happens in the normal case. + SerializedVar result; + SerializedVarReturnValue retvalue(&result); + retvalue.Return(dispatcher, var); + return result; +} + +// SerializedVarOutParam ------------------------------------------------------- + +SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized) + : serialized_(serialized), + writable_var_(PP_MakeUndefined()), + dispatcher_(NULL) { +} + +SerializedVarOutParam::~SerializedVarOutParam() { + if (serialized_->inner_->serialization_rules()) { + // When unset, OutParam wasn't called. We'll just leave the var untouched + // in that case. + serialized_->inner_->SetVar( + serialized_->inner_->serialization_rules()->BeginSendPassRef( + writable_var_)); + + // Normally the current object will be created on the stack to wrap a + // SerializedVar and won't have a scope around the actual IPC send. So we + // need to tell the SerializedVar to do the begin/end send pass ref calls. + serialized_->inner_->SetCleanupModeToEndSendPassRef(); + } +} + +PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) { + dispatcher_ = dispatcher; + serialized_->inner_->set_serialization_rules( + dispatcher->serialization_rules()); + return &writable_var_; +} + +// SerializedVarVectorOutParam ------------------------------------------------- + +SerializedVarVectorOutParam::SerializedVarVectorOutParam( + std::vector<SerializedVar>* serialized) + : dispatcher_(NULL), + serialized_(serialized), + count_(0), + array_(NULL) { +} + +SerializedVarVectorOutParam::~SerializedVarVectorOutParam() { + DCHECK(dispatcher_); + + // Convert the array written by the pepper code to the serialized structure. + // Note we can't use resize here, we have to allocate a new SerializedVar + // for each serialized item. See ParamTraits<vector<SerializedVar>>::Read. + serialized_->reserve(count_); + for (uint32_t i = 0; i < count_; i++) { + // Just mimic what we do for regular OutParams. + SerializedVar var; + SerializedVarOutParam out(&var); + *out.OutParam(dispatcher_) = array_[i]; + serialized_->push_back(var); + } + + // When returning arrays, the pepper code expects the caller to take + // ownership of the array. + free(array_); +} + +PP_Var** SerializedVarVectorOutParam::ArrayOutParam(Dispatcher* dispatcher) { + DCHECK(!dispatcher_); // Should only be called once. + dispatcher_ = dispatcher; + return &array_; +} + +SerializedVarTestConstructor::SerializedVarTestConstructor( + const PP_Var& pod_var) { + DCHECK(pod_var.type != PP_VARTYPE_STRING); + inner_->ForceSetVarValueForTest(pod_var); +} + +SerializedVarTestConstructor::SerializedVarTestConstructor( + const std::string& str) { + inner_->ForceSetVarValueForTest(StringVar::StringToPPVar(str)); +} + +SerializedVarTestReader::SerializedVarTestReader(const SerializedVar& var) + : SerializedVar(var) { +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/serialized_var.h b/chromium/ppapi/proxy/serialized_var.h new file mode 100644 index 00000000000..13052c91d38 --- /dev/null +++ b/chromium/ppapi/proxy/serialized_var.h @@ -0,0 +1,502 @@ +// 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_PROXY_SERIALIZED_VAR_H_ +#define PPAPI_PROXY_SERIALIZED_VAR_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/raw_var_data.h" +#include "ppapi/proxy/serialized_handle.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/proxy/var_serialization_rules.h" + +class PickleIterator; + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace proxy { + +class Dispatcher; +class VarSerializationRules; + +// This class encapsulates a var so that we can serialize and deserialize it. +// The problem is that for strings, serialization and deserialization requires +// knowledge from outside about how to get at or create a string. So this +// object groups the var with a dispatcher so that string values can be set or +// gotten. +// +// Declare IPC messages as using this type, but don't use it directly (it has +// no useful public methods). Instead, instantiate one of the helper classes +// below which are conveniently named for each use case to prevent screwups. +// +// Design background +// ----------------- +// This is sadly super complicated. The IPC system needs a consistent type to +// use for sending and receiving vars (this is a SerializedVar). But there are +// different combinations of reference counting for sending and receiving +// objects and for dealing with strings +// +// This makes SerializedVar complicated and easy to mess up. To make it +// reasonable to use, all functions are protected and there are use-specific +// classes that each encapsulate exactly one type of use in a way that typically +// won't compile if you do the wrong thing. +// +// The IPC system is designed to pass things around and will make copies in +// some cases, so our system must be designed so that this stuff will work. +// This is challenging when the SerializedVar must do some cleanup after the +// message is sent. To work around this, we create an inner class using a +// linked_ptr so all copies of a SerializedVar can share and we can guarantee +// that the actual data will get cleaned up on shutdown. +// +// Constness +// --------- +// SerializedVar basically doesn't support const. Everything is mutable and +// most functions are declared const. This unfortunateness is because of the +// way the IPC system works. When deserializing, it will have a const +// SerializedVar in a Tuple and this will be given to the function. We kind of +// want to modify that to convert strings and do refcounting. +// +// The helper classes used for accessing the SerializedVar have more reasonable +// behavior and will enforce that you don't do stupid things. +class PPAPI_PROXY_EXPORT SerializedVar { + public: + SerializedVar(); + ~SerializedVar(); + + // Backend implementation for IPC::ParamTraits<SerializedVar>. + void WriteToMessage(IPC::Message* m) const { + inner_->WriteToMessage(m); + } + // If ReadFromMessage has been called, WriteDataToMessage will write the var + // that has been read from ReadFromMessage back to a message. This is used + // when converting handles for use in NaCl. + void WriteDataToMessage(IPC::Message* m, + const HandleWriter& handle_writer) const { + inner_->WriteDataToMessage(m, handle_writer); + } + bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter) { + return inner_->ReadFromMessage(m, iter); + } + + bool is_valid_var() const { + return inner_->is_valid_var(); + } + + // Returns the shared memory handles associated with this SerializedVar. + std::vector<SerializedHandle*> GetHandles() const { + return inner_->GetHandles(); + } + + protected: + friend class SerializedVarReceiveInput; + friend class SerializedVarReturnValue; + friend class SerializedVarOutParam; + friend class SerializedVarSendInput; + friend class SerializedVarSendInputShmem; + friend class SerializedVarTestConstructor; + friend class SerializedVarVectorReceiveInput; + + class PPAPI_PROXY_EXPORT Inner : public base::RefCounted<Inner> { + public: + Inner(); + Inner(VarSerializationRules* serialization_rules); + ~Inner(); + + VarSerializationRules* serialization_rules() { + return serialization_rules_.get(); + } + void set_serialization_rules(VarSerializationRules* serialization_rules) { + serialization_rules_ = serialization_rules; + } + + bool is_valid_var() const { + return is_valid_var_; + } + + std::vector<SerializedHandle*> GetHandles() { + return (raw_var_data_ ? raw_var_data_->GetHandles() : + std::vector<SerializedHandle*>()); + } + + // See outer class's declarations above. + PP_Var GetVar(); + void SetVar(PP_Var var); + void SetInstance(PP_Instance instance); + + // For the SerializedVarTestConstructor, this writes the Var value as if + // it was just received off the wire, without any serialization rules. + void ForceSetVarValueForTest(PP_Var value); + + void WriteToMessage(IPC::Message* m) const; + void WriteDataToMessage(IPC::Message* m, + const HandleWriter& handle_writer) const; + bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter); + + // Sets the cleanup mode. See the CleanupMode enum below. + void SetCleanupModeToEndSendPassRef(); + void SetCleanupModeToEndReceiveCallerOwned(); + + private: + enum CleanupMode { + // The serialized var won't do anything special in the destructor + // (default). + CLEANUP_NONE, + + // The serialized var will call EndSendPassRef in the destructor. + END_SEND_PASS_REF, + + // The serialized var will call EndReceiveCallerOwned in the destructor. + END_RECEIVE_CALLER_OWNED + }; + + // Rules for serializing and deserializing vars for this process type. + // This may be NULL, but must be set before trying to serialize to IPC when + // sending, or before converting back to a PP_Var when receiving. + scoped_refptr<VarSerializationRules> serialization_rules_; + + // If this is set to VARTYPE_STRING and the 'value.id' is 0, then the + // string_from_ipc_ holds the string. This means that the caller hasn't + // called Deserialize with a valid Dispatcher yet, which is how we can + // convert the serialized string value to a PP_Var string ID. + // + // This var may not be complete until the serialization rules are set when + // reading from IPC since we'll need that to convert the string_value to + // a string ID. Before this, the as_id will be 0 for VARTYPE_STRING. + PP_Var var_; + + PP_Instance instance_; + + CleanupMode cleanup_mode_; + + // If the var is not properly serialized, this will be false. + bool is_valid_var_; + +#ifndef NDEBUG + // When being sent or received over IPC, we should only be serialized or + // deserialized once. These flags help us assert this is true. + mutable bool has_been_serialized_; + mutable bool has_been_deserialized_; +#endif + + // ReadFromMessage() may be called on the I/O thread, e.g., when reading the + // reply to a sync message. We cannot use the var tracker on the I/O thread, + // which means we cannot create some types of PP_Var + // (e.g. PP_VARTYPE_STRING). The data is stored in |raw_var_data_| and the + // PP_Var is constructed when |GetVar()| is called. + scoped_ptr<RawVarDataGraph> raw_var_data_; + + DISALLOW_COPY_AND_ASSIGN(Inner); + }; + + SerializedVar(VarSerializationRules* serialization_rules); + + mutable scoped_refptr<Inner> inner_; +}; + +// Helpers for message sending side -------------------------------------------- + +// For sending a value to the remote side. +// +// Example for API: +// void MyFunction(PP_Var) +// IPC message: +// IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar); +// Sender would be: +// void MyFunctionProxy(PP_Var param) { +// Send(new MyFunctionMsg(SerializedVarSendInput(dispatcher, param)); +// } +class PPAPI_PROXY_EXPORT SerializedVarSendInput : public SerializedVar { + public: + SerializedVarSendInput(Dispatcher* dispatcher, const PP_Var& var); + + // Helper function for serializing a vector of input vars for serialization. + static void ConvertVector(Dispatcher* dispatcher, + const PP_Var* input, + size_t input_count, + std::vector<SerializedVar>* output); + + private: + // Disallow the empty constructor, but keep the default copy constructor + // which is required to send the object to the IPC system. + SerializedVarSendInput(); +}; + +// Specialization for optionally sending over shared memory. +class PPAPI_PROXY_EXPORT SerializedVarSendInputShmem : public SerializedVar { + public: + SerializedVarSendInputShmem(Dispatcher* dispatcher, const PP_Var& var, + const PP_Instance& instance); + + private: + // Disallow the empty constructor, but keep the default copy constructor + // which is required to send the object to the IPC system. + SerializedVarSendInputShmem(); +}; + + +// For the calling side of a function returning a var. The sending side uses +// SerializedVarReturnValue. +// +// Example for API: +// PP_Var MyFunction() +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// PP_Var MyFunctionProxy() { +// ReceiveSerializedVarReturnValue result; +// Send(new MyFunctionMsg(&result)); +// return result.Return(dispatcher()); +// } +// +// TODO(yzshen): Move the dispatcher parameter to the constructor and store a +// VarSerializationRules reference instead, in case the dispatcher is destroyed +// while waiting for reply to the sync message. +class PPAPI_PROXY_EXPORT ReceiveSerializedVarReturnValue + : public SerializedVar { + public: + // Note that we can't set the dispatcher in the constructor because the + // data will be overridden when the return value is set. This constructor is + // normally used in the pattern above (operator= will be implicitly invoked + // when the sync message writes the output values). + ReceiveSerializedVarReturnValue(); + + // This constructor can be used when deserializing manually. This is useful + // when you're getting strings "returned" via a struct and need to manually + // get the PP_Vars out. In this case just do: + // ReceiveSerializedVarReturnValue(serialized).Return(dispatcher); + explicit ReceiveSerializedVarReturnValue(const SerializedVar& serialized); + + PP_Var Return(Dispatcher* dispatcher); + + private: + DISALLOW_COPY_AND_ASSIGN(ReceiveSerializedVarReturnValue); +}; + +// Example for API: +// "void MyFunction(PP_Var* exception);" +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(PP_Var* exception) { +// ReceiveSerializedException se(dispatcher(), exception) +// Send(new PpapiHostMsg_Foo(&se)); +// } +class PPAPI_PROXY_EXPORT ReceiveSerializedException : public SerializedVar { + public: + ReceiveSerializedException(Dispatcher* dispatcher, PP_Var* exception); + ~ReceiveSerializedException(); + + // Returns true if the exception passed in the constructor is set. Check + // this before actually issuing the IPC. + bool IsThrown() const; + + private: + // The input/output exception we're wrapping. May be NULL. + PP_Var* exception_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedException); +}; + +// Helper class for when we're returning a vector of Vars. When it goes out +// of scope it will automatically convert the vector filled by the IPC layer +// into the array specified by the constructor params. +// +// Example for API: +// "void MyFunction(uint32_t* count, PP_Var** vars);" +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, std::vector<SerializedVar>); +// Proxy function: +// void MyFunction(uint32_t* count, PP_Var** vars) { +// ReceiveSerializedVarVectorOutParam vect(dispatcher, count, vars); +// Send(new MyMsg(vect.OutParam())); +// } +class PPAPI_PROXY_EXPORT ReceiveSerializedVarVectorOutParam { + public: + ReceiveSerializedVarVectorOutParam(Dispatcher* dispatcher, + uint32_t* output_count, + PP_Var** output); + ~ReceiveSerializedVarVectorOutParam(); + + std::vector<SerializedVar>* OutParam(); + + private: + Dispatcher* dispatcher_; + uint32_t* output_count_; + PP_Var** output_; + + std::vector<SerializedVar> vector_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedVarVectorOutParam); +}; + +// Helpers for message receiving side ------------------------------------------ + +// For receiving a value from the remote side. +// +// Example for API: +// void MyFunction(PP_Var) +// IPC message: +// IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(SerializedVarReceiveInput param) { +// MyFunction(param.Get()); +// } +class PPAPI_PROXY_EXPORT SerializedVarReceiveInput { + public: + // We rely on the implicit constructor here since the IPC layer will call + // us with a SerializedVar. Pass this object by value, the copy constructor + // will pass along the pointer (as cheap as passing a pointer arg). + SerializedVarReceiveInput(const SerializedVar& serialized); + ~SerializedVarReceiveInput(); + + PP_Var Get(Dispatcher* dispatcher); + PP_Var GetForInstance(Dispatcher* dispatcher, PP_Instance instance); + bool is_valid_var() { return serialized_.is_valid_var(); } + + private: + const SerializedVar& serialized_; +}; + +// For receiving an input vector of vars from the remote side. +// +// Example: +// OnMsgMyFunction(SerializedVarVectorReceiveInput vector) { +// uint32_t size; +// PP_Var* array = vector.Get(dispatcher, &size); +// MyFunction(size, array); +// } +class PPAPI_PROXY_EXPORT SerializedVarVectorReceiveInput { + public: + SerializedVarVectorReceiveInput(const std::vector<SerializedVar>& serialized); + ~SerializedVarVectorReceiveInput(); + + // Only call Get() once. It will return a pointer to the converted array and + // place the array size in the out param. Will return NULL when the array is + // empty. + PP_Var* Get(Dispatcher* dispatcher, uint32_t* array_size); + + private: + const std::vector<SerializedVar>& serialized_; + + // Filled by Get(). + std::vector<PP_Var> deserialized_; +}; + +// For the receiving side of a function returning a var. The calling side uses +// ReceiveSerializedVarReturnValue. +// +// Example for API: +// PP_Var MyFunction() +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(SerializedVarReturnValue result) { +// result.Return(dispatcher(), MyFunction()); +// } +class PPAPI_PROXY_EXPORT SerializedVarReturnValue { + public: + // We rely on the implicit constructor here since the IPC layer will call + // us with a SerializedVar*. Pass this object by value, the copy constructor + // will pass along the pointer (as cheap as passing a pointer arg). + SerializedVarReturnValue(SerializedVar* serialized); + + void Return(Dispatcher* dispatcher, const PP_Var& var); + + // Helper function for code that doesn't use the pattern above, but gets + // a return value from the remote side via a struct. You can pass in the + // SerializedVar and a PP_Var will be created with return value semantics. + static SerializedVar Convert(Dispatcher* dispatcher, const PP_Var& var); + + private: + SerializedVar* serialized_; +}; + +// For writing an out param to the remote side. +// +// Example for API: +// "void MyFunction(PP_Var* out);" +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(SerializedVarOutParam out_param) { +// MyFunction(out_param.OutParam(dispatcher())); +// } +class PPAPI_PROXY_EXPORT SerializedVarOutParam { + public: + // We rely on the implicit constructor here since the IPC layer will call + // us with a SerializedVar*. Pass this object by value, the copy constructor + // will pass along the pointer (as cheap as passing a pointer arg). + SerializedVarOutParam(SerializedVar* serialized); + ~SerializedVarOutParam(); + + // Call this function only once. The caller should write its result to the + // returned var pointer before this class goes out of scope. The var's + // initial value will be VARTYPE_UNDEFINED. + PP_Var* OutParam(Dispatcher* dispatcher); + + private: + SerializedVar* serialized_; + + // This is the value actually written by the code and returned by OutParam. + // We'll write this into serialized_ in our destructor. + PP_Var writable_var_; + + Dispatcher* dispatcher_; +}; + +// For returning an array of PP_Vars to the other side and transferring +// ownership. +// +class PPAPI_PROXY_EXPORT SerializedVarVectorOutParam { + public: + SerializedVarVectorOutParam(std::vector<SerializedVar>* serialized); + ~SerializedVarVectorOutParam(); + + uint32_t* CountOutParam() { return &count_; } + PP_Var** ArrayOutParam(Dispatcher* dispatcher); + + private: + Dispatcher* dispatcher_; + std::vector<SerializedVar>* serialized_; + + uint32_t count_; + PP_Var* array_; +}; + +// For tests that just want to construct a SerializedVar for giving it to one +// of the other classes. This emulates a SerializedVar just received over the +// wire from another process. +class PPAPI_PROXY_EXPORT SerializedVarTestConstructor : public SerializedVar { + public: + // For POD-types and objects. + explicit SerializedVarTestConstructor(const PP_Var& pod_var); + + // For strings. + explicit SerializedVarTestConstructor(const std::string& str); +}; + +// For tests that want to read what's in a SerializedVar. +class PPAPI_PROXY_EXPORT SerializedVarTestReader : public SerializedVar { + public: + explicit SerializedVarTestReader(const SerializedVar& var); + + PP_Var GetVar() const { return inner_->GetVar(); } +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_SERIALIZED_VAR_H_ diff --git a/chromium/ppapi/proxy/serialized_var_unittest.cc b/chromium/ppapi/proxy/serialized_var_unittest.cc new file mode 100644 index 00000000000..fcde77795a3 --- /dev/null +++ b/chromium/ppapi/proxy/serialized_var_unittest.cc @@ -0,0 +1,354 @@ +// 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 "ppapi/proxy/ppapi_proxy_test.h" + +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/proxy_lock.h" + +namespace ppapi { +namespace proxy { + +namespace { + +PP_Var MakeObjectVar(int64_t object_id) { + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = object_id; + return ret; +} + +class SerializedVarTest : public PluginProxyTest { + public: + SerializedVarTest() {} +}; + +} // namespace + +// Tests output arguments in the plugin. This is when the host calls into the +// plugin and the plugin returns something via an out param, like an exception. +TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) { + ProxyAutoLock lock; + PP_Var host_object = MakeObjectVar(0x31337); + + PP_Var plugin_object; + { + // Receive the object param, we should be tracking it with no refcount, and + // no messages sent. + SerializedVarTestConstructor input(host_object); + SerializedVarReceiveInput receive_input(input); + plugin_object = receive_input.Get(plugin_dispatcher()); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + + SerializedVar sv; + { + // The "OutParam" does its work in its destructor, it will write the + // information to the SerializedVar we passed in the constructor. + SerializedVarOutParam out_param(&sv); + // An out-param needs to pass a reference to the caller, so it's the + // responsibility of the plugin to bump the ref-count on an input + // parameter. + var_tracker().AddRefVar(plugin_object); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + // We should have informed the host that a reference was taken. + EXPECT_EQ(1u, sink().message_count()); + *out_param.OutParam(plugin_dispatcher()) = plugin_object; + } + + // The object should have transformed the plugin object back to the host + // object ID. Nothing in the var tracker should have changed yet, and no + // messages should have been sent. + SerializedVarTestReader reader(sv); + EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + } + + // The out param should have done an "end receive caller owned" on the plugin + // var serialization rules, which should have released the "track-with-no- + // reference" count in the var tracker as well as the 1 reference we passed + // back to the host, so the object should no longer be in the tracker. The + // reference we added has been removed, so another message should be sent to + // the host to tell it we're done with the object. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(2u, sink().message_count()); +} + +// Tests output strings in the plugin. This is when the host calls into the +// plugin with a string and the plugin returns it via an out param. +TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) { + ProxyAutoLock lock; + PP_Var plugin_string; + const std::string kTestString("elite"); + { + // Receive the string param. We should track it with 1 refcount. + SerializedVarTestConstructor input(kTestString); + SerializedVarReceiveInput receive_input(input); + plugin_string = receive_input.Get(plugin_dispatcher()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); + + SerializedVar sv; + { + // The "OutParam" does its work in its destructor, it will write the + // information to the SerializedVar we passed in the constructor. + SerializedVarOutParam out_param(&sv); + // An out-param needs to pass a reference to the caller, so it's the + // responsibility of the plugin to bump the ref-count of an input + // parameter. + var_tracker().AddRefVar(plugin_string); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); + *out_param.OutParam(plugin_dispatcher()) = plugin_string; + } + + // The SerializedVar should have set the string value internally. Nothing in + // the var tracker should have changed yet, and no messages should have been + // sent. + SerializedVarTestReader reader(sv); + //EXPECT_EQ(kTestString, *reader.GetTrackerStringPtr()); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); + } + // The reference the string had initially should be gone, and the reference we + // passed to the host should also be gone, so the string should be removed. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string)); + EXPECT_EQ(0u, sink().message_count()); +} + +// Tests receiving an argument and passing it back to the browser as an output +// parameter. +TEST_F(SerializedVarTest, PluginSerializedVarOutParam) { + ProxyAutoLock lock; + PP_Var host_object = MakeObjectVar(0x31337); + + // Start tracking this object in the plugin. + PP_Var plugin_object = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + + { + SerializedVar sv; + { + // The "OutParam" does its work in its destructor, it will write the + // information to the SerializedVar we passed in the constructor. + SerializedVarOutParam out_param(&sv); + *out_param.OutParam(plugin_dispatcher()) = plugin_object; + } + + // The object should have transformed the plugin object back to the host + // object ID. Nothing in the var tracker should have changed yet, and no + // messages should have been sent. + SerializedVarTestReader reader(sv); + EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + } + + // The out param should have done an "end send pass ref" on the plugin + // var serialization rules, which should have in turn released the reference + // in the var tracker. Since we only had one reference, this should have sent + // a release to the browser. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + + // We don't bother validating that message since it's nontrivial and the + // PluginVarTracker test has cases that cover that this message is correct. +} + +// Tests the case that the plugin receives the same var twice as an input +// parameter (not passing ownership). +TEST_F(SerializedVarTest, PluginReceiveInput) { + ProxyAutoLock lock; + PP_Var host_object = MakeObjectVar(0x31337); + + PP_Var plugin_object; + { + // Receive the first param, we should be tracking it with no refcount, and + // no messages sent. + SerializedVarTestConstructor input1(host_object); + SerializedVarReceiveInput receive_input(input1); + plugin_object = receive_input.Get(plugin_dispatcher()); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + + // Receive the second param, it should be resolved to the same plugin + // object and there should still be no refcount. + SerializedVarTestConstructor input2(host_object); + SerializedVarReceiveInput receive_input2(input2); + PP_Var plugin_object2 = receive_input2.Get(plugin_dispatcher()); + EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + + // Take a reference to the object, as if the plugin was using it, and then + // release it, we should still be tracking the object since the + // ReceiveInputs keep the "track_with_no_reference_count" alive until + // they're destroyed. + var_tracker().AddRefVar(plugin_object); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + var_tracker().ReleaseVar(plugin_object); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(2u, sink().message_count()); + } + + // Since we didn't keep any refs to the objects, it should have freed the + // object. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); +} + +// Tests the case that the plugin receives the same vars twice as an input +// parameter (not passing ownership) within a vector. +TEST_F(SerializedVarTest, PluginVectorReceiveInput) { + ProxyAutoLock lock; + PP_Var host_object = MakeObjectVar(0x31337); + + std::vector<PP_Var> plugin_objects; + std::vector<PP_Var> plugin_objects2; + { + // Receive the params. The object should be tracked with no refcount and + // no messages sent. The string should is plugin-side only and should have + // a reference-count of 1. + std::vector<SerializedVar> input1; + input1.push_back(SerializedVarTestConstructor(host_object)); + input1.push_back(SerializedVarTestConstructor("elite")); + SerializedVarVectorReceiveInput receive_input(input1); + uint32_t array_size = 0; + PP_Var* plugin_objects_array = + receive_input.Get(plugin_dispatcher(), &array_size); + plugin_objects.insert(plugin_objects.begin(), plugin_objects_array, + plugin_objects_array + array_size); + ASSERT_EQ(2u, array_size); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1])); + EXPECT_EQ(0u, sink().message_count()); + + // Receive the second param, it should be resolved to the same plugin + // object and there should still be no refcount. + std::vector<SerializedVar> input2; + input2.push_back(SerializedVarTestConstructor(host_object)); + input2.push_back(SerializedVarTestConstructor("elite")); + SerializedVarVectorReceiveInput receive_input2(input2); + uint32_t array_size2 = 0; + PP_Var* plugin_objects_array2 = + receive_input2.Get(plugin_dispatcher(), &array_size2); + plugin_objects2.insert(plugin_objects2.begin(), plugin_objects_array2, + plugin_objects_array2 + array_size2); + ASSERT_EQ(2u, array_size2); + EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); + // Strings get re-created with a new ID. We don't try to reuse strings in + // the tracker, so the string should get a new ID. + EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1])); + EXPECT_EQ(0u, sink().message_count()); + + // Take a reference to the object, as if the plugin was using it, and then + // release it, we should still be tracking the object since the + // ReceiveInputs keep the "track_with_no_reference_count" alive until + // they're destroyed. + var_tracker().AddRefVar(plugin_objects[0]); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0])); + var_tracker().ReleaseVar(plugin_objects[0]); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); + EXPECT_EQ(2u, sink().message_count()); + + // Take a reference to a string and then release it. Make sure no messages + // are sent. + uint32_t old_message_count = sink().message_count(); + var_tracker().AddRefVar(plugin_objects[1]); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1])); + var_tracker().ReleaseVar(plugin_objects[1]); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1])); + EXPECT_EQ(old_message_count, sink().message_count()); + } + + // Since we didn't keep any refs to the objects or strings, so they should + // have been freed. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0])); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1])); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1])); +} + +// Tests the plugin receiving a var as a return value from the browser +// two different times (passing ownership). +TEST_F(SerializedVarTest, PluginReceiveReturn) { + ProxyAutoLock lock; + PP_Var host_object = MakeObjectVar(0x31337); + + PP_Var plugin_object; + { + // Receive the first param, we should be tracking it with a refcount of 1. + SerializedVarTestConstructor input1(host_object); + ReceiveSerializedVarReturnValue receive_input(input1); + plugin_object = receive_input.Return(plugin_dispatcher()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + + // Receive the second param, it should be resolved to the same plugin + // object and there should be a plugin refcount of 2. There should have + // been an IPC message sent that released the duplicated ref in the browser + // (so both of our refs are represented by one in the browser). + SerializedVarTestConstructor input2(host_object); + ReceiveSerializedVarReturnValue receive_input2(input2); + PP_Var plugin_object2 = receive_input2.Return(plugin_dispatcher()); + EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + } + + // The ReceiveSerializedVarReturnValue destructor shouldn't have affected + // the refcount or sent any messages. + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + + // Manually release one refcount, it shouldn't have sent any more messages. + var_tracker().ReleaseVar(plugin_object); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + + // Manually release the last refcount, it should have freed it and sent a + // release message to the browser. + var_tracker().ReleaseVar(plugin_object); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(2u, sink().message_count()); +} + +// Returns a value from the browser to the plugin, then return that one ref +// back to the browser. +TEST_F(SerializedVarTest, PluginReturnValue) { + ProxyAutoLock lock; + PP_Var host_object = MakeObjectVar(0x31337); + + PP_Var plugin_object; + { + // Receive the param in the plugin. + SerializedVarTestConstructor input1(host_object); + ReceiveSerializedVarReturnValue receive_input(input1); + plugin_object = receive_input.Return(plugin_dispatcher()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + } + + { + // Now return to the browser. + SerializedVar output; + SerializedVarReturnValue return_output(&output); + return_output.Return(plugin_dispatcher(), plugin_object); + + // The ref in the plugin should be alive until the ReturnValue goes out of + // scope, since the release needs to be after the browser processes the + // message. + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + } + + // When the ReturnValue object goes out of scope, it should have sent a + // release message to the browser. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/talk_resource.cc b/chromium/ppapi/proxy/talk_resource.cc new file mode 100644 index 00000000000..2e60abfd331 --- /dev/null +++ b/chromium/ppapi/proxy/talk_resource.cc @@ -0,0 +1,114 @@ +// 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 "ppapi/proxy/talk_resource.h" + +#include "base/bind.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace ppapi { +namespace proxy { + +TalkResource::TalkResource(Connection connection, PP_Instance instance) + : PluginResource(connection, instance), + event_callback_(NULL), + event_callback_user_data_(NULL) { + SendCreate(BROWSER, PpapiHostMsg_Talk_Create()); +} + +TalkResource::~TalkResource() { +} + +thunk::PPB_Talk_Private_API* TalkResource::AsPPB_Talk_Private_API() { + return this; +} + +int32_t TalkResource::RequestPermission( + PP_TalkPermission permission, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(permission_callback_)) + return PP_ERROR_INPROGRESS; + + permission_callback_ = callback; + + Call<PpapiPluginMsg_Talk_RequestPermissionReply>( + BROWSER, + PpapiHostMsg_Talk_RequestPermission(permission), + base::Bind(&TalkResource::OnRequestPermissionReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TalkResource::StartRemoting(PP_TalkEventCallback event_callback, + void* user_data, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(start_callback_) || + event_callback_ != NULL) + return PP_ERROR_INPROGRESS; + + start_callback_ = callback; + event_callback_ = event_callback; + event_callback_user_data_ = user_data; + + Call<PpapiPluginMsg_Talk_StartRemotingReply>( + BROWSER, + PpapiHostMsg_Talk_StartRemoting(), + base::Bind(&TalkResource::OnStartRemotingReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TalkResource::StopRemoting(scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(stop_callback_)) + return PP_ERROR_INPROGRESS; + + if (event_callback_ == NULL) + return PP_ERROR_FAILED; + + stop_callback_ = callback; + + Call<PpapiPluginMsg_Talk_StopRemotingReply>( + BROWSER, + PpapiHostMsg_Talk_StopRemoting(), + base::Bind(&TalkResource::OnStopRemotingReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} + +void TalkResource::OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(TalkResource, msg) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_Talk_NotifyEvent, + OnNotifyEvent) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( + PluginResource::OnReplyReceived(params, msg)) + IPC_END_MESSAGE_MAP() +} + +void TalkResource::OnNotifyEvent(const ResourceMessageReplyParams& params, + PP_TalkEvent event) { + if (event_callback_ != NULL) + event_callback_(event_callback_user_data_, event); +} + +void TalkResource::OnRequestPermissionReply( + const ResourceMessageReplyParams& params) { + permission_callback_->Run(params.result()); +} + +void TalkResource::OnStartRemotingReply( + const ResourceMessageReplyParams& params) { + start_callback_->Run(params.result()); +} + +void TalkResource::OnStopRemotingReply( + const ResourceMessageReplyParams& params) { + event_callback_ = NULL; + event_callback_user_data_ = NULL; + stop_callback_->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/talk_resource.h b/chromium/ppapi/proxy/talk_resource.h new file mode 100644 index 00000000000..a2d88f00b6a --- /dev/null +++ b/chromium/ppapi/proxy/talk_resource.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 PPAPI_PROXY_TALK_RESOURCE_H_ +#define PPAPI_PROXY_TALK_RESOURCE_H_ + +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_talk_private_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT TalkResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_Talk_Private_API) { + public: + TalkResource(Connection connection, PP_Instance instance); + virtual ~TalkResource(); + + // Resource overrides. + thunk::PPB_Talk_Private_API* AsPPB_Talk_Private_API(); + + private: + // PPB_Talk_API implementation. + virtual int32_t RequestPermission( + PP_TalkPermission permission, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t StartRemoting( + PP_TalkEventCallback event_callback, + void* user_data, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t StopRemoting( + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + // PluginResource override. + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + void OnNotifyEvent(const ResourceMessageReplyParams& params, + PP_TalkEvent event); + void OnRequestPermissionReply(const ResourceMessageReplyParams& params); + void OnStartRemotingReply(const ResourceMessageReplyParams& params); + void OnStopRemotingReply(const ResourceMessageReplyParams& params); + + scoped_refptr<TrackedCallback> permission_callback_; + scoped_refptr<TrackedCallback> start_callback_; + scoped_refptr<TrackedCallback> stop_callback_; + PP_TalkEventCallback event_callback_; + void* event_callback_user_data_; + + DISALLOW_COPY_AND_ASSIGN(TalkResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_TALK_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/talk_resource_unittest.cc b/chromium/ppapi/proxy/talk_resource_unittest.cc new file mode 100644 index 00000000000..e81a8a6aca3 --- /dev/null +++ b/chromium/ppapi/proxy/talk_resource_unittest.cc @@ -0,0 +1,173 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/locking_resource_releaser.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/talk_resource.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +template <class ResultType> +class MockCallbackBase { + public: + MockCallbackBase() : called_(false) { + } + + bool called() { + return called_; + } + + ResultType result() { + return result_; + } + + void Reset() { + called_ = false; + } + + static void Callback(void* user_data, ResultType result) { + MockCallbackBase* that = reinterpret_cast<MockCallbackBase*>(user_data); + that->called_ = true; + that->result_ = result; + } + + private: + bool called_; + ResultType result_; +}; + +typedef MockCallbackBase<int32_t> MockCompletionCallback; +typedef MockCallbackBase<PP_TalkEvent> TalkEventCallback; + +class TalkResourceTest : public PluginProxyTest { + public: + void SendReply( + uint32_t id, + const IPC::Message& reply, + int32_t result) { + IPC::Message msg; + ResourceMessageCallParams params; + ASSERT_TRUE(sink().GetFirstResourceCallMatching(id, ¶ms, &msg)); + + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(result); + IPC::Message reply_msg = PpapiPluginMsg_ResourceReply(reply_params, reply); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(reply_msg)); + } +}; + + +} // namespace + +TEST_F(TalkResourceTest, GetPermission) { + const PPB_Talk_Private_1_0* talk = thunk::GetPPB_Talk_Private_1_0_Thunk(); + LockingResourceReleaser res(talk->Create(pp_instance())); + MockCompletionCallback callback; + + int32_t result = talk->GetPermission( + res.get(), + PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &callback)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_Talk_RequestPermission::ID, ¶ms, &msg)); + + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(1); + IPC::Message reply = PpapiPluginMsg_ResourceReply( + reply_params, PpapiPluginMsg_Talk_RequestPermissionReply()); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(reply)); + + ASSERT_TRUE(callback.called()); + ASSERT_EQ(1, callback.result()); +} + +TEST_F(TalkResourceTest, RequestPermission) { + const PPB_Talk_Private_2_0* talk = thunk::GetPPB_Talk_Private_2_0_Thunk(); + LockingResourceReleaser res(talk->Create(pp_instance())); + MockCompletionCallback callback; + + int32_t result = talk->RequestPermission( + res.get(), + PP_TALKPERMISSION_REMOTING_CONTINUE, + PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &callback)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_Talk_RequestPermission::ID, ¶ms, &msg)); + + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(1); + IPC::Message reply = PpapiPluginMsg_ResourceReply( + reply_params, PpapiPluginMsg_Talk_RequestPermissionReply()); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(reply)); + + ASSERT_TRUE(callback.called()); + ASSERT_EQ(1, callback.result()); +} + +TEST_F(TalkResourceTest, StartStopRemoting) { + const PPB_Talk_Private_2_0* talk = thunk::GetPPB_Talk_Private_2_0_Thunk(); + LockingResourceReleaser res(talk->Create(pp_instance())); + MockCompletionCallback callback; + TalkEventCallback event_callback; + + // Start + int32_t result = talk->StartRemoting( + res.get(), + &TalkEventCallback::Callback, + &event_callback, + PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &callback)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + SendReply(PpapiHostMsg_Talk_StartRemoting::ID, + PpapiPluginMsg_Talk_StartRemotingReply(), + PP_OK); + + ASSERT_TRUE(callback.called()); + ASSERT_EQ(PP_OK, callback.result()); + + // Receive an event + ASSERT_FALSE(event_callback.called()); + ResourceMessageReplyParams notify_params(res.get(), 0); + IPC::Message notify = PpapiPluginMsg_ResourceReply( + notify_params, PpapiPluginMsg_Talk_NotifyEvent(PP_TALKEVENT_ERROR)); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(notify)); + ASSERT_TRUE(event_callback.called()); + ASSERT_EQ(PP_TALKEVENT_ERROR, event_callback.result()); + + // Stop + callback.Reset(); + result = talk->StopRemoting( + res.get(), + PP_MakeCompletionCallback(&MockCompletionCallback::Callback, &callback)); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + SendReply(PpapiHostMsg_Talk_StopRemoting::ID, + PpapiPluginMsg_Talk_StopRemotingReply(), + PP_OK); + + ASSERT_TRUE(callback.called()); + ASSERT_EQ(PP_OK, callback.result()); + + // Events should be discarded at this point + event_callback.Reset(); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(notify)); + ASSERT_FALSE(event_callback.called()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/tcp_server_socket_private_resource.cc b/chromium/ppapi/proxy/tcp_server_socket_private_resource.cc new file mode 100644 index 00000000000..6bbf4667ee7 --- /dev/null +++ b/chromium/ppapi/proxy/tcp_server_socket_private_resource.cc @@ -0,0 +1,138 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/tcp_server_socket_private_resource.h" + +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_tcp_socket_private_proxy.h" + +namespace ppapi { +namespace proxy { + +TCPServerSocketPrivateResource::TCPServerSocketPrivateResource( + Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + state_(STATE_BEFORE_LISTENING), + local_addr_(), + plugin_dispatcher_id_(0) { + SendCreate(BROWSER, PpapiHostMsg_TCPServerSocket_CreatePrivate()); + + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (dispatcher) + plugin_dispatcher_id_ = dispatcher->plugin_dispatcher_id(); + else + NOTREACHED(); +} + +TCPServerSocketPrivateResource::~TCPServerSocketPrivateResource() { +} + +thunk::PPB_TCPServerSocket_Private_API* +TCPServerSocketPrivateResource::AsPPB_TCPServerSocket_Private_API() { + return this; +} + +int32_t TCPServerSocketPrivateResource::Listen( + const PP_NetAddress_Private* addr, + int32_t backlog, + scoped_refptr<TrackedCallback> callback) { + if (!addr) + return PP_ERROR_BADARGUMENT; + if (state_ != STATE_BEFORE_LISTENING) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(listen_callback_)) + return PP_ERROR_INPROGRESS; + + listen_callback_ = callback; + + // Send the request, the browser will call us back via ListenACK + Call<PpapiPluginMsg_TCPServerSocket_ListenReply>( + BROWSER, + PpapiHostMsg_TCPServerSocket_Listen(*addr, backlog), + base::Bind(&TCPServerSocketPrivateResource::OnPluginMsgListenReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TCPServerSocketPrivateResource::Accept( + PP_Resource* tcp_socket, + scoped_refptr<TrackedCallback> callback) { + if (!tcp_socket) + return PP_ERROR_BADARGUMENT; + if (state_ != STATE_LISTENING) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(accept_callback_)) + return PP_ERROR_INPROGRESS; + + accept_callback_ = callback; + + Call<PpapiPluginMsg_TCPServerSocket_AcceptReply>( + BROWSER, + PpapiHostMsg_TCPServerSocket_Accept(plugin_dispatcher_id_), + base::Bind(&TCPServerSocketPrivateResource::OnPluginMsgAcceptReply, + base::Unretained(this), tcp_socket)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TCPServerSocketPrivateResource::GetLocalAddress( + PP_NetAddress_Private* addr) { + if (!addr) + return PP_ERROR_BADARGUMENT; + if (state_ != STATE_LISTENING) + return PP_ERROR_FAILED; + *addr = local_addr_; + return PP_OK; +} + +void TCPServerSocketPrivateResource::StopListening() { + if (state_ == STATE_CLOSED) + return; + state_ = STATE_CLOSED; + Post(BROWSER, PpapiHostMsg_TCPServerSocket_StopListening()); + if (TrackedCallback::IsPending(listen_callback_)) + listen_callback_->PostAbort(); + if (TrackedCallback::IsPending(accept_callback_)) + accept_callback_->PostAbort(); +} + +void TCPServerSocketPrivateResource::OnPluginMsgListenReply( + const ResourceMessageReplyParams& params, + const PP_NetAddress_Private& local_addr) { + if (state_ != STATE_BEFORE_LISTENING || + !TrackedCallback::IsPending(listen_callback_)) { + return; + } + if (params.result() == PP_OK) { + local_addr_ = local_addr; + state_ = STATE_LISTENING; + } + listen_callback_->Run(params.result()); +} + +void TCPServerSocketPrivateResource::OnPluginMsgAcceptReply( + PP_Resource* tcp_socket, + const ResourceMessageReplyParams& params, + uint32 accepted_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + DCHECK(tcp_socket); + if (state_ != STATE_LISTENING || + !TrackedCallback::IsPending(accept_callback_)) { + return; + } + if (params.result() == PP_OK) { + *tcp_socket = + PPB_TCPSocket_Private_Proxy::CreateProxyResourceForConnectedSocket( + pp_instance(), + accepted_socket_id, + local_addr, + remote_addr); + } + accept_callback_->Run(params.result()); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/tcp_server_socket_private_resource.h b/chromium/ppapi/proxy/tcp_server_socket_private_resource.h new file mode 100644 index 00000000000..95febde92cd --- /dev/null +++ b/chromium/ppapi/proxy/tcp_server_socket_private_resource.h @@ -0,0 +1,69 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_TCP_SERVER_SOCKET_PRIVATE_RESOURCE_H_ +#define PPAPI_PROXY_TCP_SERVER_SOCKET_PRIVATE_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_tcp_server_socket_private_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT TCPServerSocketPrivateResource + : public PluginResource, + public thunk::PPB_TCPServerSocket_Private_API { + public: + TCPServerSocketPrivateResource(Connection connection, PP_Instance instance); + virtual ~TCPServerSocketPrivateResource(); + + // PluginResource implementation. + virtual thunk::PPB_TCPServerSocket_Private_API* + AsPPB_TCPServerSocket_Private_API() OVERRIDE; + + // PPB_TCPServerSocket_Private_API implementation. + virtual int32_t Listen(const PP_NetAddress_Private* addr, + int32_t backlog, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Accept(PP_Resource* tcp_socket, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t GetLocalAddress(PP_NetAddress_Private* addr) OVERRIDE; + virtual void StopListening() OVERRIDE; + + private: + enum State { + STATE_BEFORE_LISTENING, + STATE_LISTENING, + STATE_CLOSED + }; + + // IPC message handlers. + void OnPluginMsgListenReply(const ResourceMessageReplyParams& params, + const PP_NetAddress_Private& local_addr); + void OnPluginMsgAcceptReply(PP_Resource* tcp_socket, + const ResourceMessageReplyParams& params, + uint32 accepted_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); + + State state_; + PP_NetAddress_Private local_addr_; + + uint32 plugin_dispatcher_id_; + + scoped_refptr<TrackedCallback> listen_callback_; + scoped_refptr<TrackedCallback> accept_callback_; + + DISALLOW_COPY_AND_ASSIGN(TCPServerSocketPrivateResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_TCP_SERVER_SOCKET_PRIVATE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/truetype_font_resource.cc b/chromium/ppapi/proxy/truetype_font_resource.cc new file mode 100644 index 00000000000..1de32abb434 --- /dev/null +++ b/chromium/ppapi/proxy/truetype_font_resource.cc @@ -0,0 +1,130 @@ +// 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 "ppapi/proxy/truetype_font_resource.h" + +#include "base/bind.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_TrueTypeFont_API; + +namespace { + +} // namespace + +namespace ppapi { +namespace proxy { + +TrueTypeFontResource::TrueTypeFontResource( + Connection connection, + PP_Instance instance, + const PP_TrueTypeFontDesc_Dev& desc) + : PluginResource(connection, instance) { + SerializedTrueTypeFontDesc serialized_desc; + serialized_desc.SetFromPPTrueTypeFontDesc(desc); + SendCreate(RENDERER, PpapiHostMsg_TrueTypeFont_Create(serialized_desc)); +} + +TrueTypeFontResource::~TrueTypeFontResource() { +} + +PPB_TrueTypeFont_API* TrueTypeFontResource::AsPPB_TrueTypeFont_API() { + return this; +} + +int32_t TrueTypeFontResource::Describe( + PP_TrueTypeFontDesc_Dev* desc, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_TrueTypeFont_DescribeReply>(RENDERER, + PpapiHostMsg_TrueTypeFont_Describe(), + base::Bind(&TrueTypeFontResource::OnPluginMsgDescribeComplete, this, + callback, desc)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TrueTypeFontResource::GetTableTags( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_TrueTypeFont_GetTableTagsReply>(RENDERER, + PpapiHostMsg_TrueTypeFont_GetTableTags(), + base::Bind(&TrueTypeFontResource::OnPluginMsgGetTableTagsComplete, this, + callback, output)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TrueTypeFontResource::GetTable( + uint32_t table, + int32_t offset, + int32_t max_data_length, + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + Call<PpapiPluginMsg_TrueTypeFont_GetTableReply>(RENDERER, + PpapiHostMsg_TrueTypeFont_GetTable(table, offset, max_data_length), + base::Bind(&TrueTypeFontResource::OnPluginMsgGetTableComplete, this, + callback, output)); + return PP_OK_COMPLETIONPENDING; +} + +void TrueTypeFontResource::OnPluginMsgDescribeComplete( + scoped_refptr<TrackedCallback> callback, + PP_TrueTypeFontDesc_Dev* pp_desc, + const ResourceMessageReplyParams& params, + const ppapi::proxy::SerializedTrueTypeFontDesc& desc) { + int32_t result = params.result(); + if (result == PP_OK) + desc.CopyToPPTrueTypeFontDesc(pp_desc); + + callback->Run(result); +} + +void TrueTypeFontResource::OnPluginMsgGetTableTagsComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::vector<uint32_t>& tag_array) { + // The result code should contain the data size if it's positive. + int32_t result = params.result(); + DCHECK((result < 0 && tag_array.size() == 0) || + result == static_cast<int32_t>(tag_array.size())); + + ArrayWriter output; + output.set_pp_array_output(array_output); + if (output.is_valid()) + output.StoreArray(&tag_array[0], std::max(0, result)); + else + result = PP_ERROR_FAILED; + + callback->Run(result); +} + +void TrueTypeFontResource::OnPluginMsgGetTableComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::string& data) { + // The result code should contain the data size if it's positive. + int32_t result = params.result(); + DCHECK((result < 0 && data.size() == 0) || + result == static_cast<int32_t>(data.size())); + + ArrayWriter output; + output.set_pp_array_output(array_output); + if (output.is_valid()) + output.StoreArray(data.data(), std::max(0, result)); + else + result = PP_ERROR_FAILED; + + callback->Run(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/truetype_font_resource.h b/chromium/ppapi/proxy/truetype_font_resource.h new file mode 100644 index 00000000000..6aac2d569e2 --- /dev/null +++ b/chromium/ppapi/proxy/truetype_font_resource.h @@ -0,0 +1,73 @@ +// 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 PPAPI_PROXY_TRUETYPE_FONT_RESOURCE_H_ +#define PPAPI_PROXY_TRUETYPE_FONT_RESOURCE_H_ + +#include <string> + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/ppb_truetype_font_api.h" + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +struct SerializedTrueTypeFontDesc; + +class PPAPI_PROXY_EXPORT TrueTypeFontResource + : public PluginResource, + public thunk::PPB_TrueTypeFont_API { + public: + TrueTypeFontResource(Connection connection, + PP_Instance instance, + const PP_TrueTypeFontDesc_Dev& desc); + virtual ~TrueTypeFontResource(); + + // Resource overrides. + virtual thunk::PPB_TrueTypeFont_API* AsPPB_TrueTypeFont_API() OVERRIDE; + + // PPB_TrueTypeFont_API implementation. + virtual int32_t Describe( + PP_TrueTypeFontDesc_Dev* desc, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t GetTableTags( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t GetTable( + uint32_t table, + int32_t offset, + int32_t max_data_length, + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + void OnPluginMsgDescribeComplete( + scoped_refptr<TrackedCallback> callback, + PP_TrueTypeFontDesc_Dev* pp_desc, + const ResourceMessageReplyParams& params, + const ppapi::proxy::SerializedTrueTypeFontDesc& desc); + void OnPluginMsgGetTableTagsComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::vector<uint32_t>& data); + void OnPluginMsgGetTableComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::string& data); + + DISALLOW_COPY_AND_ASSIGN(TrueTypeFontResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_TRUETYPE_FONT_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/truetype_font_singleton_resource.cc b/chromium/ppapi/proxy/truetype_font_singleton_resource.cc new file mode 100644 index 00000000000..77a7432c549 --- /dev/null +++ b/chromium/ppapi/proxy/truetype_font_singleton_resource.cc @@ -0,0 +1,122 @@ +// 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 "ppapi/proxy/truetype_font_singleton_resource.h" + +#include "base/bind.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/array_writer.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { +namespace proxy { + +TrueTypeFontSingletonResource::TrueTypeFontSingletonResource( + Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { + SendCreate(BROWSER, PpapiHostMsg_TrueTypeFontSingleton_Create()); +} + +TrueTypeFontSingletonResource::~TrueTypeFontSingletonResource() { +} + +thunk::PPB_TrueTypeFont_Singleton_API* +TrueTypeFontSingletonResource::AsPPB_TrueTypeFont_Singleton_API() { + return this; +} + +int32_t TrueTypeFontSingletonResource::GetFontFamilies( + PP_Instance instance, + const PP_ArrayOutput& output, + const scoped_refptr<TrackedCallback>& callback) { + Call<PpapiPluginMsg_TrueTypeFontSingleton_GetFontFamiliesReply>(BROWSER, + PpapiHostMsg_TrueTypeFontSingleton_GetFontFamilies(), + base::Bind( + &TrueTypeFontSingletonResource::OnPluginMsgGetFontFamiliesComplete, + this, callback, output)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t TrueTypeFontSingletonResource::GetFontsInFamily( + PP_Instance instance, + PP_Var family, + const PP_ArrayOutput& output, + const scoped_refptr<TrackedCallback>& callback) { + scoped_refptr<StringVar> family_var = StringVar::FromPPVar(family); + const uint32_t kMaxFamilySizeInBytes = 1024; + if (!family_var.get() || family_var->value().size() > kMaxFamilySizeInBytes) + return PP_ERROR_BADARGUMENT; + Call<PpapiPluginMsg_TrueTypeFontSingleton_GetFontsInFamilyReply>(BROWSER, + PpapiHostMsg_TrueTypeFontSingleton_GetFontsInFamily(family_var->value()), + base::Bind( + &TrueTypeFontSingletonResource::OnPluginMsgGetFontsInFamilyComplete, + this, callback, output)); + return PP_OK_COMPLETIONPENDING; +} + +void TrueTypeFontSingletonResource::OnPluginMsgGetFontFamiliesComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::vector<std::string>& font_families) { + if (!TrackedCallback::IsPending(callback)) + return; + // The result code should contain the data size if it's positive. + int32_t result = params.result(); + DCHECK((result < 0 && font_families.size() == 0) || + result == static_cast<int32_t>(font_families.size())); + + ArrayWriter output; + output.set_pp_array_output(array_output); + if (output.is_valid()) { + std::vector< scoped_refptr<Var> > font_family_vars; + for (size_t i = 0; i < font_families.size(); i++) + font_family_vars.push_back( + scoped_refptr<Var>(new StringVar(font_families[i]))); + output.StoreVarVector(font_family_vars); + } else { + result = PP_ERROR_FAILED; + } + + callback->Run(result); +} + +void TrueTypeFontSingletonResource::OnPluginMsgGetFontsInFamilyComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::vector<SerializedTrueTypeFontDesc>& fonts) { + if (!TrackedCallback::IsPending(callback)) + return; + // The result code should contain the data size if it's positive. + int32_t result = params.result(); + DCHECK((result < 0 && fonts.size() == 0) || + result == static_cast<int32_t>(fonts.size())); + ArrayWriter output; + output.set_pp_array_output(array_output); + if (output.is_valid()) { + // Convert the message data to an array of PP_TrueTypeFontDesc_Dev structs. + // Each desc has an embedded PP_Var containing the family name. + std::vector<PP_TrueTypeFontDesc_Dev> pp_fonts(fonts.size()); + for (size_t i = 0; i < fonts.size(); i++) + fonts[i].CopyToPPTrueTypeFontDesc(&pp_fonts[i]); + + if (!output.StoreVector(pp_fonts)) { + for (size_t i = 0; i < pp_fonts.size(); i++) + PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(pp_fonts[i].family); + } + } else { + result = PP_ERROR_FAILED; + } + + callback->Run(result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/truetype_font_singleton_resource.h b/chromium/ppapi/proxy/truetype_font_singleton_resource.h new file mode 100644 index 00000000000..dee58632dcb --- /dev/null +++ b/chromium/ppapi/proxy/truetype_font_singleton_resource.h @@ -0,0 +1,65 @@ +// 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 PPAPI_PROXY_TRUETYPE_FONT_SINGLETON_RESOURCE_H_ +#define PPAPI_PROXY_TRUETYPE_FONT_SINGLETON_RESOURCE_H_ + +#include <string> +#include <vector> + +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/ppb_truetype_font_singleton_api.h" + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +struct SerializedTrueTypeFontDesc; + +// This handles the singleton calls (that don't take a PP_Resource parameter) +// on the TrueType font interface. +class TrueTypeFontSingletonResource + : public PluginResource, + public thunk::PPB_TrueTypeFont_Singleton_API { + public: + TrueTypeFontSingletonResource(Connection connection, PP_Instance instance); + virtual ~TrueTypeFontSingletonResource(); + + // Resource override. + virtual thunk::PPB_TrueTypeFont_Singleton_API* + AsPPB_TrueTypeFont_Singleton_API() OVERRIDE; + + // thunk::PPB_TrueTypeFont_Singleton_API implementation. + virtual int32_t GetFontFamilies( + PP_Instance instance, + const PP_ArrayOutput& output, + const scoped_refptr<TrackedCallback>& callback) OVERRIDE; + virtual int32_t GetFontsInFamily( + PP_Instance instance, + PP_Var family, + const PP_ArrayOutput& output, + const scoped_refptr<TrackedCallback>& callback) OVERRIDE; + + private: + void OnPluginMsgGetFontFamiliesComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::vector<std::string>& data); + void OnPluginMsgGetFontsInFamilyComplete( + scoped_refptr<TrackedCallback> callback, + PP_ArrayOutput array_output, + const ResourceMessageReplyParams& params, + const std::vector<SerializedTrueTypeFontDesc>& fonts); + + DISALLOW_COPY_AND_ASSIGN(TrueTypeFontSingletonResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_TRUETYPE_FONT_SINGLETON_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/udp_socket_private_resource.cc b/chromium/ppapi/proxy/udp_socket_private_resource.cc new file mode 100644 index 00000000000..af43c10fb05 --- /dev/null +++ b/chromium/ppapi/proxy/udp_socket_private_resource.cc @@ -0,0 +1,83 @@ +// 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 "ppapi/proxy/udp_socket_private_resource.h" + +#include "base/logging.h" +#include "ppapi/c/ppb_udp_socket.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace ppapi { +namespace proxy { + +UDPSocketPrivateResource::UDPSocketPrivateResource(Connection connection, + PP_Instance instance) + : UDPSocketResourceBase(connection, instance, true) { +} + +UDPSocketPrivateResource::~UDPSocketPrivateResource() { +} + +thunk::PPB_UDPSocket_Private_API* +UDPSocketPrivateResource::AsPPB_UDPSocket_Private_API() { + return this; +} + +int32_t UDPSocketPrivateResource::SetSocketFeature( + PP_UDPSocketFeature_Private name, + PP_Var value) { + PP_UDPSocket_Option public_name = PP_UDPSOCKET_OPTION_ADDRESS_REUSE; + switch (name) { + case PP_UDPSOCKETFEATURE_PRIVATE_ADDRESS_REUSE: + // |public_name| has been initialized above. + break; + case PP_UDPSOCKETFEATURE_PRIVATE_BROADCAST: + public_name = PP_UDPSOCKET_OPTION_BROADCAST; + break; + case PP_UDPSOCKETFEATURE_PRIVATE_COUNT: + return PP_ERROR_BADARGUMENT; + default: + NOTREACHED(); + return PP_ERROR_BADARGUMENT; + } + int32_t result = SetOptionImpl(public_name, value, NULL); + return result == PP_OK_COMPLETIONPENDING ? PP_OK : result; +} + +int32_t UDPSocketPrivateResource::Bind( + const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback) { + return BindImpl(addr, callback); +} + +PP_Bool UDPSocketPrivateResource::GetBoundAddress(PP_NetAddress_Private* addr) { + return GetBoundAddressImpl(addr); +} + +int32_t UDPSocketPrivateResource::RecvFrom( + char* buffer, + int32_t num_bytes, + scoped_refptr<TrackedCallback> callback) { + return RecvFromImpl(buffer, num_bytes, NULL, callback); +} + +PP_Bool UDPSocketPrivateResource::GetRecvFromAddress( + PP_NetAddress_Private* addr) { + return GetRecvFromAddressImpl(addr); +} + +int32_t UDPSocketPrivateResource::SendTo( + const char* buffer, + int32_t num_bytes, + const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback) { + return SendToImpl(buffer, num_bytes, addr, callback); +} + +void UDPSocketPrivateResource::Close() { + CloseImpl(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/udp_socket_private_resource.h b/chromium/ppapi/proxy/udp_socket_private_resource.h new file mode 100644 index 00000000000..48f5d71198b --- /dev/null +++ b/chromium/ppapi/proxy/udp_socket_private_resource.h @@ -0,0 +1,51 @@ +// 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_PROXY_UDP_SOCKET_PRIVATE_RESOURCE_H_ +#define PPAPI_PROXY_UDP_SOCKET_PRIVATE_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/udp_socket_resource_base.h" +#include "ppapi/thunk/ppb_udp_socket_private_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT UDPSocketPrivateResource + : public UDPSocketResourceBase, + public thunk::PPB_UDPSocket_Private_API { + public: + UDPSocketPrivateResource(Connection connection, PP_Instance instance); + virtual ~UDPSocketPrivateResource(); + + // PluginResource implementation. + virtual thunk::PPB_UDPSocket_Private_API* + AsPPB_UDPSocket_Private_API() OVERRIDE; + + // PPB_UDPSocket_Private_API implementation. + virtual int32_t SetSocketFeature(PP_UDPSocketFeature_Private name, + PP_Var value) OVERRIDE; + virtual int32_t Bind(const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Bool GetBoundAddress(PP_NetAddress_Private* addr) OVERRIDE; + virtual int32_t RecvFrom(char* buffer, + int32_t num_bytes, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Bool GetRecvFromAddress(PP_NetAddress_Private* addr) OVERRIDE; + virtual int32_t SendTo(const char* buffer, + int32_t num_bytes, + const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(UDPSocketPrivateResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_UDP_SOCKET_PRIVATE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/udp_socket_resource.cc b/chromium/ppapi/proxy/udp_socket_resource.cc new file mode 100644 index 00000000000..9ce7c91f130 --- /dev/null +++ b/chromium/ppapi/proxy/udp_socket_resource.cc @@ -0,0 +1,86 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/udp_socket_resource.h" + +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_net_address_api.h" +#include "ppapi/thunk/resource_creation_api.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef thunk::EnterResourceNoLock<thunk::PPB_NetAddress_API> + EnterNetAddressNoLock; + +} // namespace + +UDPSocketResource::UDPSocketResource(Connection connection, + PP_Instance instance) + : UDPSocketResourceBase(connection, instance, false) { +} + +UDPSocketResource::~UDPSocketResource() { +} + +thunk::PPB_UDPSocket_API* UDPSocketResource::AsPPB_UDPSocket_API() { + return this; +} + +int32_t UDPSocketResource::Bind(PP_Resource addr, + scoped_refptr<TrackedCallback> callback) { + EnterNetAddressNoLock enter(addr, true); + if (enter.failed()) + return PP_ERROR_BADARGUMENT; + + return BindImpl(&enter.object()->GetNetAddressPrivate(), callback); +} + +PP_Resource UDPSocketResource::GetBoundAddress() { + PP_NetAddress_Private addr_private; + if (!GetBoundAddressImpl(&addr_private)) + return 0; + + thunk::EnterResourceCreationNoLock enter(pp_instance()); + if (enter.failed()) + return 0; + return enter.functions()->CreateNetAddressFromNetAddressPrivate( + pp_instance(), addr_private); +} + +int32_t UDPSocketResource::RecvFrom(char* buffer, + int32_t num_bytes, + PP_Resource* addr, + scoped_refptr<TrackedCallback> callback) { + return RecvFromImpl(buffer, num_bytes, addr, callback); +} + +int32_t UDPSocketResource::SendTo(const char* buffer, + int32_t num_bytes, + PP_Resource addr, + scoped_refptr<TrackedCallback> callback) { + EnterNetAddressNoLock enter(addr, true); + if (enter.failed()) + return PP_ERROR_BADARGUMENT; + + return SendToImpl(buffer, num_bytes, &enter.object()->GetNetAddressPrivate(), + callback); +} + +void UDPSocketResource::Close() { + CloseImpl(); +} + +int32_t UDPSocketResource::SetOption( + PP_UDPSocket_Option name, + const PP_Var& value, + scoped_refptr<TrackedCallback> callback) { + return SetOptionImpl(name, value, callback); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/udp_socket_resource.h b/chromium/ppapi/proxy/udp_socket_resource.h new file mode 100644 index 00000000000..7df9797fb07 --- /dev/null +++ b/chromium/ppapi/proxy/udp_socket_resource.h @@ -0,0 +1,50 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_UDP_SOCKET_RESOURCE_H_ +#define PPAPI_PROXY_UDP_SOCKET_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/udp_socket_resource_base.h" +#include "ppapi/thunk/ppb_udp_socket_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT UDPSocketResource : public UDPSocketResourceBase, + public thunk::PPB_UDPSocket_API { + public: + UDPSocketResource(Connection connection, PP_Instance instance); + virtual ~UDPSocketResource(); + + // PluginResource implementation. + virtual thunk::PPB_UDPSocket_API* AsPPB_UDPSocket_API() OVERRIDE; + + // thunk::PPB_UDPSocket_API implementation. + virtual int32_t Bind(PP_Resource addr, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Resource GetBoundAddress() OVERRIDE; + virtual int32_t RecvFrom(char* buffer, + int32_t num_bytes, + PP_Resource* addr, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t SendTo(const char* buffer, + int32_t num_bytes, + PP_Resource addr, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + virtual int32_t SetOption(PP_UDPSocket_Option name, + const PP_Var& value, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(UDPSocketResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_UDP_SOCKET_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/udp_socket_resource_base.cc b/chromium/ppapi/proxy/udp_socket_resource_base.cc new file mode 100644 index 00000000000..166f2e30856 --- /dev/null +++ b/chromium/ppapi/proxy/udp_socket_resource_base.cc @@ -0,0 +1,301 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/udp_socket_resource_base.h" + +#include <algorithm> +#include <cstring> + +#include "base/logging.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/socket_option_data.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" + +namespace ppapi { +namespace proxy { + +namespace { + +int32_t ConvertPPError(int32_t pp_error, bool private_api) { + // The private API doesn't return network-specific error codes or + // PP_ERROR_NOACCESS. In order to preserve the behavior, we convert those to + // PP_ERROR_FAILED. + if (private_api && + (pp_error <= PP_ERROR_CONNECTION_CLOSED || + pp_error == PP_ERROR_NOACCESS)) { + return PP_ERROR_FAILED; + } + + return pp_error; +} + +} // namespace + +const int32_t UDPSocketResourceBase::kMaxReadSize = 1024 * 1024; +const int32_t UDPSocketResourceBase::kMaxWriteSize = 1024 * 1024; +const int32_t UDPSocketResourceBase::kMaxSendBufferSize = + 1024 * UDPSocketResourceBase::kMaxWriteSize; +const int32_t UDPSocketResourceBase::kMaxReceiveBufferSize = + 1024 * UDPSocketResourceBase::kMaxReadSize; + + +UDPSocketResourceBase::UDPSocketResourceBase(Connection connection, + PP_Instance instance, + bool private_api) + : PluginResource(connection, instance), + private_api_(private_api), + bound_(false), + closed_(false), + read_buffer_(NULL), + bytes_to_read_(-1) { + recvfrom_addr_.size = 0; + memset(recvfrom_addr_.data, 0, + arraysize(recvfrom_addr_.data) * sizeof(*recvfrom_addr_.data)); + bound_addr_.size = 0; + memset(bound_addr_.data, 0, + arraysize(bound_addr_.data) * sizeof(*bound_addr_.data)); + + if (private_api) + SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate()); + else + SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create()); +} + +UDPSocketResourceBase::~UDPSocketResourceBase() { +} + +int32_t UDPSocketResourceBase::SetOptionImpl( + PP_UDPSocket_Option name, + const PP_Var& value, + scoped_refptr<TrackedCallback> callback) { + if (closed_) + return PP_ERROR_FAILED; + + SocketOptionData option_data; + switch (name) { + case PP_UDPSOCKET_OPTION_ADDRESS_REUSE: + case PP_UDPSOCKET_OPTION_BROADCAST: { + if (bound_) + return PP_ERROR_FAILED; + if (value.type != PP_VARTYPE_BOOL) + return PP_ERROR_BADARGUMENT; + option_data.SetBool(PP_ToBool(value.value.as_bool)); + break; + } + case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE: + case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: { + if (!bound_) + return PP_ERROR_FAILED; + if (value.type != PP_VARTYPE_INT32) + return PP_ERROR_BADARGUMENT; + option_data.SetInt32(value.value.as_int); + break; + } + default: { + NOTREACHED(); + return PP_ERROR_BADARGUMENT; + } + } + + Call<PpapiPluginMsg_UDPSocket_SetOptionReply>( + BROWSER, + PpapiHostMsg_UDPSocket_SetOption(name, option_data), + base::Bind(&UDPSocketResourceBase::OnPluginMsgSetOptionReply, + base::Unretained(this), + callback)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t UDPSocketResourceBase::BindImpl( + const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback) { + if (!addr) + return PP_ERROR_BADARGUMENT; + if (bound_ || closed_) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(bind_callback_)) + return PP_ERROR_INPROGRESS; + + bind_callback_ = callback; + + // Send the request, the browser will call us back via BindReply. + Call<PpapiPluginMsg_UDPSocket_BindReply>( + BROWSER, + PpapiHostMsg_UDPSocket_Bind(*addr), + base::Bind(&UDPSocketResourceBase::OnPluginMsgBindReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} + +PP_Bool UDPSocketResourceBase::GetBoundAddressImpl( + PP_NetAddress_Private* addr) { + if (!addr || !bound_ || closed_) + return PP_FALSE; + + *addr = bound_addr_; + return PP_TRUE; +} + +int32_t UDPSocketResourceBase::RecvFromImpl( + char* buffer, + int32_t num_bytes, + PP_Resource* addr, + scoped_refptr<TrackedCallback> callback) { + if (!buffer || num_bytes <= 0) + return PP_ERROR_BADARGUMENT; + if (!bound_) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(recvfrom_callback_)) + return PP_ERROR_INPROGRESS; + + read_buffer_ = buffer; + bytes_to_read_ = std::min(num_bytes, kMaxReadSize); + recvfrom_callback_ = callback; + + // Send the request, the browser will call us back via RecvFromReply. + Call<PpapiPluginMsg_UDPSocket_RecvFromReply>( + BROWSER, + PpapiHostMsg_UDPSocket_RecvFrom(bytes_to_read_), + base::Bind(&UDPSocketResourceBase::OnPluginMsgRecvFromReply, + base::Unretained(this), addr)); + return PP_OK_COMPLETIONPENDING; +} + +PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( + PP_NetAddress_Private* addr) { + if (!addr) + return PP_FALSE; + *addr = recvfrom_addr_; + return PP_TRUE; +} + +int32_t UDPSocketResourceBase::SendToImpl( + const char* buffer, + int32_t num_bytes, + const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback) { + if (!buffer || num_bytes <= 0 || !addr) + return PP_ERROR_BADARGUMENT; + if (!bound_) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(sendto_callback_)) + return PP_ERROR_INPROGRESS; + + if (num_bytes > kMaxWriteSize) + num_bytes = kMaxWriteSize; + + sendto_callback_ = callback; + + // Send the request, the browser will call us back via SendToReply. + Call<PpapiPluginMsg_UDPSocket_SendToReply>( + BROWSER, + PpapiHostMsg_UDPSocket_SendTo(std::string(buffer, num_bytes), *addr), + base::Bind(&UDPSocketResourceBase::OnPluginMsgSendToReply, + base::Unretained(this))); + return PP_OK_COMPLETIONPENDING; +} + +void UDPSocketResourceBase::CloseImpl() { + if(closed_) + return; + + bound_ = false; + closed_ = true; + + Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); + + PostAbortIfNecessary(&bind_callback_); + PostAbortIfNecessary(&recvfrom_callback_); + PostAbortIfNecessary(&sendto_callback_); + + read_buffer_ = NULL; + bytes_to_read_ = -1; +} + +void UDPSocketResourceBase::PostAbortIfNecessary( + scoped_refptr<TrackedCallback>* callback) { + if (TrackedCallback::IsPending(*callback)) + (*callback)->PostAbort(); +} + +void UDPSocketResourceBase::OnPluginMsgSetOptionReply( + scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params) { + if (TrackedCallback::IsPending(callback)) + callback->Run(ConvertPPError(params.result(), private_api_)); +} + +void UDPSocketResourceBase::OnPluginMsgBindReply( + const ResourceMessageReplyParams& params, + const PP_NetAddress_Private& bound_addr) { + // It is possible that |bind_callback_| is pending while |closed_| is true: + // CloseImpl() has been called, but a BindReply came earlier than the task to + // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| + // in that case. + if (!TrackedCallback::IsPending(bind_callback_) || closed_) + return; + + if (params.result() == PP_OK) + bound_ = true; + bound_addr_ = bound_addr; + bind_callback_->Run(ConvertPPError(params.result(), private_api_)); +} + +void UDPSocketResourceBase::OnPluginMsgRecvFromReply( + PP_Resource* output_addr, + const ResourceMessageReplyParams& params, + const std::string& data, + const PP_NetAddress_Private& addr) { + // It is possible that |recvfrom_callback_| is pending while |read_buffer_| is + // NULL: CloseImpl() has been called, but a RecvFromReply came earlier than + // the task to abort |recvfrom_callback_|. We shouldn't access the buffer in + // that case. The user may have released it. + if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_) + return; + + int32_t result = params.result(); + if (result == PP_OK && output_addr) { + thunk::EnterResourceCreationNoLock enter(pp_instance()); + if (enter.succeeded()) { + *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate( + pp_instance(), addr); + } else { + result = PP_ERROR_FAILED; + } + } + + if (result == PP_OK) { + CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_); + if (!data.empty()) + memcpy(read_buffer_, data.c_str(), data.size()); + } + + read_buffer_ = NULL; + bytes_to_read_ = -1; + recvfrom_addr_ = addr; + + if (result == PP_OK) + recvfrom_callback_->Run(static_cast<int32_t>(data.size())); + else + recvfrom_callback_->Run(ConvertPPError(result, private_api_)); +} + +void UDPSocketResourceBase::OnPluginMsgSendToReply( + const ResourceMessageReplyParams& params, + int32_t bytes_written) { + if (!TrackedCallback::IsPending(sendto_callback_)) + return; + + if (params.result() == PP_OK) + sendto_callback_->Run(bytes_written); + else + sendto_callback_->Run(ConvertPPError(params.result(), private_api_)); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/udp_socket_resource_base.h b/chromium/ppapi/proxy/udp_socket_resource_base.h new file mode 100644 index 00000000000..925475e0e1a --- /dev/null +++ b/chromium/ppapi/proxy/udp_socket_resource_base.h @@ -0,0 +1,103 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_UDP_SOCKET_RESOURCE_BASE_H_ +#define PPAPI_PROXY_UDP_SOCKET_RESOURCE_BASE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "ppapi/c/ppb_udp_socket.h" +#include "ppapi/c/private/ppb_net_address_private.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace ppapi { +namespace proxy { + +class ResourceMessageReplyParams; + +class PPAPI_PROXY_EXPORT UDPSocketResourceBase: public PluginResource { + public: + // The maximum number of bytes that each PpapiHostMsg_PPBUDPSocket_RecvFrom + // message is allowed to request. + static const int32_t kMaxReadSize; + // The maximum number of bytes that each PpapiHostMsg_PPBUDPSocket_SendTo + // message is allowed to carry. + static const int32_t kMaxWriteSize; + + // The maximum number that we allow for setting + // PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE. This number is only for input + // argument sanity check, it doesn't mean the browser guarantees to support + // such a buffer size. + static const int32_t kMaxSendBufferSize; + // The maximum number that we allow for setting + // PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE. This number is only for input + // argument sanity check, it doesn't mean the browser guarantees to support + // such a buffer size. + static const int32_t kMaxReceiveBufferSize; + + protected: + UDPSocketResourceBase(Connection connection, + PP_Instance instance, + bool private_api); + virtual ~UDPSocketResourceBase(); + + int32_t SetOptionImpl(PP_UDPSocket_Option name, + const PP_Var& value, + scoped_refptr<TrackedCallback> callback); + int32_t BindImpl(const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback); + PP_Bool GetBoundAddressImpl(PP_NetAddress_Private* addr); + // |addr| could be NULL to indicate that an output value is not needed. + int32_t RecvFromImpl(char* buffer, + int32_t num_bytes, + PP_Resource* addr, + scoped_refptr<TrackedCallback> callback); + PP_Bool GetRecvFromAddressImpl(PP_NetAddress_Private* addr); + int32_t SendToImpl(const char* buffer, + int32_t num_bytes, + const PP_NetAddress_Private* addr, + scoped_refptr<TrackedCallback> callback); + void CloseImpl(); + + private: + void PostAbortIfNecessary(scoped_refptr<TrackedCallback>* callback); + + // IPC message handlers. + void OnPluginMsgSetOptionReply(scoped_refptr<TrackedCallback> callback, + const ResourceMessageReplyParams& params); + void OnPluginMsgBindReply(const ResourceMessageReplyParams& params, + const PP_NetAddress_Private& bound_addr); + void OnPluginMsgRecvFromReply(PP_Resource* output_addr, + const ResourceMessageReplyParams& params, + const std::string& data, + const PP_NetAddress_Private& addr); + void OnPluginMsgSendToReply(const ResourceMessageReplyParams& params, + int32_t bytes_written); + + bool private_api_; + bool bound_; + bool closed_; + + scoped_refptr<TrackedCallback> bind_callback_; + scoped_refptr<TrackedCallback> recvfrom_callback_; + scoped_refptr<TrackedCallback> sendto_callback_; + + char* read_buffer_; + int32_t bytes_to_read_; + + PP_NetAddress_Private recvfrom_addr_; + PP_NetAddress_Private bound_addr_; + + DISALLOW_COPY_AND_ASSIGN(UDPSocketResourceBase); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_UDP_SOCKET_RESOURCE_BASE_H_ diff --git a/chromium/ppapi/proxy/url_loader_resource.cc b/chromium/ppapi/proxy/url_loader_resource.cc new file mode 100644 index 00000000000..5bbc9372ff2 --- /dev/null +++ b/chromium/ppapi/proxy/url_loader_resource.cc @@ -0,0 +1,392 @@ +// 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 "ppapi/proxy/url_loader_resource.h" + +#include "base/logging.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/url_request_info_resource.h" +#include "ppapi/proxy/url_response_info_resource.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/url_response_info_data.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_URLLoader_API; +using ppapi::thunk::PPB_URLRequestInfo_API; + +#ifdef _MSC_VER +// Do not warn about use of std::copy with raw pointers. +#pragma warning(disable : 4996) +#endif + +namespace ppapi { +namespace proxy { + +URLLoaderResource::URLLoaderResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + mode_(MODE_WAITING_TO_OPEN), + status_callback_(NULL), + bytes_sent_(0), + total_bytes_to_be_sent_(-1), + bytes_received_(0), + total_bytes_to_be_received_(-1), + user_buffer_(NULL), + user_buffer_size_(0), + done_status_(PP_OK_COMPLETIONPENDING), + is_streaming_to_file_(false), + is_asynchronous_load_suspended_(false) { + SendCreate(RENDERER, PpapiHostMsg_URLLoader_Create()); +} + +URLLoaderResource::URLLoaderResource(Connection connection, + PP_Instance instance, + int pending_main_document_loader_id, + const ppapi::URLResponseInfoData& data) + : PluginResource(connection, instance), + mode_(MODE_OPENING), + status_callback_(NULL), + bytes_sent_(0), + total_bytes_to_be_sent_(-1), + bytes_received_(0), + total_bytes_to_be_received_(-1), + user_buffer_(NULL), + user_buffer_size_(0), + done_status_(PP_OK_COMPLETIONPENDING), + is_streaming_to_file_(false), + is_asynchronous_load_suspended_(false) { + AttachToPendingHost(RENDERER, pending_main_document_loader_id); + SaveResponseInfo(data); +} + +URLLoaderResource::~URLLoaderResource() { +} + +PPB_URLLoader_API* URLLoaderResource::AsPPB_URLLoader_API() { + return this; +} + +int32_t URLLoaderResource::Open(PP_Resource request_id, + scoped_refptr<TrackedCallback> callback) { + EnterResourceNoLock<PPB_URLRequestInfo_API> enter_request(request_id, true); + if (enter_request.failed()) { + Log(PP_LOGLEVEL_ERROR, + "PPB_URLLoader.Open: invalid request resource ID. (Hint to C++ wrapper" + " users: use the ResourceRequest constructor that takes an instance or" + " else the request will be null.)"); + return PP_ERROR_BADARGUMENT; + } + return Open(enter_request.object()->GetData(), 0, callback); +} + +int32_t URLLoaderResource::Open( + const ::ppapi::URLRequestInfoData& request_data, + int requestor_pid, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (mode_ != MODE_WAITING_TO_OPEN) + return PP_ERROR_INPROGRESS; + + request_data_ = request_data; + + mode_ = MODE_OPENING; + is_asynchronous_load_suspended_ = false; + + RegisterCallback(callback); + Post(RENDERER, PpapiHostMsg_URLLoader_Open(request_data)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t URLLoaderResource::FollowRedirect( + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (mode_ != MODE_OPENING) + return PP_ERROR_INPROGRESS; + + SetDefersLoading(false); // Allow the redirect to continue. + RegisterCallback(callback); + return PP_OK_COMPLETIONPENDING; +} + +PP_Bool URLLoaderResource::GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) { + if (!request_data_.record_upload_progress) { + *bytes_sent = 0; + *total_bytes_to_be_sent = 0; + return PP_FALSE; + } + *bytes_sent = bytes_sent_; + *total_bytes_to_be_sent = total_bytes_to_be_sent_; + return PP_TRUE; +} + +PP_Bool URLLoaderResource::GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) { + if (!request_data_.record_download_progress) { + *bytes_received = 0; + *total_bytes_to_be_received = 0; + return PP_FALSE; + } + *bytes_received = bytes_received_; + *total_bytes_to_be_received = total_bytes_to_be_received_; + return PP_TRUE; +} + +PP_Resource URLLoaderResource::GetResponseInfo() { + if (response_info_.get()) + return response_info_->GetReference(); + return 0; +} + +int32_t URLLoaderResource::ReadResponseBody( + void* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (!response_info_.get() || + !response_info_->data().body_as_file_ref.resource.is_null()) + return PP_ERROR_FAILED; + if (bytes_to_read <= 0 || !buffer) + return PP_ERROR_BADARGUMENT; + + user_buffer_ = static_cast<char*>(buffer); + user_buffer_size_ = bytes_to_read; + + if (!buffer_.empty()) + return FillUserBuffer(); + + // We may have already reached EOF. + if (done_status_ != PP_OK_COMPLETIONPENDING) { + user_buffer_ = NULL; + user_buffer_size_ = 0; + return done_status_; + } + + RegisterCallback(callback); + return PP_OK_COMPLETIONPENDING; +} + +int32_t URLLoaderResource::FinishStreamingToFile( + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (!response_info_.get() || + response_info_->data().body_as_file_ref.resource.is_null()) + return PP_ERROR_FAILED; + + // We may have already reached EOF. + if (done_status_ != PP_OK_COMPLETIONPENDING) + return done_status_; + + is_streaming_to_file_ = true; + if (is_asynchronous_load_suspended_) + SetDefersLoading(false); + + // Wait for didFinishLoading / didFail. + RegisterCallback(callback); + return PP_OK_COMPLETIONPENDING; +} + +void URLLoaderResource::Close() { + mode_ = MODE_LOAD_COMPLETE; + done_status_ = PP_ERROR_ABORTED; + + Post(RENDERER, PpapiHostMsg_URLLoader_Close()); + + // Abort the callbacks, the plugin doesn't want to be called back after this. + // TODO(brettw) this should fix bug 69457, mark it fixed. ============ + if (TrackedCallback::IsPending(pending_callback_)) + pending_callback_->PostAbort(); +} + +void URLLoaderResource::GrantUniversalAccess() { + Post(RENDERER, PpapiHostMsg_URLLoader_GrantUniversalAccess()); +} + +void URLLoaderResource::RegisterStatusCallback( + PP_URLLoaderTrusted_StatusCallback callback) { + status_callback_ = callback; +} + +void URLLoaderResource::OnReplyReceived( + const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(URLLoaderResource, msg) + case PpapiPluginMsg_URLLoader_SendData::ID: + // Special message, manually dispatch since we don't want the automatic + // unpickling. + OnPluginMsgSendData(params, msg); + break; + + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_URLLoader_ReceivedResponse, + OnPluginMsgReceivedResponse) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_URLLoader_FinishedLoading, + OnPluginMsgFinishedLoading) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_URLLoader_UpdateProgress, + OnPluginMsgUpdateProgress) + IPC_END_MESSAGE_MAP() +} + +void URLLoaderResource::OnPluginMsgReceivedResponse( + const ResourceMessageReplyParams& params, + const URLResponseInfoData& data) { + SaveResponseInfo(data); + RunCallback(PP_OK); +} + +void URLLoaderResource::OnPluginMsgSendData( + const ResourceMessageReplyParams& params, + const IPC::Message& message) { + PickleIterator iter(message); + const char* data; + int data_length; + if (!iter.ReadData(&data, &data_length)) { + NOTREACHED() << "Expecting data"; + return; + } + + mode_ = MODE_STREAMING_DATA; + buffer_.insert(buffer_.end(), data, data + data_length); + + // To avoid letting the network stack download an entire stream all at once, + // defer loading when we have enough buffer. + // Check for this before we run the callback, even though that could move + // data out of the buffer. Doing anything after the callback is unsafe. + DCHECK(request_data_.prefetch_buffer_lower_threshold < + request_data_.prefetch_buffer_upper_threshold); + if (!is_streaming_to_file_ && + !is_asynchronous_load_suspended_ && + (buffer_.size() >= static_cast<size_t>( + request_data_.prefetch_buffer_upper_threshold))) { + DVLOG(1) << "Suspending async load - buffer size: " << buffer_.size(); + SetDefersLoading(true); + } + + if (user_buffer_) + RunCallback(FillUserBuffer()); + else + DCHECK(!TrackedCallback::IsPending(pending_callback_)); +} + +void URLLoaderResource::OnPluginMsgFinishedLoading( + const ResourceMessageReplyParams& params, + int32_t result) { + mode_ = MODE_LOAD_COMPLETE; + done_status_ = result; + user_buffer_ = NULL; + user_buffer_size_ = 0; + + // If the client hasn't called any function that takes a callback since + // the initial call to Open, or called ReadResponseBody and got a + // synchronous return, then the callback will be NULL. + if (TrackedCallback::IsPending(pending_callback_)) + RunCallback(done_status_); +} + +void URLLoaderResource::OnPluginMsgUpdateProgress( + const ResourceMessageReplyParams& params, + int64_t bytes_sent, + int64_t total_bytes_to_be_sent, + int64_t bytes_received, + int64_t total_bytes_to_be_received) { + bytes_sent_ = bytes_sent; + total_bytes_to_be_sent_ = total_bytes_to_be_sent; + bytes_received_ = bytes_received; + total_bytes_to_be_received_ = total_bytes_to_be_received; + + if (status_callback_) + status_callback_(pp_instance(), pp_resource(), + bytes_sent_, total_bytes_to_be_sent_, + bytes_received_, total_bytes_to_be_received_); +} + +void URLLoaderResource::SetDefersLoading(bool defers_loading) { + Post(RENDERER, PpapiHostMsg_URLLoader_SetDeferLoading(defers_loading)); +} + +int32_t URLLoaderResource::ValidateCallback( + scoped_refptr<TrackedCallback> callback) { + DCHECK(callback.get()); + if (TrackedCallback::IsPending(pending_callback_)) + return PP_ERROR_INPROGRESS; + return PP_OK; +} + +void URLLoaderResource::RegisterCallback( + scoped_refptr<TrackedCallback> callback) { + DCHECK(!TrackedCallback::IsPending(pending_callback_)); + pending_callback_ = callback; +} + +void URLLoaderResource::RunCallback(int32_t result) { + // This may be null when this is a main document loader. + if (!pending_callback_.get()) + return; + + // If |user_buffer_| was set as part of registering a callback, the paths + // which trigger that callack must have cleared it since the callback is now + // free to delete it. + DCHECK(!user_buffer_); + + // As a second line of defense, clear the |user_buffer_| in case the + // callbacks get called in an unexpected order. + user_buffer_ = NULL; + user_buffer_size_ = 0; + pending_callback_->Run(result); +} + +void URLLoaderResource::SaveResponseInfo(const URLResponseInfoData& data) { + // Create a proxy resource for the the file ref host resource if needed. + PP_Resource body_as_file_ref = 0; + if (!data.body_as_file_ref.resource.is_null()) { + thunk::EnterResourceCreationNoLock enter(pp_instance()); + body_as_file_ref = + enter.functions()->CreateFileRef(data.body_as_file_ref); + } + response_info_ = new URLResponseInfoResource( + connection(), pp_instance(), data, body_as_file_ref); +} + +size_t URLLoaderResource::FillUserBuffer() { + DCHECK(user_buffer_); + DCHECK(user_buffer_size_); + + size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_); + std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_); + buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy); + + // If the buffer is getting too empty, resume asynchronous loading. + if (is_asynchronous_load_suspended_ && + buffer_.size() <= static_cast<size_t>( + request_data_.prefetch_buffer_lower_threshold)) { + DVLOG(1) << "Resuming async load - buffer size: " << buffer_.size(); + SetDefersLoading(false); + } + + // Reset for next time. + user_buffer_ = NULL; + user_buffer_size_ = 0; + return bytes_to_copy; +} + +} // namespace proxy +} // namespace ppapi
\ No newline at end of file diff --git a/chromium/ppapi/proxy/url_loader_resource.h b/chromium/ppapi/proxy/url_loader_resource.h new file mode 100644 index 00000000000..685ccfe1243 --- /dev/null +++ b/chromium/ppapi/proxy/url_loader_resource.h @@ -0,0 +1,146 @@ +// 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 PPAPI_PROXY_URL_LOADER_RESOURCE_H_ +#define PPAPI_PROXY_URL_LOADER_RESOURCE_H_ + +#include <deque> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/url_request_info_data.h" +#include "ppapi/thunk/ppb_url_loader_api.h" + +namespace ppapi { +namespace proxy { + +class URLResponseInfoResource; + +class PPAPI_PROXY_EXPORT URLLoaderResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_URLLoader_API) { + public: + // Constructor for plugin-initiated loads. + URLLoaderResource(Connection connection, + PP_Instance instance); + + // Constructor for renderer-initiated (document) loads. The loader ID is the + // pending host ID for the already-created host in the renderer, and the + // response data is the response for the already-opened connection. + URLLoaderResource(Connection connection, + PP_Instance instance, + int pending_main_document_loader_id, + const URLResponseInfoData& data); + + virtual ~URLLoaderResource(); + + // Resource override. + thunk::PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE; + + // PPB_URLLoader_API implementation. + virtual int32_t Open(PP_Resource request_id, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Open(const URLRequestInfoData& data, + int requestor_pid, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t FollowRedirect( + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Bool GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) OVERRIDE; + virtual PP_Bool GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) OVERRIDE; + virtual PP_Resource GetResponseInfo() OVERRIDE; + virtual int32_t ReadResponseBody( + void* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t FinishStreamingToFile( + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + virtual void GrantUniversalAccess() OVERRIDE; + virtual void RegisterStatusCallback( + PP_URLLoaderTrusted_StatusCallback callback) OVERRIDE; + + // PluginResource implementation. + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + private: + enum Mode { + // The plugin has not called Open() yet. + MODE_WAITING_TO_OPEN, + + // The plugin is waiting for the Open() or FollowRedirect callback. + MODE_OPENING, + + // We've started to receive data and may receive more. + MODE_STREAMING_DATA, + + // All data has been streamed or there was an error. + MODE_LOAD_COMPLETE + }; + + // IPC message handlers. + void OnPluginMsgReceivedResponse(const ResourceMessageReplyParams& params, + const URLResponseInfoData& data); + void OnPluginMsgSendData(const ResourceMessageReplyParams& params, + const IPC::Message& message); + void OnPluginMsgFinishedLoading(const ResourceMessageReplyParams& params, + int32_t result); + void OnPluginMsgUpdateProgress(const ResourceMessageReplyParams& params, + int64_t bytes_sent, + int64_t total_bytes_to_be_sent, + int64_t bytes_received, + int64_t total_bytes_to_be_received); + + // Sends the defers loading message to the renderer to block or unblock the + // load. + void SetDefersLoading(bool defers_loading); + + int32_t ValidateCallback(scoped_refptr<TrackedCallback> callback); + + // Sets up |callback| as the pending callback. This should only be called once + // it is certain that |PP_OK_COMPLETIONPENDING| will be returned. + void RegisterCallback(scoped_refptr<TrackedCallback> callback); + + void RunCallback(int32_t result); + + // Saves the given response info to response_info_, handling file refs if + // necessary. This does not issue any callbacks. + void SaveResponseInfo(const URLResponseInfoData& data); + + size_t FillUserBuffer(); + + Mode mode_; + URLRequestInfoData request_data_; + + scoped_refptr<TrackedCallback> pending_callback_; + + PP_URLLoaderTrusted_StatusCallback status_callback_; + + std::deque<char> buffer_; + int64_t bytes_sent_; + int64_t total_bytes_to_be_sent_; + int64_t bytes_received_; + int64_t total_bytes_to_be_received_; + char* user_buffer_; + size_t user_buffer_size_; + int32_t done_status_; + bool is_streaming_to_file_; + bool is_asynchronous_load_suspended_; + + // The response info if we've received it. + scoped_refptr<URLResponseInfoResource> response_info_; + + DISALLOW_COPY_AND_ASSIGN(URLLoaderResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_URL_LOADER_RESOURCE_H_
\ No newline at end of file diff --git a/chromium/ppapi/proxy/url_request_info_resource.cc b/chromium/ppapi/proxy/url_request_info_resource.cc new file mode 100644 index 00000000000..19d02d726ce --- /dev/null +++ b/chromium/ppapi/proxy/url_request_info_resource.cc @@ -0,0 +1,215 @@ +// 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 "ppapi/proxy/url_request_info_resource.h" + +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_file_ref_api.h" + +namespace ppapi { +namespace proxy { + +URLRequestInfoResource::URLRequestInfoResource(Connection connection, + PP_Instance instance, + const URLRequestInfoData& data) + : PluginResource(connection, instance), + data_(data) { +} + +URLRequestInfoResource::~URLRequestInfoResource() { +} + +thunk::PPB_URLRequestInfo_API* +URLRequestInfoResource::AsPPB_URLRequestInfo_API() { + return this; +} + +PP_Bool URLRequestInfoResource::SetProperty(PP_URLRequestProperty property, + PP_Var var) { + // IMPORTANT: Do not do security validation of parameters at this level + // without also adding them to PPB_URLRequestInfo_Impl::ValidateData. This + // code is used both in the plugin (which we don't trust) and in the renderer + // (which we trust more). When running out-of-process, the plugin calls this + // function to configure the URLRequestInfoData, which is then sent to + // the renderer and *not* run through SetProperty again. + // + // This means that anything in the PPB_URLRequestInfo_Data needs to be + // validated at the time the URL is requested (which is what ValidateData + // does). If your feature requires security checks, it should be in the + // implementation in the renderer when the WebKit request is actually + // constructed. + // + // It is legal to do some validation here if you want to report failure to + // the plugin as a convenience, as long as you also do it in the renderer + // later. + PP_Bool result = PP_FALSE; + switch (var.type) { + case PP_VARTYPE_UNDEFINED: + result = PP_FromBool(SetUndefinedProperty(property)); + break; + case PP_VARTYPE_BOOL: + result = PP_FromBool( + SetBooleanProperty(property, PP_ToBool(var.value.as_bool))); + break; + case PP_VARTYPE_INT32: + result = PP_FromBool( + SetIntegerProperty(property, var.value.as_int)); + break; + case PP_VARTYPE_STRING: { + StringVar* string = StringVar::FromPPVar(var); + if (string) + result = PP_FromBool(SetStringProperty(property, string->value())); + break; + } + default: + break; + } + return result; +} + +PP_Bool URLRequestInfoResource::AppendDataToBody(const void* data, + uint32_t len) { + if (len > 0) { + data_.body.push_back(URLRequestInfoData::BodyItem( + std::string(static_cast<const char*>(data), len))); + } + return PP_TRUE; +} + +PP_Bool URLRequestInfoResource::AppendFileToBody( + PP_Resource file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) { + thunk::EnterResourceNoLock<thunk::PPB_FileRef_API> enter(file_ref, true); + if (enter.failed()) + return PP_FALSE; + + // Ignore a call to append nothing. + if (number_of_bytes == 0) + return PP_TRUE; + + // Check for bad values. (-1 means read until end of file.) + if (start_offset < 0 || number_of_bytes < -1) + return PP_FALSE; + + data_.body.push_back(URLRequestInfoData::BodyItem( + enter.resource(), + start_offset, + number_of_bytes, + expected_last_modified_time)); + return PP_TRUE; +} + +const URLRequestInfoData& URLRequestInfoResource::GetData() const { + return data_; +} + +bool URLRequestInfoResource::SetUndefinedProperty( + PP_URLRequestProperty property) { + // IMPORTANT: Do not do security validation of parameters at this level + // without also adding them to PPB_URLRequestInfo_Impl::ValidateData. See + // SetProperty() above for why. + switch (property) { + case PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL: + data_.has_custom_referrer_url = false; + data_.custom_referrer_url = std::string(); + return true; + case PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING: + data_.has_custom_content_transfer_encoding = false; + data_.custom_content_transfer_encoding = std::string(); + return true; + case PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT: + data_.has_custom_user_agent = false; + data_.custom_user_agent = std::string(); + return true; + default: + return false; + } +} + +bool URLRequestInfoResource::SetBooleanProperty( + PP_URLRequestProperty property, + bool value) { + // IMPORTANT: Do not do security validation of parameters at this level + // without also adding them to PPB_URLRequestInfo_Impl::ValidateData. See + // SetProperty() above for why. + switch (property) { + case PP_URLREQUESTPROPERTY_STREAMTOFILE: + data_.stream_to_file = value; + return true; + case PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS: + data_.follow_redirects = value; + return true; + case PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS: + data_.record_download_progress = value; + return true; + case PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS: + data_.record_upload_progress = value; + return true; + case PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS: + data_.allow_cross_origin_requests = value; + return true; + case PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS: + data_.allow_credentials = value; + return true; + default: + return false; + } +} + +bool URLRequestInfoResource::SetIntegerProperty( + PP_URLRequestProperty property, + int32_t value) { + // IMPORTANT: Do not do security validation of parameters at this level + // without also adding them to PPB_URLRequestInfo_Impl::ValidateData. See + // SetProperty() above for why. + switch (property) { + case PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD: + data_.prefetch_buffer_upper_threshold = value; + return true; + case PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD: + data_.prefetch_buffer_lower_threshold = value; + return true; + default: + return false; + } +} + +bool URLRequestInfoResource::SetStringProperty( + PP_URLRequestProperty property, + const std::string& value) { + // IMPORTANT: Do not do security validation of parameters at this level + // without also adding them to PPB_URLRequestInfo_Impl::ValidateData. See + // SetProperty() above for why. + switch (property) { + case PP_URLREQUESTPROPERTY_URL: + data_.url = value; // NOTE: This may be a relative URL. + return true; + case PP_URLREQUESTPROPERTY_METHOD: + data_.method = value; + return true; + case PP_URLREQUESTPROPERTY_HEADERS: + data_.headers = value; + return true; + case PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL: + data_.has_custom_referrer_url = true; + data_.custom_referrer_url = value; + return true; + case PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING: + data_.has_custom_content_transfer_encoding = true; + data_.custom_content_transfer_encoding = value; + return true; + case PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT: + data_.has_custom_user_agent = true; + data_.custom_user_agent = value; + return true; + default: + return false; + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/url_request_info_resource.h b/chromium/ppapi/proxy/url_request_info_resource.h new file mode 100644 index 00000000000..e3906a6f4ed --- /dev/null +++ b/chromium/ppapi/proxy/url_request_info_resource.h @@ -0,0 +1,55 @@ +// 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_PROXY_URL_REQUEST_INFO_RESOURCE_H_ +#define PPAPI_PROXY_URL_REQUEST_INFO_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/url_request_info_data.h" +#include "ppapi/thunk/ppb_url_request_info_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT URLRequestInfoResource + : public PluginResource, + public thunk::PPB_URLRequestInfo_API { + public: + URLRequestInfoResource(Connection connection, PP_Instance instance, + const URLRequestInfoData& data); + virtual ~URLRequestInfoResource(); + + // Resource overrides. + virtual thunk::PPB_URLRequestInfo_API* AsPPB_URLRequestInfo_API() OVERRIDE; + + // PPB_URLRequestInfo_API implementation. + virtual PP_Bool SetProperty(PP_URLRequestProperty property, + PP_Var var) OVERRIDE; + virtual PP_Bool AppendDataToBody(const void* data, uint32_t len) OVERRIDE; + virtual PP_Bool AppendFileToBody( + PP_Resource file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) OVERRIDE; + virtual const URLRequestInfoData& GetData() const OVERRIDE; + + bool SetUndefinedProperty(PP_URLRequestProperty property); + bool SetBooleanProperty(PP_URLRequestProperty property, bool value); + bool SetIntegerProperty(PP_URLRequestProperty property, int32_t value); + bool SetStringProperty(PP_URLRequestProperty property, + const std::string& value); + + private: + URLRequestInfoData data_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestInfoResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_URL_REQUEST_INFO_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/url_response_info_resource.cc b/chromium/ppapi/proxy/url_response_info_resource.cc new file mode 100644 index 00000000000..85dae9a1aef --- /dev/null +++ b/chromium/ppapi/proxy/url_response_info_resource.cc @@ -0,0 +1,73 @@ +// 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 "ppapi/proxy/url_response_info_resource.h" + +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" + +namespace ppapi { +namespace proxy { + +namespace { + +bool IsRedirect(int32_t status) { + return status >= 300 && status <= 399; +} + +} // namespace + +URLResponseInfoResource::URLResponseInfoResource( + Connection connection, + PP_Instance instance, + const URLResponseInfoData& data, + PP_Resource file_ref_resource) + : PluginResource(connection, instance), + data_(data), + body_as_file_ref_(ScopedPPResource::PassRef(), file_ref_resource) { +} + +URLResponseInfoResource::~URLResponseInfoResource() { +} + +thunk::PPB_URLResponseInfo_API* +URLResponseInfoResource::AsPPB_URLResponseInfo_API() { + return this; +} + +PP_Var URLResponseInfoResource::GetProperty(PP_URLResponseProperty property) { + switch (property) { + case PP_URLRESPONSEPROPERTY_URL: + return StringVar::StringToPPVar(data_.url); + case PP_URLRESPONSEPROPERTY_REDIRECTURL: + if (IsRedirect(data_.status_code)) + return StringVar::StringToPPVar(data_.redirect_url); + break; + case PP_URLRESPONSEPROPERTY_REDIRECTMETHOD: + if (IsRedirect(data_.status_code)) + return StringVar::StringToPPVar(data_.status_text); + break; + case PP_URLRESPONSEPROPERTY_STATUSCODE: + return PP_MakeInt32(data_.status_code); + case PP_URLRESPONSEPROPERTY_STATUSLINE: + return StringVar::StringToPPVar(data_.status_text); + case PP_URLRESPONSEPROPERTY_HEADERS: + return StringVar::StringToPPVar(data_.headers); + } + // The default is to return an undefined PP_Var. + return PP_MakeUndefined(); +} + +PP_Resource URLResponseInfoResource::GetBodyAsFileRef() { + if (!body_as_file_ref_.get()) + return 0; + PpapiGlobals::Get()->GetResourceTracker()->AddRefResource( + body_as_file_ref_.get()); + return body_as_file_ref_.get(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/url_response_info_resource.h b/chromium/ppapi/proxy/url_response_info_resource.h new file mode 100644 index 00000000000..dfb1f8feb60 --- /dev/null +++ b/chromium/ppapi/proxy/url_response_info_resource.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 PPAPI_PROXY_URL_RESPONSE_INFO_RESOURCE_H_ +#define PPAPI_PROXY_URL_RESPONSE_INFO_RESOURCE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/shared_impl/url_response_info_data.h" +#include "ppapi/thunk/ppb_url_response_info_api.h" + +namespace ppapi { +namespace proxy { + +class PPAPI_PROXY_EXPORT URLResponseInfoResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_URLResponseInfo_API) { + public: + // The file_ref_resource should be the body_as_file_ref host resource in the + // |data| converted to a resource valid in the current process (if we're + // downloading to a file; it will be 0 if we're not). A reference + // is passed from the caller and is taken over by this object. + URLResponseInfoResource(Connection connection, + PP_Instance instance, + const URLResponseInfoData& data, + PP_Resource file_ref_resource); + virtual ~URLResponseInfoResource(); + + // Resource override. + virtual PPB_URLResponseInfo_API* AsPPB_URLResponseInfo_API() OVERRIDE; + + // PPB_URLResponseInfo_API implementation. + virtual PP_Var GetProperty(PP_URLResponseProperty property) OVERRIDE; + virtual PP_Resource GetBodyAsFileRef() OVERRIDE; + + const URLResponseInfoData& data() const { return data_; } + + private: + URLResponseInfoData data_; + + // Non-zero when the load is being streamed to a file. + ScopedPPResource body_as_file_ref_; + + DISALLOW_COPY_AND_ASSIGN(URLResponseInfoResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_URL_RESPONSE_INFO_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/var_serialization_rules.h b/chromium/ppapi/proxy/var_serialization_rules.h new file mode 100644 index 00000000000..399cff326ec --- /dev/null +++ b/chromium/ppapi/proxy/var_serialization_rules.h @@ -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. + +#ifndef PPAPI_PROXY_VAR_SERIALIZATION_RULES_H_ +#define PPAPI_PROXY_VAR_SERIALIZATION_RULES_H_ + +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_var.h" + +#include <string> + +namespace ppapi { +namespace proxy { + +// Encapsulates the rules for serializing and deserializing vars to and from +// the local process. The renderer and the plugin process each have separate +// bookkeeping rules. +class VarSerializationRules : public base::RefCounted<VarSerializationRules> { + public: + // Caller-owned calls -------------------------------------------------------- + // + // A caller-owned call is when doing a function call with a "normal" input + // argument. The caller has a reference to the var, and the caller is + // responsible for freeing that reference. + + // Prepares the given var for sending to the remote process. For object vars, + // the returned var will contain the id valid for the host process. + // Otherwise, the returned var is valid in the local process. + virtual PP_Var SendCallerOwned(const PP_Var& var) = 0; + + // When receiving a caller-owned variable, normally we don't have to do + // anything. However, in the case of strings, we need to deserialize the + // string from IPC, call the function, and then destroy the temporary string. + // These two functions handle that process. + // + // BeginReceiveCallerOwned takes a var from IPC and returns a new var + // representing the input in the local process. + // + // EndReceiveCallerOwned releases the reference count in the Var tracker for + // the object or string that was added to the tracker. (Note, if the recipient + // took a reference to the Var, it will remain in the tracker after + // EndReceiveCallerOwned). + virtual PP_Var BeginReceiveCallerOwned(const PP_Var& var) = 0; + virtual void EndReceiveCallerOwned(const PP_Var& var) = 0; + + // Passing refs ------------------------------------------------------------- + // + // A pass-ref transfer is when ownership of a reference is passed from + // one side to the other. Normally, this happens via return values and + // output arguments, as for exceptions. The code generating the value + // (the function returning it in the case of a return value) will AddRef + // the var on behalf of the consumer of the value. Responsibility for + // Release is on the consumer (the caller of the function in the case of a + // return value). + + // Creates a var in the context of the local process from the given + // deserialized var. The input var should be the result of calling + // SendPassRef in the remote process. The return value is the var valid in + // the host process for object vars. Otherwise, the return value is a var + // which is valid in the local process. + virtual PP_Var ReceivePassRef(const PP_Var& var) = 0; + + // Prepares a var to be sent to the remote side. One local reference will + // be passed to the remote side. Call Begin* before doing the send and End* + // after doing the send + // + // For object vars, the return value from BeginSendPassRef will be the var + // valid for the host process. Otherwise, it is a var that is valid in the + // local process. This same var must be passed to EndSendPassRef. + virtual PP_Var BeginSendPassRef(const PP_Var& var) = 0; + virtual void EndSendPassRef(const PP_Var& var) = 0; + + // --------------------------------------------------------------------------- + + virtual void ReleaseObjectRef(const PP_Var& var) = 0; + + protected: + VarSerializationRules() {} + virtual ~VarSerializationRules() {} + + private: + friend class base::RefCounted<VarSerializationRules>; +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_VAR_SERIALIZATION_RULES_H_ diff --git a/chromium/ppapi/proxy/video_capture_resource.cc b/chromium/ppapi/proxy/video_capture_resource.cc new file mode 100644 index 00000000000..6ea8bd50015 --- /dev/null +++ b/chromium/ppapi/proxy/video_capture_resource.cc @@ -0,0 +1,240 @@ +// 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 "ppapi/proxy/video_capture_resource.h" + +#include "ppapi/c/dev/ppp_video_capture_dev.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/tracked_callback.h" + +namespace ppapi { +namespace proxy { + +VideoCaptureResource::VideoCaptureResource( + Connection connection, + PP_Instance instance, + PluginDispatcher* dispatcher) + : PluginResource(connection, instance), + open_state_(BEFORE_OPEN), + enumeration_helper_(this) { + SendCreate(RENDERER, PpapiHostMsg_VideoCapture_Create()); + + ppp_video_capture_impl_ = static_cast<const PPP_VideoCapture_Dev*>( + dispatcher->local_get_interface()(PPP_VIDEO_CAPTURE_DEV_INTERFACE)); +} + +VideoCaptureResource::~VideoCaptureResource() { +} + +void VideoCaptureResource::OnReplyReceived( + const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + if (enumeration_helper_.HandleReply(params, msg)) + return; + + if (params.sequence()) { + PluginResource::OnReplyReceived(params, msg); + return; + } + + IPC_BEGIN_MESSAGE_MAP(VideoCaptureResource, msg) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_VideoCapture_OnDeviceInfo, + OnPluginMsgOnDeviceInfo) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_VideoCapture_OnStatus, + OnPluginMsgOnStatus) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_VideoCapture_OnError, + OnPluginMsgOnError) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_VideoCapture_OnBufferReady, + OnPluginMsgOnBufferReady) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(NOTREACHED()) + IPC_END_MESSAGE_MAP() +} + +int32_t VideoCaptureResource::EnumerateDevices0_2( + PP_Resource* devices, + scoped_refptr<TrackedCallback> callback) { + return enumeration_helper_.EnumerateDevices0_2(devices, callback); +} + +int32_t VideoCaptureResource::EnumerateDevices( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) { + return enumeration_helper_.EnumerateDevices(output, callback); +} + +int32_t VideoCaptureResource::MonitorDeviceChange( + PP_MonitorDeviceChangeCallback callback, + void* user_data) { + return enumeration_helper_.MonitorDeviceChange(callback, user_data); +} + +int32_t VideoCaptureResource::Open( + const std::string& device_id, + const PP_VideoCaptureDeviceInfo_Dev& requested_info, + uint32_t buffer_count, + scoped_refptr<TrackedCallback> callback) { + if (open_state_ != BEFORE_OPEN) + return PP_ERROR_FAILED; + + if (TrackedCallback::IsPending(open_callback_)) + return PP_ERROR_INPROGRESS; + + open_callback_ = callback; + + Call<PpapiPluginMsg_VideoCapture_OpenReply>( + RENDERER, + PpapiHostMsg_VideoCapture_Open(device_id, requested_info, buffer_count), + base::Bind(&VideoCaptureResource::OnPluginMsgOpenReply, this)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t VideoCaptureResource::StartCapture() { + if (open_state_ != OPENED) + return PP_ERROR_FAILED; + + Post(RENDERER, PpapiHostMsg_VideoCapture_StartCapture()); + return PP_OK; +} + +int32_t VideoCaptureResource::ReuseBuffer(uint32_t buffer) { + if (buffer >= buffer_in_use_.size() || !buffer_in_use_[buffer]) + return PP_ERROR_BADARGUMENT; + Post(RENDERER, PpapiHostMsg_VideoCapture_ReuseBuffer(buffer)); + return PP_OK; +} + +int32_t VideoCaptureResource::StopCapture() { + if (open_state_ != OPENED) + return PP_ERROR_FAILED; + + Post(RENDERER, PpapiHostMsg_VideoCapture_StopCapture()); + return PP_OK; +} + +void VideoCaptureResource::Close() { + if (open_state_ == CLOSED) + return; + + Post(RENDERER, PpapiHostMsg_VideoCapture_Close()); + + open_state_ = CLOSED; + + if (TrackedCallback::IsPending(open_callback_)) + open_callback_->PostAbort(); +} + +int32_t VideoCaptureResource::EnumerateDevicesSync( + const PP_ArrayOutput& devices) { + return enumeration_helper_.EnumerateDevicesSync(devices); +} + +void VideoCaptureResource::LastPluginRefWasDeleted() { + enumeration_helper_.LastPluginRefWasDeleted(); +} + +void VideoCaptureResource::OnPluginMsgOnDeviceInfo( + const ResourceMessageReplyParams& params, + const struct PP_VideoCaptureDeviceInfo_Dev& info, + const std::vector<HostResource>& buffers, + uint32_t buffer_size) { + if (!ppp_video_capture_impl_) + return; + + std::vector<base::SharedMemoryHandle> handles; + params.TakeAllSharedMemoryHandles(&handles); + CHECK(handles.size() == buffers.size()); + + PluginResourceTracker* tracker = + PluginGlobals::Get()->plugin_resource_tracker(); + scoped_ptr<PP_Resource[]> resources(new PP_Resource[buffers.size()]); + for (size_t i = 0; i < buffers.size(); ++i) { + // We assume that the browser created a new set of resources. + DCHECK(!tracker->PluginResourceForHostResource(buffers[i])); + resources[i] = ppapi::proxy::PPB_Buffer_Proxy::AddProxyResource( + buffers[i], handles[i], buffer_size); + } + + buffer_in_use_ = std::vector<bool>(buffers.size()); + + CallWhileUnlocked(ppp_video_capture_impl_->OnDeviceInfo, + pp_instance(), + pp_resource(), + &info, + static_cast<uint32_t>(buffers.size()), + const_cast<const PP_Resource*>(resources.get())); + + for (size_t i = 0; i < buffers.size(); ++i) + tracker->ReleaseResource(resources[i]); +} + +void VideoCaptureResource::OnPluginMsgOnStatus( + const ResourceMessageReplyParams& params, + uint32_t status) { + switch (status) { + case PP_VIDEO_CAPTURE_STATUS_STARTING: + case PP_VIDEO_CAPTURE_STATUS_STOPPING: + // Those states are not sent by the browser. + NOTREACHED(); + break; + } + if (ppp_video_capture_impl_) { + CallWhileUnlocked(ppp_video_capture_impl_->OnStatus, + pp_instance(), + pp_resource(), + status); + } +} + +void VideoCaptureResource::OnPluginMsgOnError( + const ResourceMessageReplyParams& params, + uint32_t error_code) { + open_state_ = CLOSED; + if (ppp_video_capture_impl_) { + CallWhileUnlocked(ppp_video_capture_impl_->OnError, + pp_instance(), + pp_resource(), + error_code); + } +} + +void VideoCaptureResource::OnPluginMsgOnBufferReady( + const ResourceMessageReplyParams& params, + uint32_t buffer) { + SetBufferInUse(buffer); + if (ppp_video_capture_impl_) { + CallWhileUnlocked(ppp_video_capture_impl_->OnBufferReady, + pp_instance(), + pp_resource(), + buffer); + } +} + +void VideoCaptureResource::OnPluginMsgOpenReply( + const ResourceMessageReplyParams& params) { + if (open_state_ == BEFORE_OPEN && params.result() == PP_OK) + open_state_ = OPENED; + + // The callback may have been aborted by Close(). + if (TrackedCallback::IsPending(open_callback_)) + open_callback_->Run(params.result()); +} + +void VideoCaptureResource::SetBufferInUse(uint32_t buffer_index) { + CHECK(buffer_index < buffer_in_use_.size()); + buffer_in_use_[buffer_index] = true; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/video_capture_resource.h b/chromium/ppapi/proxy/video_capture_resource.h new file mode 100644 index 00000000000..e533ef095fb --- /dev/null +++ b/chromium/ppapi/proxy/video_capture_resource.h @@ -0,0 +1,99 @@ +// 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_PROXY_VIDEO_CAPTURE_RESOURCE_H_ +#define PPAPI_PROXY_VIDEO_CAPTURE_RESOURCE_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/dev/ppp_video_capture_dev.h" +#include "ppapi/proxy/device_enumeration_resource_helper.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/thunk/ppb_video_capture_api.h" + +namespace ppapi { +namespace proxy { + +class VideoCaptureResource + : public PluginResource, + public ::ppapi::thunk::PPB_VideoCapture_API { + public: + VideoCaptureResource(Connection connection, + PP_Instance instance, + PluginDispatcher* dispatcher); + virtual ~VideoCaptureResource(); + + // PluginResource override. + virtual thunk::PPB_VideoCapture_API* AsPPB_VideoCapture_API() OVERRIDE { + return this; + } + + // PPB_VideoCapture_API implementation. + virtual int32_t EnumerateDevices0_2( + PP_Resource* devices, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t EnumerateDevices( + const PP_ArrayOutput& output, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t MonitorDeviceChange( + PP_MonitorDeviceChangeCallback callback, + void* user_data) OVERRIDE; + virtual int32_t Open(const std::string& device_id, + const PP_VideoCaptureDeviceInfo_Dev& requested_info, + uint32_t buffer_count, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t StartCapture() OVERRIDE; + virtual int32_t ReuseBuffer(uint32_t buffer) OVERRIDE; + virtual int32_t StopCapture() OVERRIDE; + virtual void Close() OVERRIDE; + virtual int32_t EnumerateDevicesSync(const PP_ArrayOutput& devices) OVERRIDE; + + protected: + // Resource override. + virtual void LastPluginRefWasDeleted() OVERRIDE; + + private: + enum OpenState { + BEFORE_OPEN, + OPENED, + CLOSED + }; + + // PluginResource overrides. + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + void OnPluginMsgOnDeviceInfo(const ResourceMessageReplyParams& params, + const struct PP_VideoCaptureDeviceInfo_Dev& info, + const std::vector<HostResource>& buffers, + uint32_t buffer_size); + void OnPluginMsgOnStatus(const ResourceMessageReplyParams& params, + uint32_t status); + void OnPluginMsgOnError(const ResourceMessageReplyParams& params, + uint32_t error); + void OnPluginMsgOnBufferReady(const ResourceMessageReplyParams& params, + uint32_t buffer); + + void OnPluginMsgOpenReply(const ResourceMessageReplyParams& params); + + void SetBufferInUse(uint32_t buffer_index); + + // Points to the C interface of client implementation. + const PPP_VideoCapture_Dev* ppp_video_capture_impl_; + + // Indicates that the i-th buffer is currently in use. + std::vector<bool> buffer_in_use_; + + // Holds a reference of the callback so that Close() can cancel it. + scoped_refptr<TrackedCallback> open_callback_; + OpenState open_state_; + + DeviceEnumerationResourceHelper enumeration_helper_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_VIDEO_CAPTURE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/video_destination_resource.cc b/chromium/ppapi/proxy/video_destination_resource.cc new file mode 100644 index 00000000000..5175705160e --- /dev/null +++ b/chromium/ppapi/proxy/video_destination_resource.cc @@ -0,0 +1,102 @@ +// 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 "ppapi/proxy/video_destination_resource.h" + +#include "base/bind.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/pp_video_frame_private.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_VideoDestination_Private_API; + +namespace ppapi { +namespace proxy { + +VideoDestinationResource::VideoDestinationResource( + Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + is_open_(false) { + SendCreate(RENDERER, PpapiHostMsg_VideoDestination_Create()); +} + +VideoDestinationResource::~VideoDestinationResource() { +} + +PPB_VideoDestination_Private_API* + VideoDestinationResource::AsPPB_VideoDestination_Private_API() { + return this; +} + +int32_t VideoDestinationResource::Open( + const PP_Var& stream_url, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(open_callback_)) + return PP_ERROR_INPROGRESS; + + open_callback_ = callback; + + scoped_refptr<StringVar> stream_url_var = StringVar::FromPPVar(stream_url); + const uint32_t kMaxStreamIdSizeInBytes = 16384; + if (!stream_url_var.get() || + stream_url_var->value().size() > kMaxStreamIdSizeInBytes) + return PP_ERROR_BADARGUMENT; + Call<PpapiPluginMsg_VideoDestination_OpenReply>(RENDERER, + PpapiHostMsg_VideoDestination_Open(stream_url_var->value()), + base::Bind(&VideoDestinationResource::OnPluginMsgOpenComplete, this)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t VideoDestinationResource::PutFrame( + const PP_VideoFrame_Private& frame) { + if (!is_open_) + return PP_ERROR_FAILED; + + thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_image( + frame.image_data, true); + if (enter_image.failed()) + return PP_ERROR_BADRESOURCE; + + // Check that the PP_Instance matches. + Resource* image_object = + PpapiGlobals::Get()->GetResourceTracker()->GetResource(frame.image_data); + if (!image_object || pp_instance() != image_object->pp_instance()) { + Log(PP_LOGLEVEL_ERROR, + "VideoDestinationPrivateResource.PutFrame: Bad image resource."); + return PP_ERROR_BADRESOURCE; + } + + Post(RENDERER, + PpapiHostMsg_VideoDestination_PutFrame(image_object->host_resource(), + frame.timestamp)); + return PP_OK; +} + +void VideoDestinationResource::Close() { + Post(RENDERER, PpapiHostMsg_VideoDestination_Close()); + + if (TrackedCallback::IsPending(open_callback_)) + open_callback_->PostAbort(); +} + +void VideoDestinationResource::OnPluginMsgOpenComplete( + const ResourceMessageReplyParams& params) { + if (TrackedCallback::IsPending(open_callback_)) { + int32_t result = params.result(); + if (result == PP_OK) + is_open_ = true; + open_callback_->Run(result); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/video_destination_resource.h b/chromium/ppapi/proxy/video_destination_resource.h new file mode 100644 index 00000000000..91c0d1da0c2 --- /dev/null +++ b/chromium/ppapi/proxy/video_destination_resource.h @@ -0,0 +1,56 @@ +// 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 PPAPI_PROXY_VIDEO_DESTINATION_RESOURCE_H_ +#define PPAPI_PROXY_VIDEO_DESTINATION_RESOURCE_H_ + +#include <string> + +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_video_destination_private_api.h" + +struct PP_VideoFrame_Private; + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +class PPAPI_PROXY_EXPORT VideoDestinationResource + : public PluginResource, + public thunk::PPB_VideoDestination_Private_API { + public: + VideoDestinationResource(Connection connection, + PP_Instance instance); + virtual ~VideoDestinationResource(); + + // Resource overrides. + virtual thunk::PPB_VideoDestination_Private_API* + AsPPB_VideoDestination_Private_API() OVERRIDE; + + // PPB_VideoDestination_Private_API implementation. + virtual int32_t Open( + const PP_Var& stream_url, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t PutFrame(const PP_VideoFrame_Private& frame) OVERRIDE; + virtual void Close() OVERRIDE; + + private: + void OnPluginMsgOpenComplete( + const ResourceMessageReplyParams& params); + + scoped_refptr<TrackedCallback> open_callback_; + bool is_open_; + + DISALLOW_COPY_AND_ASSIGN(VideoDestinationResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_VIDEO_DESTINATION_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/video_source_resource.cc b/chromium/ppapi/proxy/video_source_resource.cc new file mode 100644 index 00000000000..c2949031883 --- /dev/null +++ b/chromium/ppapi/proxy/video_source_resource.cc @@ -0,0 +1,120 @@ +// 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 "ppapi/proxy/video_source_resource.h" + +#include "base/bind.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/pp_video_frame_private.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_VideoSource_Private_API; + +namespace ppapi { +namespace proxy { + +VideoSourceResource::VideoSourceResource( + Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + is_open_(false) { + SendCreate(RENDERER, PpapiHostMsg_VideoSource_Create()); +} + +VideoSourceResource::~VideoSourceResource() { +} + +PPB_VideoSource_Private_API* + VideoSourceResource::AsPPB_VideoSource_Private_API() { + return this; +} + +int32_t VideoSourceResource::Open( + const PP_Var& stream_url, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(open_callback_)) + return PP_ERROR_INPROGRESS; + + open_callback_ = callback; + + scoped_refptr<StringVar> stream_url_var = StringVar::FromPPVar(stream_url); + const uint32_t kMaxStreamIdSizeInBytes = 16384; + if (!stream_url_var.get() || + stream_url_var->value().size() > kMaxStreamIdSizeInBytes) + return PP_ERROR_BADARGUMENT; + Call<PpapiPluginMsg_VideoSource_OpenReply>(RENDERER, + PpapiHostMsg_VideoSource_Open(stream_url_var->value()), + base::Bind(&VideoSourceResource::OnPluginMsgOpenComplete, this)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t VideoSourceResource::GetFrame( + PP_VideoFrame_Private* frame, + scoped_refptr<TrackedCallback> callback) { + if (!is_open_) + return PP_ERROR_FAILED; + + if (TrackedCallback::IsPending(get_frame_callback_)) + return PP_ERROR_INPROGRESS; + + get_frame_callback_ = callback; + Call<PpapiPluginMsg_VideoSource_GetFrameReply>(RENDERER, + PpapiHostMsg_VideoSource_GetFrame(), + base::Bind(&VideoSourceResource::OnPluginMsgGetFrameComplete, this, + frame)); + return PP_OK_COMPLETIONPENDING; +} + +void VideoSourceResource::Close() { + Post(RENDERER, PpapiHostMsg_VideoSource_Close()); + + if (TrackedCallback::IsPending(open_callback_)) + open_callback_->PostAbort(); + if (TrackedCallback::IsPending(get_frame_callback_)) + get_frame_callback_->PostAbort(); +} + +void VideoSourceResource::OnPluginMsgOpenComplete( + const ResourceMessageReplyParams& reply_params) { + if (TrackedCallback::IsPending(open_callback_)) { + int32_t result = reply_params.result(); + if (result == PP_OK) + is_open_ = true; + open_callback_->Run(result); + } +} + +void VideoSourceResource::OnPluginMsgGetFrameComplete( + PP_VideoFrame_Private* frame, + const ResourceMessageReplyParams& reply_params, + const HostResource& image_data, + const PP_ImageDataDesc& image_desc, + PP_TimeTicks timestamp) { + // The callback may have been aborted by Close(). + if (TrackedCallback::IsPending(get_frame_callback_)) { + int32_t result = reply_params.result(); + if (result == PP_OK && + PPB_ImageData_Shared::IsImageDataDescValid(image_desc)) { + frame->timestamp = timestamp; + + base::SharedMemoryHandle handle; + if (!reply_params.TakeSharedMemoryHandleAtIndex(0, &handle)) + frame->image_data = 0; + frame->image_data = + (new SimpleImageData( + image_data, image_desc, handle))->GetReference(); + } + get_frame_callback_->Run(result); + } +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/video_source_resource.h b/chromium/ppapi/proxy/video_source_resource.h new file mode 100644 index 00000000000..cdd4638a215 --- /dev/null +++ b/chromium/ppapi/proxy/video_source_resource.h @@ -0,0 +1,67 @@ +// 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 PPAPI_PROXY_VIDEO_SOURCE_RESOURCE_H_ +#define PPAPI_PROXY_VIDEO_SOURCE_RESOURCE_H_ + +#include <string> + +#include "ppapi/c/pp_time.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/connection.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_video_source_private_api.h" + +struct PP_ImageDataDesc; +struct PP_VideoFrame_Private; + +namespace ppapi { + +class TrackedCallback; + +namespace proxy { + +class PPAPI_PROXY_EXPORT VideoSourceResource + : public PluginResource, + public thunk::PPB_VideoSource_Private_API { + public: + VideoSourceResource(Connection connection, + PP_Instance instance); + virtual ~VideoSourceResource(); + + // Resource overrides. + virtual thunk::PPB_VideoSource_Private_API* + AsPPB_VideoSource_Private_API() OVERRIDE; + + // PPB_VideoSource_Private_API implementation. + virtual int32_t Open( + const PP_Var& stream_url, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t GetFrame( + PP_VideoFrame_Private* frame, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + + private: + void OnPluginMsgOpenComplete( + const ResourceMessageReplyParams& reply_params); + void OnPluginMsgGetFrameComplete( + PP_VideoFrame_Private* frame, + const ResourceMessageReplyParams& reply_params, + const HostResource& image_data, + const PP_ImageDataDesc& image_desc_data, + PP_TimeTicks timestamp); + + scoped_refptr<TrackedCallback> open_callback_; + scoped_refptr<TrackedCallback> get_frame_callback_; + bool is_open_; + + DISALLOW_COPY_AND_ASSIGN(VideoSourceResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_VIDEO_SOURCE_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/websocket_resource.cc b/chromium/ppapi/proxy/websocket_resource.cc new file mode 100644 index 00000000000..394a2c54f9e --- /dev/null +++ b/chromium/ppapi/proxy/websocket_resource.cc @@ -0,0 +1,494 @@ +// 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 "ppapi/proxy/websocket_resource.h" + +#include <set> +#include <string> +#include <vector> + +#include "base/bind.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.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/WebSocket.h" + +namespace { + +const uint32_t kMaxReasonSizeInBytes = 123; +const size_t kBaseFramingOverhead = 2; +const size_t kMaskingKeyLength = 4; +const size_t kMinimumPayloadSizeWithTwoByteExtendedPayloadLength = 126; +const size_t kMinimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000; + +uint64_t SaturateAdd(uint64_t a, uint64_t b) { + if (kuint64max - a < b) + return kuint64max; + return a + b; +} + +uint64_t GetFrameSize(uint64_t payload_size) { + uint64_t overhead = kBaseFramingOverhead + kMaskingKeyLength; + if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength) + overhead += 8; + else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength) + overhead += 2; + return SaturateAdd(payload_size, overhead); +} + +bool InValidStateToReceive(PP_WebSocketReadyState state) { + return state == PP_WEBSOCKETREADYSTATE_OPEN || + state == PP_WEBSOCKETREADYSTATE_CLOSING; +} + +} // namespace + + +namespace ppapi { +namespace proxy { + +WebSocketResource::WebSocketResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + state_(PP_WEBSOCKETREADYSTATE_INVALID), + error_was_received_(false), + receive_callback_var_(NULL), + empty_string_(new StringVar(std::string())), + close_code_(0), + close_reason_(NULL), + close_was_clean_(PP_FALSE), + extensions_(NULL), + protocol_(NULL), + url_(NULL), + buffered_amount_(0), + buffered_amount_after_close_(0) { +} + +WebSocketResource::~WebSocketResource() { +} + +thunk::PPB_WebSocket_API* WebSocketResource::AsPPB_WebSocket_API() { + return this; +} + +int32_t WebSocketResource::Connect( + const PP_Var& url, + const PP_Var protocols[], + uint32_t protocol_count, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(connect_callback_)) + return PP_ERROR_INPROGRESS; + + // Connect() can be called at most once. + if (state_ != PP_WEBSOCKETREADYSTATE_INVALID) + return PP_ERROR_INPROGRESS; + state_ = PP_WEBSOCKETREADYSTATE_CLOSED; + + // Get the URL. + url_ = StringVar::FromPPVar(url); + if (!url_.get()) + return PP_ERROR_BADARGUMENT; + + // Get the protocols. + std::set<std::string> protocol_set; + std::vector<std::string> protocol_strings; + protocol_strings.reserve(protocol_count); + for (uint32_t i = 0; i < protocol_count; ++i) { + scoped_refptr<StringVar> protocol(StringVar::FromPPVar(protocols[i])); + + // Check invalid and empty entries. + if (!protocol.get() || !protocol->value().length()) + return PP_ERROR_BADARGUMENT; + + // Check duplicated protocol entries. + if (protocol_set.find(protocol->value()) != protocol_set.end()) + return PP_ERROR_BADARGUMENT; + protocol_set.insert(protocol->value()); + + protocol_strings.push_back(protocol->value()); + } + + // Install callback. + connect_callback_ = callback; + + // Create remote host in the renderer, then request to check the URL and + // establish the connection. + state_ = PP_WEBSOCKETREADYSTATE_CONNECTING; + SendCreate(RENDERER, PpapiHostMsg_WebSocket_Create()); + PpapiHostMsg_WebSocket_Connect msg(url_->value(), protocol_strings); + Call<PpapiPluginMsg_WebSocket_ConnectReply>(RENDERER, msg, + base::Bind(&WebSocketResource::OnPluginMsgConnectReply, this)); + + return PP_OK_COMPLETIONPENDING; +} + +int32_t WebSocketResource::Close(uint16_t code, + const PP_Var& reason, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(close_callback_)) + return PP_ERROR_INPROGRESS; + if (state_ == PP_WEBSOCKETREADYSTATE_INVALID) + return PP_ERROR_FAILED; + + // Validate |code| and |reason|. + scoped_refptr<StringVar> reason_string_var; + std::string reason_string; + WebKit::WebSocket::CloseEventCode event_code = + static_cast<WebKit::WebSocket::CloseEventCode>(code); + if (code == PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED) { + // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED and CloseEventCodeNotSpecified are + // assigned to different values. A conversion is needed if + // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED is specified. + event_code = WebKit::WebSocket::CloseEventCodeNotSpecified; + } else { + if (!(code == PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE || + (PP_WEBSOCKETSTATUSCODE_USER_REGISTERED_MIN <= code && + code <= PP_WEBSOCKETSTATUSCODE_USER_PRIVATE_MAX))) + // RFC 6455 limits applications to use reserved connection close code in + // section 7.4.2.. The WebSocket API (http://www.w3.org/TR/websockets/) + // defines this out of range error as InvalidAccessError in JavaScript. + return PP_ERROR_NOACCESS; + + // |reason| must be ignored if it is PP_VARTYPE_UNDEFINED or |code| is + // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED. + if (reason.type != PP_VARTYPE_UNDEFINED) { + // Validate |reason|. + reason_string_var = StringVar::FromPPVar(reason); + if (!reason_string_var.get() || + reason_string_var->value().size() > kMaxReasonSizeInBytes) + return PP_ERROR_BADARGUMENT; + reason_string = reason_string_var->value(); + } + } + + // Check state. + if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING) + return PP_ERROR_INPROGRESS; + if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED) + return PP_OK; + + // Install |callback|. + close_callback_ = callback; + + // Abort ongoing connect. + if (TrackedCallback::IsPending(connect_callback_)) { + state_ = PP_WEBSOCKETREADYSTATE_CLOSING; + // Need to do a "Post" to avoid reentering the plugin. + connect_callback_->PostAbort(); + connect_callback_ = NULL; + Post(RENDERER, PpapiHostMsg_WebSocket_Fail( + "WebSocket was closed before the connection was established.")); + return PP_OK_COMPLETIONPENDING; + } + + // Abort ongoing receive. + if (TrackedCallback::IsPending(receive_callback_)) { + receive_callback_var_ = NULL; + // Need to do a "Post" to avoid reentering the plugin. + receive_callback_->PostAbort(); + receive_callback_ = NULL; + } + + // Close connection. + state_ = PP_WEBSOCKETREADYSTATE_CLOSING; + PpapiHostMsg_WebSocket_Close msg(static_cast<int32_t>(event_code), + reason_string); + Call<PpapiPluginMsg_WebSocket_CloseReply>(RENDERER, msg, + base::Bind(&WebSocketResource::OnPluginMsgCloseReply, this)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t WebSocketResource::ReceiveMessage( + PP_Var* message, + scoped_refptr<TrackedCallback> callback) { + if (TrackedCallback::IsPending(receive_callback_)) + return PP_ERROR_INPROGRESS; + + // Check state. + if (state_ == PP_WEBSOCKETREADYSTATE_INVALID || + state_ == PP_WEBSOCKETREADYSTATE_CONNECTING) + return PP_ERROR_BADARGUMENT; + + // Just return received message if any received message is queued. + if (!received_messages_.empty()) { + receive_callback_var_ = message; + return DoReceive(); + } + + // Check state again. In CLOSED state, no more messages will be received. + if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED) + return PP_ERROR_BADARGUMENT; + + // Returns PP_ERROR_FAILED after an error is received and received messages + // is exhausted. + if (error_was_received_) + return PP_ERROR_FAILED; + + // Or retain |message| as buffer to store and install |callback|. + receive_callback_var_ = message; + receive_callback_ = callback; + + return PP_OK_COMPLETIONPENDING; +} + +int32_t WebSocketResource::SendMessage(const PP_Var& message) { + // Check state. + if (state_ == PP_WEBSOCKETREADYSTATE_INVALID || + state_ == PP_WEBSOCKETREADYSTATE_CONNECTING) + return PP_ERROR_BADARGUMENT; + + if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING || + state_ == PP_WEBSOCKETREADYSTATE_CLOSED) { + // Handle buffered_amount_after_close_. + uint64_t payload_size = 0; + if (message.type == PP_VARTYPE_STRING) { + scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message); + if (message_string.get()) + payload_size += message_string->value().length(); + } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) { + scoped_refptr<ArrayBufferVar> message_array_buffer = + ArrayBufferVar::FromPPVar(message); + if (message_array_buffer.get()) + payload_size += message_array_buffer->ByteLength(); + } else { + // TODO(toyoshim): Support Blob. + return PP_ERROR_NOTSUPPORTED; + } + + buffered_amount_after_close_ = + SaturateAdd(buffered_amount_after_close_, GetFrameSize(payload_size)); + + return PP_ERROR_FAILED; + } + + // Send the message. + if (message.type == PP_VARTYPE_STRING) { + // Convert message to std::string, then send it. + scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message); + if (!message_string.get()) + return PP_ERROR_BADARGUMENT; + Post(RENDERER, PpapiHostMsg_WebSocket_SendText(message_string->value())); + } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) { + // Convert message to std::vector<uint8_t>, then send it. + scoped_refptr<ArrayBufferVar> message_arraybuffer = + ArrayBufferVar::FromPPVar(message); + if (!message_arraybuffer.get()) + return PP_ERROR_BADARGUMENT; + uint8_t* message_data = static_cast<uint8_t*>(message_arraybuffer->Map()); + uint32 message_length = message_arraybuffer->ByteLength(); + std::vector<uint8_t> message_vector(message_data, + message_data + message_length); + Post(RENDERER, PpapiHostMsg_WebSocket_SendBinary(message_vector)); + } else { + // TODO(toyoshim): Support Blob. + return PP_ERROR_NOTSUPPORTED; + } + return PP_OK; +} + +uint64_t WebSocketResource::GetBufferedAmount() { + return SaturateAdd(buffered_amount_, buffered_amount_after_close_); +} + +uint16_t WebSocketResource::GetCloseCode() { + return close_code_; +} + +PP_Var WebSocketResource::GetCloseReason() { + if (!close_reason_.get()) + return empty_string_->GetPPVar(); + return close_reason_->GetPPVar(); +} + +PP_Bool WebSocketResource::GetCloseWasClean() { + return close_was_clean_; +} + +PP_Var WebSocketResource::GetExtensions() { + return StringVar::StringToPPVar(std::string()); +} + +PP_Var WebSocketResource::GetProtocol() { + if (!protocol_.get()) + return empty_string_->GetPPVar(); + return protocol_->GetPPVar(); +} + +PP_WebSocketReadyState WebSocketResource::GetReadyState() { + return state_; +} + +PP_Var WebSocketResource::GetURL() { + if (!url_.get()) + return empty_string_->GetPPVar(); + return url_->GetPPVar(); +} + +void WebSocketResource::OnReplyReceived( + const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + if (params.sequence()) { + PluginResource::OnReplyReceived(params, msg); + return; + } + + IPC_BEGIN_MESSAGE_MAP(WebSocketResource, msg) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_WebSocket_ReceiveTextReply, + OnPluginMsgReceiveTextReply) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_WebSocket_ReceiveBinaryReply, + OnPluginMsgReceiveBinaryReply) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_0( + PpapiPluginMsg_WebSocket_ErrorReply, + OnPluginMsgErrorReply) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_WebSocket_BufferedAmountReply, + OnPluginMsgBufferedAmountReply) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_WebSocket_StateReply, + OnPluginMsgStateReply) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_WebSocket_ClosedReply, + OnPluginMsgClosedReply) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(NOTREACHED()) + IPC_END_MESSAGE_MAP() +} + +void WebSocketResource::OnPluginMsgConnectReply( + const ResourceMessageReplyParams& params, + const std::string& url, + const std::string& protocol) { + if (!TrackedCallback::IsPending(connect_callback_) || + TrackedCallback::IsScheduledToRun(connect_callback_)) { + return; + } + + int32_t result = params.result(); + if (result == PP_OK) { + state_ = PP_WEBSOCKETREADYSTATE_OPEN; + protocol_ = new StringVar(protocol); + url_ = new StringVar(url); + } + connect_callback_->Run(params.result()); +} + +void WebSocketResource::OnPluginMsgCloseReply( + const ResourceMessageReplyParams& params, + unsigned long buffered_amount, + bool was_clean, + unsigned short code, + const std::string& reason) { + // Set close related properties. + state_ = PP_WEBSOCKETREADYSTATE_CLOSED; + buffered_amount_ = buffered_amount; + close_was_clean_ = PP_FromBool(was_clean); + close_code_ = code; + close_reason_ = new StringVar(reason); + + if (TrackedCallback::IsPending(receive_callback_)) { + receive_callback_var_ = NULL; + if (!TrackedCallback::IsScheduledToRun(receive_callback_)) + receive_callback_->PostRun(PP_ERROR_FAILED); + receive_callback_ = NULL; + } + + if (TrackedCallback::IsPending(close_callback_)) { + if (!TrackedCallback::IsScheduledToRun(close_callback_)) + close_callback_->PostRun(params.result()); + close_callback_ = NULL; + } +} + +void WebSocketResource::OnPluginMsgReceiveTextReply( + const ResourceMessageReplyParams& params, + const std::string& message) { + // Dispose packets after receiving an error or in invalid state. + if (error_was_received_ || !InValidStateToReceive(state_)) + return; + + // Append received data to queue. + received_messages_.push(scoped_refptr<Var>(new StringVar(message))); + + if (!TrackedCallback::IsPending(receive_callback_) || + TrackedCallback::IsScheduledToRun(receive_callback_)) { + return; + } + + receive_callback_->Run(DoReceive()); +} + +void WebSocketResource::OnPluginMsgReceiveBinaryReply( + const ResourceMessageReplyParams& params, + const std::vector<uint8_t>& message) { + // Dispose packets after receiving an error or in invalid state. + if (error_was_received_ || !InValidStateToReceive(state_)) + return; + + // Append received data to queue. + scoped_refptr<Var> message_var( + PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferVar( + message.size(), + &message.front())); + received_messages_.push(message_var); + + if (!TrackedCallback::IsPending(receive_callback_) || + TrackedCallback::IsScheduledToRun(receive_callback_)) { + return; + } + + receive_callback_->Run(DoReceive()); +} + +void WebSocketResource::OnPluginMsgErrorReply( + const ResourceMessageReplyParams& params) { + error_was_received_ = true; + + if (!TrackedCallback::IsPending(receive_callback_) || + TrackedCallback::IsScheduledToRun(receive_callback_)) { + return; + } + + // No more text or binary messages will be received. If there is ongoing + // ReceiveMessage(), we must invoke the callback with error code here. + receive_callback_var_ = NULL; + receive_callback_->Run(PP_ERROR_FAILED); +} + +void WebSocketResource::OnPluginMsgBufferedAmountReply( + const ResourceMessageReplyParams& params, + unsigned long buffered_amount) { + buffered_amount_ = buffered_amount; +} + +void WebSocketResource::OnPluginMsgStateReply( + const ResourceMessageReplyParams& params, + int32_t state) { + state_ = static_cast<PP_WebSocketReadyState>(state); +} + +void WebSocketResource::OnPluginMsgClosedReply( + const ResourceMessageReplyParams& params, + unsigned long buffered_amount, + bool was_clean, + unsigned short code, + const std::string& reason) { + OnPluginMsgCloseReply(params, buffered_amount, was_clean, code, reason); +} + +int32_t WebSocketResource::DoReceive() { + if (!receive_callback_var_) + return PP_OK; + + *receive_callback_var_ = received_messages_.front()->GetPPVar(); + received_messages_.pop(); + receive_callback_var_ = NULL; + return PP_OK; +} + +} // namespace proxy +} // namespace ppapi diff --git a/chromium/ppapi/proxy/websocket_resource.h b/chromium/ppapi/proxy/websocket_resource.h new file mode 100644 index 00000000000..49353e4b0b5 --- /dev/null +++ b/chromium/ppapi/proxy/websocket_resource.h @@ -0,0 +1,157 @@ +// 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_PROXY_WEBSOCKET_RESOURCE_H_ +#define PPAPI_PROXY_WEBSOCKET_RESOURCE_H_ + +#include <queue> + +#include "ppapi/c/ppb_websocket.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_websocket_api.h" + +namespace ppapi { + +class StringVar; +class Var; + +namespace proxy { + +// This class contains protocol checks which doesn't affect security when it +// run with untrusted code. +class PPAPI_PROXY_EXPORT WebSocketResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_WebSocket_API) { + public: + WebSocketResource(Connection connection, PP_Instance instance); + virtual ~WebSocketResource(); + + // PluginResource implementation. + virtual thunk::PPB_WebSocket_API* AsPPB_WebSocket_API() OVERRIDE; + + // PPB_WebSocket_API implementation. + virtual int32_t Connect(const PP_Var& url, + const PP_Var protocols[], + uint32_t protocol_count, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Close(uint16_t code, + const PP_Var& reason, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t ReceiveMessage( + PP_Var* message, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t SendMessage(const PP_Var& message) OVERRIDE; + virtual uint64_t GetBufferedAmount() OVERRIDE; + virtual uint16_t GetCloseCode() OVERRIDE; + virtual PP_Var GetCloseReason() OVERRIDE; + virtual PP_Bool GetCloseWasClean() OVERRIDE; + virtual PP_Var GetExtensions() OVERRIDE; + virtual PP_Var GetProtocol() OVERRIDE; + virtual PP_WebSocketReadyState GetReadyState() OVERRIDE; + virtual PP_Var GetURL() OVERRIDE; + + private: + // PluginResource override. + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + // IPC message handlers. + void OnPluginMsgConnectReply(const ResourceMessageReplyParams& params, + const std::string& url, + const std::string& protocol); + void OnPluginMsgCloseReply(const ResourceMessageReplyParams& params, + unsigned long buffered_amount, + bool was_clean, + unsigned short code, + const std::string& reason); + void OnPluginMsgReceiveTextReply(const ResourceMessageReplyParams& params, + const std::string& message); + void OnPluginMsgReceiveBinaryReply(const ResourceMessageReplyParams& params, + const std::vector<uint8_t>& message); + void OnPluginMsgErrorReply(const ResourceMessageReplyParams& params); + void OnPluginMsgBufferedAmountReply(const ResourceMessageReplyParams& params, + unsigned long buffered_amount); + void OnPluginMsgStateReply(const ResourceMessageReplyParams& params, + int32_t state); + void OnPluginMsgClosedReply(const ResourceMessageReplyParams& params, + unsigned long buffered_amount, + bool was_clean, + unsigned short code, + const std::string& reason); + + // Picks up a received message and moves it to user receiving buffer. This + // function is used in both ReceiveMessage for fast returning path, and + // OnPluginMsgReceiveTextReply and OnPluginMsgReceiveBinaryReply for delayed + // callback invocations. + int32_t DoReceive(); + + // Holds user callbacks to invoke later. + scoped_refptr<TrackedCallback> connect_callback_; + scoped_refptr<TrackedCallback> close_callback_; + scoped_refptr<TrackedCallback> receive_callback_; + + // Represents readyState described in the WebSocket API specification. It can + // be read via GetReadyState(). + PP_WebSocketReadyState state_; + + // Becomes true if any error is detected. Incoming data will be disposed + // if this variable is true, then ReceiveMessage() returns PP_ERROR_FAILED + // after returning all received data. + bool error_was_received_; + + // Keeps a pointer to PP_Var which is provided via ReceiveMessage(). + // Received data will be copied to this PP_Var on ready. + PP_Var* receive_callback_var_; + + // Keeps received data until ReceiveMessage() requests. + std::queue<scoped_refptr<Var> > received_messages_; + + // Keeps empty string for functions to return empty string. + scoped_refptr<StringVar> empty_string_; + + // Keeps the status code field of closing handshake. It can be read via + // GetCloseCode(). + uint16_t close_code_; + + // Keeps the reason field of closing handshake. It can be read via + // GetCloseReason(). + scoped_refptr<StringVar> close_reason_; + + // Becomes true when closing handshake is performed successfully. It can be + // read via GetCloseWasClean(). + PP_Bool close_was_clean_; + + // Represents extensions described in the WebSocket API specification. It can + // be read via GetExtensions(). + scoped_refptr<StringVar> extensions_; + + // Represents protocol described in the WebSocket API specification. It can be + // read via GetProtocol(). + scoped_refptr<StringVar> protocol_; + + // Represents url described in the WebSocket API specification. It can be + // read via GetURL(). + scoped_refptr<StringVar> url_; + + // Keeps the number of bytes of application data that have been queued using + // SendMessage(). WebKit side implementation calculates the actual amount. + // This is a cached value which is notified through a WebKit callback. + // This value is used to calculate bufferedAmount in the WebSocket API + // specification. The calculated value can be read via GetBufferedAmount(). + uint64_t buffered_amount_; + + // Keeps the number of bytes of application data that have been ignored + // because the connection was already closed. + // This value is used to calculate bufferedAmount in the WebSocket API + // specification. The calculated value can be read via GetBufferedAmount(). + uint64_t buffered_amount_after_close_; + + DISALLOW_COPY_AND_ASSIGN(WebSocketResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_WEBSOCKET_RESOURCE_H_ diff --git a/chromium/ppapi/proxy/websocket_resource_unittest.cc b/chromium/ppapi/proxy/websocket_resource_unittest.cc new file mode 100644 index 00000000000..ecd9111c980 --- /dev/null +++ b/chromium/ppapi/proxy/websocket_resource_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 "base/memory/ref_counted.h" +#include "base/message_loop/message_loop.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/ppb_websocket.h" +#include "ppapi/proxy/locking_resource_releaser.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" +#include "ppapi/proxy/websocket_resource.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/ppb_var_shared.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/resource_tracker.h" +#include "ppapi/shared_impl/scoped_pp_resource.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace proxy { + +namespace { + +typedef PluginProxyTest WebSocketResourceTest; + +bool g_callback_called; +int32_t g_callback_result; +const PPB_Var* ppb_var_ = NULL; + +void Callback(void* user_data, int32_t result) { + g_callback_called = true; + g_callback_result = result; +} + +PP_CompletionCallback MakeCallback() { + g_callback_called = false; + g_callback_result = PP_OK; + return PP_MakeCompletionCallback(Callback, NULL); +} + +PP_Var MakeStringVar(const std::string& string) { + if (!ppb_var_) + ppb_var_ = ppapi::PPB_Var_Shared::GetVarInterface1_1(); + return ppb_var_->VarFromUtf8(string.c_str(), string.length()); +} + +} // namespace + + +// Does a test of Connect(). +TEST_F(WebSocketResourceTest, Connect) { + const PPB_WebSocket_1_0* websocket_iface = + thunk::GetPPB_WebSocket_1_0_Thunk(); + + std::string url("ws://ws.google.com"); + std::string protocol0("x-foo"); + std::string protocol1("x-bar"); + PP_Var url_var = MakeStringVar(url); + PP_Var protocols[] = { MakeStringVar(protocol0), MakeStringVar(protocol1) }; + + LockingResourceReleaser res(websocket_iface->Create(pp_instance())); + + int32_t result = websocket_iface->Connect(res.get(), url_var, protocols, 2, + MakeCallback()); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + // Should be sent a "Connect" message. + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_WebSocket_Connect::ID, ¶ms, &msg)); + PpapiHostMsg_WebSocket_Connect::Schema::Param p; + PpapiHostMsg_WebSocket_Connect::Read(&msg, &p); + EXPECT_EQ(url, p.a); + EXPECT_EQ(protocol0, p.b[0]); + EXPECT_EQ(protocol1, p.b[1]); + + // Synthesize a response. + ResourceMessageReplyParams reply_params(params.pp_resource(), + params.sequence()); + reply_params.set_result(PP_OK); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply(reply_params, + PpapiPluginMsg_WebSocket_ConnectReply(url, protocol1)))); + + EXPECT_EQ(PP_OK, g_callback_result); + EXPECT_EQ(true, g_callback_called); +} + +// Does a test for unsolicited replies. +TEST_F(WebSocketResourceTest, UnsolicitedReplies) { + const PPB_WebSocket_1_0* websocket_iface = + thunk::GetPPB_WebSocket_1_0_Thunk(); + + LockingResourceReleaser res(websocket_iface->Create(pp_instance())); + + // Check if BufferedAmountReply is handled. + ResourceMessageReplyParams reply_params(res.get(), 0); + reply_params.set_result(PP_OK); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_WebSocket_BufferedAmountReply(19760227u)))); + + uint64_t amount = websocket_iface->GetBufferedAmount(res.get()); + EXPECT_EQ(19760227u, amount); + + // Check if StateReply is handled. + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply( + reply_params, + PpapiPluginMsg_WebSocket_StateReply( + static_cast<int32_t>(PP_WEBSOCKETREADYSTATE_CLOSING))))); + + PP_WebSocketReadyState state = websocket_iface->GetReadyState(res.get()); + EXPECT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, state); +} + +TEST_F(WebSocketResourceTest, MessageError) { + const PPB_WebSocket_1_0* websocket_iface = + thunk::GetPPB_WebSocket_1_0_Thunk(); + + std::string url("ws://ws.google.com"); + PP_Var url_var = MakeStringVar(url); + + LockingResourceReleaser res(websocket_iface->Create(pp_instance())); + + // Establish the connection virtually. + int32_t result = + websocket_iface->Connect(res.get(), url_var, NULL, 0, MakeCallback()); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); + + ResourceMessageCallParams params; + IPC::Message msg; + ASSERT_TRUE(sink().GetFirstResourceCallMatching( + PpapiHostMsg_WebSocket_Connect::ID, ¶ms, &msg)); + + ResourceMessageReplyParams connect_reply_params(params.pp_resource(), + params.sequence()); + connect_reply_params.set_result(PP_OK); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply(connect_reply_params, + PpapiPluginMsg_WebSocket_ConnectReply(url, std::string())))); + + EXPECT_EQ(PP_OK, g_callback_result); + EXPECT_TRUE(g_callback_called); + + PP_Var message; + result = websocket_iface->ReceiveMessage(res.get(), &message, MakeCallback()); + EXPECT_FALSE(g_callback_called); + + // Synthesize a WebSocket_ErrorReply message. + ResourceMessageReplyParams error_reply_params(res.get(), 0); + error_reply_params.set_result(PP_OK); + ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived( + PpapiPluginMsg_ResourceReply(error_reply_params, + PpapiPluginMsg_WebSocket_ErrorReply()))); + + EXPECT_EQ(PP_ERROR_FAILED, g_callback_result); + EXPECT_TRUE(g_callback_called); +} + +} // namespace proxy +} // namespace ppapi |