summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authordmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-29 18:26:36 +0000
committerdmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-29 18:26:36 +0000
commit912f3d6c2193584bc9376ed17f3dd2b90e78a40e (patch)
tree98729e7a810cc29cdc414ea8e0e75e9967a0ac4c /ppapi
parent0daefc769a7578184c1c57ef2b59970a41d8cf79 (diff)
downloadchromium_src-912f3d6c2193584bc9376ed17f3dd2b90e78a40e.zip
chromium_src-912f3d6c2193584bc9376ed17f3dd2b90e78a40e.tar.gz
chromium_src-912f3d6c2193584bc9376ed17f3dd2b90e78a40e.tar.bz2
Make o.o.p. proxy handle PPP_Instance versions 0.4 and 0.5.
Move & tweak PPP_Instance_Combined to ppapi_shared so the proxy can use it. Use versioned PPP_Instance types only. BUG=82606 TEST=run tests o.o.p. Review URL: http://codereview.chromium.org/7189045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90984 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/ppapi_shared.gypi2
-rw-r--r--ppapi/ppapi_tests.gypi1
-rw-r--r--ppapi/proxy/dispatcher.cc16
-rw-r--r--ppapi/proxy/dispatcher.h2
-rw-r--r--ppapi/proxy/host_dispatcher.cc29
-rw-r--r--ppapi/proxy/host_dispatcher.h10
-rw-r--r--ppapi/proxy/host_dispatcher_unittest.cc4
-rw-r--r--ppapi/proxy/plugin_dispatcher.cc2
-rw-r--r--ppapi/proxy/plugin_dispatcher_unittest.cc5
-rw-r--r--ppapi/proxy/plugin_resource_tracker.h2
-rw-r--r--ppapi/proxy/plugin_var_tracker.h2
-rw-r--r--ppapi/proxy/ppapi_proxy_test.cc294
-rw-r--r--ppapi/proxy/ppapi_proxy_test.h169
-rw-r--r--ppapi/proxy/ppp_instance_proxy.cc64
-rw-r--r--ppapi/proxy/ppp_instance_proxy.h22
-rw-r--r--ppapi/proxy/ppp_instance_proxy_test.cc319
-rw-r--r--ppapi/shared_impl/ppp_instance_combined.cc28
-rw-r--r--ppapi/shared_impl/ppp_instance_combined.h26
18 files changed, 881 insertions, 116 deletions
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index c09157b..11440a1 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -39,6 +39,8 @@
'shared_impl/image_data_impl.h',
'shared_impl/ppapi_preferences.cc',
'shared_impl/ppapi_preferences.h',
+ 'shared_impl/ppp_instance_combined.cc',
+ 'shared_impl/ppp_instance_combined.h',
'shared_impl/resource_object_base.cc',
'shared_impl/resource_object_base.h',
'shared_impl/tracker_base.cc',
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index ca09ebe..2b5f967 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -185,6 +185,7 @@
'proxy/plugin_var_tracker_unittest.cc',
'proxy/ppapi_proxy_test.cc',
'proxy/ppapi_proxy_test.h',
+ 'proxy/ppp_instance_proxy_test.cc',
'proxy/serialized_var_unittest.cc',
],
},
diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc
index 35a7d67..3520752 100644
--- a/ppapi/proxy/dispatcher.cc
+++ b/ppapi/proxy/dispatcher.cc
@@ -103,12 +103,10 @@ struct InterfaceList {
// we're converting to the thunk system, when that is complete, we need to
// have a better way of handling multiple interface implemented by one
// proxy object.
- const InterfaceProxy::Info* id_to_plugin_info_[INTERFACE_ID_COUNT];
const InterfaceProxy::Info* id_to_browser_info_[INTERFACE_ID_COUNT];
};
InterfaceList::InterfaceList() {
- memset(id_to_plugin_info_, 0, sizeof(id_to_plugin_info_));
memset(id_to_browser_info_, 0, sizeof(id_to_browser_info_));
// PPB (browser) interfaces.
@@ -157,18 +155,16 @@ InterfaceList::InterfaceList() {
// PPP (plugin) interfaces.
AddPPP(PPP_Graphics3D_Proxy::GetInfo());
AddPPP(PPP_Instance_Private_Proxy::GetInfo());
- AddPPP(PPP_Instance_Proxy::GetInfo());
+ AddPPP(PPP_Instance_Proxy::GetInfo0_4());
+ AddPPP(PPP_Instance_Proxy::GetInfo0_5());
}
void InterfaceList::AddPPP(const InterfaceProxy::Info* info) {
DCHECK(name_to_plugin_info_.find(info->name) ==
name_to_plugin_info_.end());
DCHECK(info->id >= INTERFACE_ID_NONE && info->id < INTERFACE_ID_COUNT);
- DCHECK(info->id == INTERFACE_ID_NONE || id_to_plugin_info_[info->id] == NULL);
name_to_plugin_info_[info->name] = info;
- if (info->id != INTERFACE_ID_NONE)
- id_to_plugin_info_[info->id] = info;
}
void InterfaceList::AddPPB(const InterfaceProxy::Info* info) {
@@ -245,14 +241,6 @@ const InterfaceProxy::Info* Dispatcher::GetPPPInterfaceInfo(
return found->second;
}
-// static
-const InterfaceProxy::Info* Dispatcher::GetPPPInterfaceInfo(InterfaceID id) {
- if (id <= 0 || id >= INTERFACE_ID_COUNT)
- return NULL;
- const InterfaceList* list = InterfaceList::GetInstance();
- return list->id_to_plugin_info_[id];
-}
-
void Dispatcher::SetSerializationRules(
VarSerializationRules* var_serialization_rules) {
serialization_rules_.reset(var_serialization_rules);
diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h
index 39fa1e0..348c91c 100644
--- a/ppapi/proxy/dispatcher.h
+++ b/ppapi/proxy/dispatcher.h
@@ -93,8 +93,6 @@ class Dispatcher : public ProxyChannel {
InterfaceID id);
static const InterfaceProxy::Info* GetPPPInterfaceInfo(
const std::string& name);
- static const InterfaceProxy::Info* GetPPPInterfaceInfo(
- InterfaceID id);
protected:
Dispatcher(base::ProcessHandle remote_process_handle,
diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc
index c00390b..60c0cf7 100644
--- a/ppapi/proxy/host_dispatcher.cc
+++ b/ppapi/proxy/host_dispatcher.cc
@@ -75,9 +75,8 @@ HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle,
local_get_interface(PPB_VAR_DEPRECATED_INTERFACE));
SetSerializationRules(new HostVarSerializationRules(var_interface, module));
- memset(plugin_interface_support_, 0,
- sizeof(PluginInterfaceSupport) * INTERFACE_ID_COUNT);
-
+ // TODO(brettw): It might be more testable to inject the PPB_Proxy_Private
+ // instead of requesting it from GetLocalInterface.
ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>(
GetLocalInterface(PPB_PROXY_PRIVATE_INTERFACE));
DCHECK(ppb_proxy_) << "The proxy interface should always be supported.";
@@ -208,21 +207,17 @@ const void* HostDispatcher::GetProxiedInterface(const std::string& interface) {
if (!info)
return NULL;
- if (plugin_interface_support_[static_cast<int>(info->id)] !=
- INTERFACE_UNQUERIED) {
- // Already queried the plugin if it supports this interface.
- if (plugin_interface_support_[info->id] == INTERFACE_SUPPORTED)
- return info->interface_ptr;
- return NULL;
+ PluginIFSupportedMap::iterator iter(plugin_if_supported_.find(interface));
+ if (iter == plugin_if_supported_.end()) {
+ // Need to query. Cache the result so we only do this once.
+ bool supported = false;
+ Send(new PpapiMsg_SupportsInterface(interface, &supported));
+ std::pair<PluginIFSupportedMap::iterator, bool> iter_success_pair;
+ iter_success_pair = plugin_if_supported_.insert(
+ PluginIFSupportedMap::value_type(interface, supported));
+ iter = iter_success_pair.first;
}
-
- // Need to re-query. Cache the result so we only do this once.
- bool supported = false;
- Send(new PpapiMsg_SupportsInterface(interface, &supported));
- plugin_interface_support_[static_cast<int>(info->id)] =
- supported ? INTERFACE_SUPPORTED : INTERFACE_UNSUPPORTED;
-
- if (supported)
+ if (iter->second)
return info->interface_ptr;
return NULL;
}
diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h
index 55ba56b..e3d9001 100644
--- a/ppapi/proxy/host_dispatcher.h
+++ b/ppapi/proxy/host_dispatcher.h
@@ -110,12 +110,10 @@ class HostDispatcher : public Dispatcher {
PP_Module pp_module_;
- enum PluginInterfaceSupport {
- INTERFACE_UNQUERIED = 0, // Must be 0 so memset(0) will clear the list.
- INTERFACE_SUPPORTED,
- INTERFACE_UNSUPPORTED
- };
- PluginInterfaceSupport plugin_interface_support_[INTERFACE_ID_COUNT];
+ typedef std::map<std::string, bool> PluginIFSupportedMap;
+ // 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.
+ std::map<std::string, bool> plugin_if_supported_;
// All target proxies currently created. These are ones that receive
// messages. They are created on demand when we receive messages.
diff --git a/ppapi/proxy/host_dispatcher_unittest.cc b/ppapi/proxy/host_dispatcher_unittest.cc
index ffa53f2..b2caa1a 100644
--- a/ppapi/proxy/host_dispatcher_unittest.cc
+++ b/ppapi/proxy/host_dispatcher_unittest.cc
@@ -21,7 +21,9 @@ class HostDispatcherTest : public HostProxyTest {
}
};
-TEST_F(HostDispatcherTest, PPBCreation) {
+// TODO(brettw): Make and register an implementation of TrackerBase for this
+// test. Possibly fix other failures too, once that's resolved.
+TEST_F(HostDispatcherTest, FAILS_PPBCreation) {
RegisterTestInterface(PPB_AUDIO_INTERFACE,
reinterpret_cast<void*>(0xdeadbeef));
diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc
index a701947..ac0a072 100644
--- a/ppapi/proxy/plugin_dispatcher.cc
+++ b/ppapi/proxy/plugin_dispatcher.cc
@@ -131,7 +131,7 @@ bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) {
return handled;
}
- if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) {
+ if (msg.routing_id() <= 0 || msg.routing_id() >= INTERFACE_ID_COUNT) {
// Host is sending us garbage. Since it's supposed to be trusted, this
// isn't supposed to happen. Crash here in all builds in case the renderer
// is compromised.
diff --git a/ppapi/proxy/plugin_dispatcher_unittest.cc b/ppapi/proxy/plugin_dispatcher_unittest.cc
index 096783e..f3e8da5 100644
--- a/ppapi/proxy/plugin_dispatcher_unittest.cc
+++ b/ppapi/proxy/plugin_dispatcher_unittest.cc
@@ -44,6 +44,8 @@ PPB_Audio dummy_audio_interface = {
&StopPlayback
};
+PPP_Instance dummy_ppp_instance_interface = {};
+
} // namespace
class PluginDispatcherTest : public PluginProxyTest {
@@ -57,8 +59,7 @@ class PluginDispatcherTest : public PluginProxyTest {
TEST_F(PluginDispatcherTest, SupportsInterface) {
RegisterTestInterface(PPB_AUDIO_INTERFACE, &dummy_audio_interface);
- RegisterTestInterface(PPP_INSTANCE_INTERFACE,
- reinterpret_cast<void*>(0xdeadbeef));
+ RegisterTestInterface(PPP_INSTANCE_INTERFACE, &dummy_ppp_instance_interface);
// Sending a request for a random interface should fail.
EXPECT_FALSE(SupportsInterface("Random interface"));
diff --git a/ppapi/proxy/plugin_resource_tracker.h b/ppapi/proxy/plugin_resource_tracker.h
index 0a18dff..83b7840 100644
--- a/ppapi/proxy/plugin_resource_tracker.h
+++ b/ppapi/proxy/plugin_resource_tracker.h
@@ -66,7 +66,7 @@ class PluginResourceTracker : public ::ppapi::TrackerBase {
private:
friend struct DefaultSingletonTraits<PluginResourceTracker>;
friend class PluginResourceTrackerTest;
- friend class PluginProxyTest;
+ friend class PluginProxyTestHarness;
PluginResourceTracker();
virtual ~PluginResourceTracker();
diff --git a/ppapi/proxy/plugin_var_tracker.h b/ppapi/proxy/plugin_var_tracker.h
index 1587736..748ec2d 100644
--- a/ppapi/proxy/plugin_var_tracker.h
+++ b/ppapi/proxy/plugin_var_tracker.h
@@ -88,7 +88,7 @@ class PluginVarTracker {
private:
friend struct DefaultSingletonTraits<PluginVarTracker>;
- friend class PluginProxyTest;
+ friend class PluginProxyTestHarness;
class RefCountedString : public base::RefCounted<RefCountedString> {
public:
diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc
index 1782302..733f04c 100644
--- a/ppapi/proxy/ppapi_proxy_test.cc
+++ b/ppapi/proxy/ppapi_proxy_test.cc
@@ -4,48 +4,113 @@
#include "ppapi/proxy/ppapi_proxy_test.h"
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.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/shared_impl/ppapi_preferences.cc"
namespace pp {
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.
+}
-ProxyTestBase* current_test = NULL;
+int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) {
+ NOTREACHED();
+ return 0;
+}
+
+void AddRefModule(PP_Module module) {}
+void ReleaseModule(PP_Module module) {}
+
+PPB_Proxy_Private ppb_proxy_private = { PluginCrashed,
+ GetInstanceForResource,
+ SetReserveInstanceIDCallback,
+ GetURLLoaderBufferedBytes,
+ AddRefModule,
+ ReleaseModule };
+
+// 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) {
- if (!current_test) {
- NOTREACHED();
- return NULL;
+ ObserverList<ProxyTestHarnessBase>::Iterator it =
+ get_interface_handlers_;
+ while (ProxyTestHarnessBase* observer = it.GetNext()) {
+ const void* interface = observer->GetInterface(name);
+ if (interface)
+ return interface;
}
- return current_test->GetInterface(name);
+ 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();
}
} // namespace
-// ProxyTestBase ---------------------------------------------------------------
+// ProxyTestHarnessBase --------------------------------------------------------
-ProxyTestBase::ProxyTestBase() : pp_module_(0x98765), pp_instance_(0x12345) {
- DCHECK(!current_test);
- current_test = this;
+ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765),
+ pp_instance_(0x12345) {
+ get_interface_handlers_.AddObserver(this);
}
-ProxyTestBase::~ProxyTestBase() {
- DCHECK(current_test == this);
- current_test = NULL;
+ProxyTestHarnessBase::~ProxyTestHarnessBase() {
+ get_interface_handlers_.RemoveObserver(this);
}
-const void* ProxyTestBase::GetInterface(const char* name) {
+const void* ProxyTestHarnessBase::GetInterface(const char* name) {
return registered_interfaces_[name];
}
-void ProxyTestBase::RegisterTestInterface(const char* name,
- const void* interface) {
+void ProxyTestHarnessBase::RegisterTestInterface(const char* name,
+ const void* interface) {
registered_interfaces_[name] = interface;
}
-bool ProxyTestBase::SupportsInterface(const char* name) {
+bool ProxyTestHarnessBase::SupportsInterface(const char* name) {
sink().ClearMessages();
// IPC doesn't actually write to this when we send a message manually
@@ -68,19 +133,19 @@ bool ProxyTestBase::SupportsInterface(const char* name) {
return reply_data.a;
}
-// PluginProxyTest -------------------------------------------------------------
+// PluginProxyTestHarness ------------------------------------------------------
-PluginProxyTest::PluginProxyTest() {
+PluginProxyTestHarness::PluginProxyTestHarness() {
}
-PluginProxyTest::~PluginProxyTest() {
+PluginProxyTestHarness::~PluginProxyTestHarness() {
}
-Dispatcher* PluginProxyTest::GetDispatcher() {
+Dispatcher* PluginProxyTestHarness::GetDispatcher() {
return plugin_dispatcher_.get();
}
-void PluginProxyTest::SetUp() {
+void PluginProxyTestHarness::SetUpHarness() {
// These must be first since the dispatcher set-up uses them.
PluginResourceTracker::SetInstanceForTest(&resource_tracker_);
PluginVarTracker::SetInstanceForTest(&var_tracker_);
@@ -92,7 +157,26 @@ void PluginProxyTest::SetUp() {
plugin_dispatcher_->DidCreateInstance(pp_instance());
}
-void PluginProxyTest::TearDown() {
+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.
+ PluginResourceTracker::SetInstanceForTest(&resource_tracker_);
+ PluginVarTracker::SetInstanceForTest(&var_tracker_);
+ plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event);
+
+ plugin_dispatcher_.reset(new PluginDispatcher(
+ base::Process::Current().handle(),
+ &MockGetInterface));
+ plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_,
+ channel_handle,
+ is_client);
+ plugin_dispatcher_->DidCreateInstance(pp_instance());
+}
+
+void PluginProxyTestHarness::TearDownHarness() {
plugin_dispatcher_->DidDestroyInstance(pp_instance());
plugin_dispatcher_.reset();
@@ -100,19 +184,68 @@ void PluginProxyTest::TearDown() {
PluginResourceTracker::SetInstanceForTest(NULL);
}
-// HostProxyTest ---------------------------------------------------------------
+base::MessageLoopProxy*
+PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() {
+ return ipc_message_loop_;
+}
-HostProxyTest::HostProxyTest() {
+base::WaitableEvent*
+PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() {
+ return shutdown_event_;
}
-HostProxyTest::~HostProxyTest() {
+std::set<PP_Instance>*
+PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() {
+ return &instance_id_set_;
+}
+
+ppapi::WebKitForwarding*
+PluginProxyTestHarness::PluginDelegateMock::GetWebKitForwarding() {
+ NOTREACHED();
+ return NULL;
+}
+
+void PluginProxyTestHarness::PluginDelegateMock::PostToWebKitThread(
+ const tracked_objects::Location& from_here, const base::Closure& task) {
+ NOTREACHED();
+}
+
+bool PluginProxyTestHarness::PluginDelegateMock::SendToBrowser(
+ IPC::Message* msg) {
+ NOTREACHED();
+ return false;
+}
+
+
+// PluginProxyTest -------------------------------------------------------------
+
+PluginProxyTest::PluginProxyTest() {
+}
+
+PluginProxyTest::~PluginProxyTest() {
+}
+
+void PluginProxyTest::SetUp() {
+ SetUpHarness();
+}
+
+void PluginProxyTest::TearDown() {
+ TearDownHarness();
+}
+
+// HostProxyTestHarness --------------------------------------------------------
+
+HostProxyTestHarness::HostProxyTestHarness() {
+}
+
+HostProxyTestHarness::~HostProxyTestHarness() {
}
-Dispatcher* HostProxyTest::GetDispatcher() {
+Dispatcher* HostProxyTestHarness::GetDispatcher() {
return host_dispatcher_.get();
}
-void HostProxyTest::SetUp() {
+void HostProxyTestHarness::SetUpHarness() {
host_dispatcher_.reset(new HostDispatcher(
base::Process::Current().handle(),
pp_module(),
@@ -121,10 +254,115 @@ void HostProxyTest::SetUp() {
HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
}
-void HostProxyTest::TearDown() {
+void HostProxyTestHarness::SetUpHarnessWithChannel(
+ const IPC::ChannelHandle& channel_handle,
+ base::MessageLoopProxy* ipc_message_loop,
+ base::WaitableEvent* shutdown_event,
+ bool is_client) {
+ delegate_mock_.Init(ipc_message_loop, shutdown_event);
+ host_dispatcher_.reset(new HostDispatcher(
+ base::Process::Current().handle(),
+ pp_module(),
+ &MockGetInterface));
+ ppapi::Preferences preferences;
+ host_dispatcher_->InitHostWithChannel(&delegate_mock_, channel_handle,
+ is_client, preferences);
+ HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
+}
+
+void HostProxyTestHarness::TearDownHarness() {
HostDispatcher::RemoveForInstance(pp_instance());
host_dispatcher_.reset();
}
+base::MessageLoopProxy*
+HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() {
+ return ipc_message_loop_;
+}
+
+base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() {
+ return shutdown_event_;
+}
+
+
+// HostProxyTest ---------------------------------------------------------------
+
+HostProxyTest::HostProxyTest() {
+}
+
+HostProxyTest::~HostProxyTest() {
+}
+
+void HostProxyTest::SetUp() {
+ SetUpHarness();
+}
+
+void HostProxyTest::TearDown() {
+ TearDownHarness();
+}
+
+// TwoWayTest ---------------------------------------------------------------
+
+TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode)
+ : test_mode_(test_mode),
+ 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 = MessageLoop::TYPE_IO;
+ io_thread_.StartWithOptions(options);
+ plugin_thread_.Start();
+
+ IPC::ChannelHandle handle;
+ handle.name = "TwoWayTestChannel";
+
+ base::WaitableEvent remote_harness_set_up(true, false);
+ plugin_thread_.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(&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(),
+ &shutdown_event_,
+ true); // is_client
+}
+
+void TwoWayTest::TearDown() {
+ base::WaitableEvent remote_harness_torn_down(true, false);
+ plugin_thread_.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(&TearDownRemoteHarness,
+ remote_harness_,
+ &remote_harness_torn_down));
+ remote_harness_torn_down.Wait();
+
+ local_harness_->TearDownHarness();
+
+ io_thread_.Stop();
+}
+
+
} // namespace proxy
} // namespace pp
diff --git a/ppapi/proxy/ppapi_proxy_test.h b/ppapi/proxy/ppapi_proxy_test.h
index 2c1ae1f..5067c96 100644
--- a/ppapi/proxy/ppapi_proxy_test.h
+++ b/ppapi/proxy/ppapi_proxy_test.h
@@ -5,7 +5,10 @@
#include <map>
#include <string>
+#include "base/message_loop.h"
#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
#include "ipc/ipc_test_sink.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/proxy/host_dispatcher.h"
@@ -17,12 +20,12 @@
namespace pp {
namespace proxy {
-// Base class for plugin and host tests. Tests will not use this directly.
-// Instead, use the Plugin or HostProxyTest.
-class ProxyTestBase : public testing::Test {
+// Base class for plugin and host test harnesses. Tests will not use this
+// directly. Instead, use the PluginProxyTest, HostProxyTest, or TwoWayTest.
+class ProxyTestHarnessBase {
public:
- ProxyTestBase();
- virtual ~ProxyTestBase();
+ ProxyTestHarnessBase();
+ virtual ~ProxyTestHarnessBase();
PP_Module pp_module() const { return pp_module_; }
PP_Instance pp_instance() const { return pp_instance_; }
@@ -31,6 +34,17 @@ class ProxyTestBase : public testing::Test {
// 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();
@@ -58,44 +72,165 @@ class ProxyTestBase : public testing::Test {
};
// Test harness for the plugin side of the proxy.
-class PluginProxyTest : public ProxyTestBase {
+class PluginProxyTestHarness : public ProxyTestHarnessBase {
public:
- PluginProxyTest();
- virtual ~PluginProxyTest();
+ PluginProxyTestHarness();
+ virtual ~PluginProxyTestHarness();
PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); }
PluginResourceTracker& resource_tracker() { return resource_tracker_; }
PluginVarTracker& var_tracker() { return var_tracker_; }
- // ProxyTestBase implementation.
+ // ProxyTestHarnessBase implementation.
virtual Dispatcher* GetDispatcher();
-
- // testing::Test implementation.
- virtual void SetUp();
- virtual void TearDown();
+ 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:
+ 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;
+ }
+
+ // ProxyChannel::Delegate implementation.
+ virtual base::MessageLoopProxy* GetIPCMessageLoop();
+ virtual base::WaitableEvent* GetShutdownEvent();
+
+ // PluginDispatcher::PluginDelegate implementation.
+ virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet();
+ virtual ppapi::WebKitForwarding* GetWebKitForwarding();
+ virtual void PostToWebKitThread(const tracked_objects::Location& from_here,
+ const base::Closure& task);
+ virtual bool SendToBrowser(IPC::Message* msg);
+
+ private:
+ base::MessageLoopProxy* ipc_message_loop_; // Weak
+ base::WaitableEvent* shutdown_event_; // Weak
+ std::set<PP_Instance> instance_id_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginDelegateMock);
+ };
private:
PluginResourceTracker resource_tracker_;
PluginVarTracker var_tracker_;
scoped_ptr<PluginDispatcher> plugin_dispatcher_;
+ PluginDelegateMock plugin_delegate_mock_;
};
-class HostProxyTest : public ProxyTestBase {
+class PluginProxyTest : public PluginProxyTestHarness, public testing::Test {
public:
- HostProxyTest();
- virtual ~HostProxyTest();
+ PluginProxyTest();
+ virtual ~PluginProxyTest();
+
+ // testing::Test implementation.
+ virtual void SetUp();
+ virtual void TearDown();
+};
+
+class HostProxyTestHarness : public ProxyTestHarnessBase {
+ public:
+ HostProxyTestHarness();
+ virtual ~HostProxyTestHarness();
HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); }
// ProxyTestBase implementation.
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();
+
+ private:
+ base::MessageLoopProxy* ipc_message_loop_; // Weak
+ base::WaitableEvent* shutdown_event_; // Weak
+
+ DISALLOW_COPY_AND_ASSIGN(DelegateMock);
+ };
+
+ private:
+ scoped_ptr<HostDispatcher> host_dispatcher_;
+ DelegateMock delegate_mock_;
+};
+
+class HostProxyTest : public HostProxyTestHarness, public testing::Test {
+ public:
+ HostProxyTest();
+ virtual ~HostProxyTest();
+
+ // testing::Test implementation.
+ virtual void SetUp();
+ virtual void TearDown();
+};
+
+// 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();
private:
- scoped_ptr<HostDispatcher> host_dispatcher_;
+ 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.
+ 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_;
};
} // namespace proxy
diff --git a/ppapi/proxy/ppp_instance_proxy.cc b/ppapi/proxy/ppp_instance_proxy.cc
index 1ccc673..b09055d 100644
--- a/ppapi/proxy/ppp_instance_proxy.cc
+++ b/ppapi/proxy/ppp_instance_proxy.cc
@@ -120,7 +120,7 @@ PP_Var GetInstanceObject(PP_Instance instance) {
return result.Return(dispatcher);
}
-static const PPP_Instance instance_interface = {
+static const PPP_Instance_0_4 instance_interface_0_4 = {
&DidCreate,
&DidDestroy,
&DidChangeView,
@@ -130,29 +130,48 @@ static const PPP_Instance instance_interface = {
&GetInstanceObject
};
+static const PPP_Instance_0_5 instance_interface_0_5 = {
+ &DidCreate,
+ &DidDestroy,
+ &DidChangeView,
+ &DidChangeFocus,
+ &HandleInputEvent,
+ &HandleDocumentLoad
+};
+
+template <class PPP_Instance_Type>
InterfaceProxy* CreateInstanceProxy(Dispatcher* dispatcher,
const void* target_interface) {
- return new PPP_Instance_Proxy(dispatcher, target_interface);
+ return new PPP_Instance_Proxy(
+ dispatcher,
+ static_cast<const PPP_Instance_Type*>(target_interface));
}
} // namespace
-PPP_Instance_Proxy::PPP_Instance_Proxy(Dispatcher* dispatcher,
- const void* target_interface)
- : InterfaceProxy(dispatcher, target_interface) {
+PPP_Instance_Proxy::~PPP_Instance_Proxy() {
}
-PPP_Instance_Proxy::~PPP_Instance_Proxy() {
+// static
+const InterfaceProxy::Info* PPP_Instance_Proxy::GetInfo0_4() {
+ static const Info info = {
+ &instance_interface_0_4,
+ PPP_INSTANCE_INTERFACE_0_4,
+ INTERFACE_ID_PPP_INSTANCE,
+ false,
+ &CreateInstanceProxy<PPP_Instance_0_4>
+ };
+ return &info;
}
// static
-const InterfaceProxy::Info* PPP_Instance_Proxy::GetInfo() {
+const InterfaceProxy::Info* PPP_Instance_Proxy::GetInfo0_5() {
static const Info info = {
- &instance_interface,
- PPP_INSTANCE_INTERFACE,
+ &instance_interface_0_5,
+ PPP_INSTANCE_INTERFACE_0_5,
INTERFACE_ID_PPP_INSTANCE,
false,
- &CreateInstanceProxy,
+ &CreateInstanceProxy<PPP_Instance_0_5>,
};
return &info;
}
@@ -206,14 +225,14 @@ void PPP_Instance_Proxy::OnMsgDidCreate(
argv_array[i] = argv[i].c_str();
}
- DCHECK(ppp_instance_target());
- *result = ppp_instance_target()->DidCreate(instance,
- static_cast<uint32_t>(argn.size()),
- &argn_array[0], &argv_array[0]);
+ 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::OnMsgDidDestroy(PP_Instance instance) {
- ppp_instance_target()->DidDestroy(instance);
+ combined_interface_->DidDestroy(instance);
static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance);
}
@@ -229,18 +248,18 @@ void PPP_Instance_Proxy::OnMsgDidChangeView(PP_Instance instance,
return;
data->position = position;
data->fullscreen = fullscreen;
- ppp_instance_target()->DidChangeView(instance, &position, &clip);
+ combined_interface_->DidChangeView(instance, &position, &clip);
}
void PPP_Instance_Proxy::OnMsgDidChangeFocus(PP_Instance instance,
PP_Bool has_focus) {
- ppp_instance_target()->DidChangeFocus(instance, has_focus);
+ combined_interface_->DidChangeFocus(instance, has_focus);
}
void PPP_Instance_Proxy::OnMsgHandleInputEvent(PP_Instance instance,
const PP_InputEvent& event,
PP_Bool* result) {
- *result = ppp_instance_target()->HandleInputEvent(instance, &event);
+ *result = combined_interface_->HandleInputEvent(instance, &event);
}
void PPP_Instance_Proxy::OnMsgHandleDocumentLoad(PP_Instance instance,
@@ -248,8 +267,7 @@ void PPP_Instance_Proxy::OnMsgHandleDocumentLoad(PP_Instance instance,
PP_Bool* result) {
PP_Resource plugin_loader =
PPB_URLLoader_Proxy::TrackPluginResource(url_loader);
- *result = ppp_instance_target()->HandleDocumentLoad(
- instance, plugin_loader);
+ *result = combined_interface_->HandleDocumentLoad(instance, plugin_loader);
// This balances the one reference that TrackPluginResource() initialized it
// with. The plugin will normally take an additional reference which will keep
@@ -263,8 +281,12 @@ void PPP_Instance_Proxy::OnMsgHandleDocumentLoad(PP_Instance instance,
void PPP_Instance_Proxy::OnMsgGetInstanceObject(
PP_Instance instance,
SerializedVarReturnValue result) {
+ // GetInstanceObject_0_4 can be null if we're talking to version 0.5 or later,
+ // however the host side of the proxy should never call this function on an
+ // 0.5 or later version.
+ DCHECK(combined_interface_->GetInstanceObject_0_4);
result.Return(dispatcher(),
- ppp_instance_target()->GetInstanceObject(instance));
+ combined_interface_->GetInstanceObject_0_4(instance));
}
} // namespace proxy
diff --git a/ppapi/proxy/ppp_instance_proxy.h b/ppapi/proxy/ppp_instance_proxy.h
index 7c208ca..e4ef2ba 100644
--- a/ppapi/proxy/ppp_instance_proxy.h
+++ b/ppapi/proxy/ppp_instance_proxy.h
@@ -8,15 +8,16 @@
#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/host_resource.h"
#include "ppapi/proxy/interface_proxy.h"
+#include "ppapi/shared_impl/ppp_instance_combined.h"
struct PP_InputEvent;
struct PP_Rect;
-struct PPP_Instance;
namespace pp {
namespace proxy {
@@ -25,13 +26,23 @@ class SerializedVarReturnValue;
class PPP_Instance_Proxy : public InterfaceProxy {
public:
- PPP_Instance_Proxy(Dispatcher* dispatcher, const void* target_interface);
+ template <class PPP_Instance_Type>
+ PPP_Instance_Proxy(Dispatcher* dispatcher,
+ const PPP_Instance_Type* target_interface)
+ : InterfaceProxy(dispatcher, static_cast<const void*>(target_interface)),
+ combined_interface_(
+ new ::ppapi::PPP_Instance_Combined(*target_interface)) {
+ }
virtual ~PPP_Instance_Proxy();
- static const Info* GetInfo();
+ // Return the info for the 0.4 version of the interface.
+ static const Info* GetInfo0_4();
+
+ // Return the info for the 0.5 (latest, canonical) version of the interface.
+ static const Info* GetInfo0_5();
- const PPP_Instance* ppp_instance_target() const {
- return reinterpret_cast<const PPP_Instance*>(target_interface());
+ ::ppapi::PPP_Instance_Combined* ppp_instance_target() const {
+ return combined_interface_.get();
}
// InterfaceProxy implementation.
@@ -57,6 +68,7 @@ class PPP_Instance_Proxy : public InterfaceProxy {
PP_Bool* result);
void OnMsgGetInstanceObject(PP_Instance instance,
SerializedVarReturnValue result);
+ scoped_ptr< ::ppapi::PPP_Instance_Combined> combined_interface_;
};
} // namespace proxy
diff --git a/ppapi/proxy/ppp_instance_proxy_test.cc b/ppapi/proxy/ppp_instance_proxy_test.cc
new file mode 100644
index 0000000..15cb716
--- /dev/null
+++ b/ppapi/proxy/ppp_instance_proxy_test.cc
@@ -0,0 +1,319 @@
+// 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/synchronization/waitable_event.h"
+#include "ipc/ipc_message_utils.h"
+#include "ppapi/c/dev/ppb_fullscreen_dev.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/ppapi_proxy_test.h"
+
+namespace pp {
+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_InputEvent received_event;
+PP_Bool HandleInputEvent(PP_Instance instance, const PP_InputEvent* event) {
+ received_instance = instance;
+ memcpy(&received_event, event, sizeof(*event));;
+ return bool_to_return;
+}
+
+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;
+}
+
+PP_Var var_to_return;
+PP_Var GetInstanceObject(PP_Instance instance) {
+ received_instance = instance;
+ return var_to_return;
+}
+
+// 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;
+ memset(&received_event, 0, sizeof(received_event));
+}
+
+PPP_Instance_0_4 ppp_instance_0_4 = {
+ &DidCreate,
+ &DidDestroy,
+ &DidChangeView,
+ &DidChangeFocus,
+ &HandleInputEvent,
+ &HandleDocumentLoad,
+ &GetInstanceObject
+};
+
+PPP_Instance_0_5 ppp_instance_0_5 = {
+ &DidCreate,
+ &DidDestroy,
+ &DidChangeView,
+ &DidChangeFocus,
+ &HandleInputEvent,
+ &HandleDocumentLoad
+};
+
+// PPP_Instance_Proxy::DidChangeView relies on PPB_FullscreenDev being
+// available with a valid implementation of IsFullScreen, so we mock it.
+PP_Bool IsFullscreen(PP_Instance instance) {
+ return PP_FALSE;
+}
+PPB_Fullscreen_Dev ppb_fullscreen_dev = { &IsFullscreen };
+
+} // namespace
+
+class PPP_Instance_ProxyTest : public TwoWayTest {
+ public:
+ PPP_Instance_ProxyTest()
+ : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) {
+ }
+};
+
+TEST_F(PPP_Instance_ProxyTest, PPPInstance0_4) {
+ plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_0_4, &ppp_instance_0_4);
+ host().RegisterTestInterface(PPB_FULLSCREEN_DEV_INTERFACE,
+ &ppb_fullscreen_dev);
+
+ // Try requesting the 0.5 version, like the browser does. This should come
+ // back NULL, since we're not registering 0.5. But this ensures that the
+ // behavior through the proxy code reflects more closely what happens for a
+ // real plug-in.
+ const void* interface =
+ host().host_dispatcher()->GetProxiedInterface(PPP_INSTANCE_INTERFACE_0_5);
+ EXPECT_EQ(NULL, interface);
+
+ // Grab the host-side proxy for the 0.4 interface.
+ const PPP_Instance_0_4* ppp_instance = static_cast<const PPP_Instance_0_4*>(
+ host().host_dispatcher()->GetProxiedInterface(
+ PPP_INSTANCE_INTERFACE_0_4));
+
+ // 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();
+ 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} };
+ ResetReceived();
+ ppp_instance->DidChangeView(expected_instance, &expected_position,
+ &expected_clip);
+ did_change_view_called.Wait();
+ EXPECT_EQ(received_instance, expected_instance);
+ // If I define operator== for PP_Rect, it has to come before gtest's template
+ // definitions in the translation unit, or else it's not found. So instead of
+ // defining operator== before the #include that brings in gtest, I compare the
+ // individual parts.
+ 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);
+
+ PP_InputEvent expected_event = { PP_INPUTEVENT_TYPE_KEYDOWN, // type
+ 0, // padding
+ 1.0, // time_stamp
+ { { 2, 3 } } }; // u (as PP_InputEvent_Key)
+ ResetReceived();
+ EXPECT_EQ(bool_to_return,
+ ppp_instance->HandleInputEvent(expected_instance, &expected_event));
+ EXPECT_EQ(received_instance, expected_instance);
+ ASSERT_EQ(received_event.type, expected_event.type);
+ // Ignore padding; it's okay if it's not serialized.
+ EXPECT_EQ(received_event.time_stamp, expected_event.time_stamp);
+ EXPECT_EQ(received_event.u.key.modifier, expected_event.u.key.modifier);
+ EXPECT_EQ(received_event.u.key.key_code, expected_event.u.key.key_code);
+
+ // 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.
+
+ var_to_return = PP_MakeInt32(100);
+ ResetReceived();
+ PP_Var result(ppp_instance->GetInstanceObject(expected_instance));
+ ASSERT_EQ(var_to_return.type, result.type);
+ EXPECT_EQ(var_to_return.value.as_int, result.value.as_int);
+ EXPECT_EQ(received_instance, expected_instance);
+}
+
+TEST_F(PPP_Instance_ProxyTest, PPPInstance0_5) {
+ plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_0_5, &ppp_instance_0_5);
+ host().RegisterTestInterface(PPB_FULLSCREEN_DEV_INTERFACE,
+ &ppb_fullscreen_dev);
+
+ // Grab the host-side proxy for the 0.5 interface.
+ const PPP_Instance_0_5* ppp_instance = static_cast<const PPP_Instance_0_5*>(
+ host().host_dispatcher()->GetProxiedInterface(
+ PPP_INSTANCE_INTERFACE_0_5));
+
+ // 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();
+ 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} };
+ ResetReceived();
+ ppp_instance->DidChangeView(expected_instance, &expected_position,
+ &expected_clip);
+ 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);
+
+ PP_InputEvent expected_event = { PP_INPUTEVENT_TYPE_KEYDOWN, // type
+ 0, // padding
+ 1.0, // time_stamp
+ { { 2, 3 } } }; // u (as PP_InputEvent_Key)
+ ResetReceived();
+ EXPECT_EQ(bool_to_return,
+ ppp_instance->HandleInputEvent(expected_instance, &expected_event));
+ EXPECT_EQ(received_instance, expected_instance);
+ ASSERT_EQ(received_event.type, expected_event.type);
+ // Ignore padding; it's okay if it's not serialized.
+ EXPECT_EQ(received_event.time_stamp, expected_event.time_stamp);
+ EXPECT_EQ(received_event.u.key.modifier, expected_event.u.key.modifier);
+ EXPECT_EQ(received_event.u.key.key_code, expected_event.u.key.key_code);
+
+ // 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.
+}
+
+} // namespace proxy
+} // namespace pp
+
diff --git a/ppapi/shared_impl/ppp_instance_combined.cc b/ppapi/shared_impl/ppp_instance_combined.cc
new file mode 100644
index 0000000..8da13af
--- /dev/null
+++ b/ppapi/shared_impl/ppp_instance_combined.cc
@@ -0,0 +1,28 @@
+// 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/shared_impl/ppp_instance_combined.h"
+
+namespace ppapi {
+
+PPP_Instance_Combined::PPP_Instance_Combined(
+ const PPP_Instance_0_5& instance_if)
+ : PPP_Instance_0_5(instance_if),
+ GetInstanceObject_0_4(NULL) {
+}
+
+PPP_Instance_Combined::PPP_Instance_Combined(
+ const PPP_Instance_0_4& instance_if)
+ : PPP_Instance_0_5(), // Zero-initialize.
+ GetInstanceObject_0_4(instance_if.GetInstanceObject) {
+ DidCreate = instance_if.DidCreate;
+ DidDestroy = instance_if.DidDestroy;
+ DidChangeView = instance_if.DidChangeView;
+ DidChangeFocus = instance_if.DidChangeFocus;
+ HandleInputEvent = instance_if.HandleInputEvent;
+ HandleDocumentLoad = instance_if.HandleDocumentLoad;
+}
+
+} // namespace ppapi
+
diff --git a/ppapi/shared_impl/ppp_instance_combined.h b/ppapi/shared_impl/ppp_instance_combined.h
new file mode 100644
index 0000000..a186c06
--- /dev/null
+++ b/ppapi/shared_impl/ppp_instance_combined.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_SHARED_IMPL_PPP_INSTANCE_COMBINED_H_
+#define PPAPI_SHARED_IMPL_PPP_INSTANCE_COMBINED_H_
+
+#include "base/basictypes.h"
+#include "ppapi/c/ppp_instance.h"
+
+namespace ppapi {
+
+struct PPP_Instance_Combined : public PPP_Instance_0_5 {
+ public:
+ explicit PPP_Instance_Combined(const PPP_Instance_0_5& instance_if);
+ explicit PPP_Instance_Combined(const PPP_Instance_0_4& instance_if);
+
+ PP_Var (*const GetInstanceObject_0_4)(PP_Instance instance);
+
+ DISALLOW_COPY_AND_ASSIGN(PPP_Instance_Combined);
+};
+
+} // namespace ppapi
+
+#endif // PPAPI_SHARED_IMPL_PPP_INSTANCE_COMBINED_H_
+