summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-24 23:41:07 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-24 23:41:07 +0000
commite50d02901c840370bdccd2fcdf460754649b0874 (patch)
tree92c5995ac1f3a198c6e434b058aef5493aea8127
parent8d19b928672734f9ecd34e3492420fd2d42b8e3a (diff)
downloadchromium_src-e50d02901c840370bdccd2fcdf460754649b0874.zip
chromium_src-e50d02901c840370bdccd2fcdf460754649b0874.tar.gz
chromium_src-e50d02901c840370bdccd2fcdf460754649b0874.tar.bz2
Added DispatchedNPObject.
Automatically invokes member functions on C++ NPObjects for NPAPI methods. See comment in DispatchedNPObject. Utilities for invoking the methods of an NPAPI object using C++ typed arguments and return values. BUG=none TEST=none Review URL: http://codereview.chromium.org/173237 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24177 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--o3d/gpu_plugin/gpu_plugin.gyp19
-rw-r--r--o3d/gpu_plugin/np_utils/base_np_object.cc (renamed from o3d/gpu_plugin/base_np_object.cc)2
-rw-r--r--o3d/gpu_plugin/np_utils/base_np_object.h (renamed from o3d/gpu_plugin/base_np_object.h)15
-rw-r--r--o3d/gpu_plugin/np_utils/base_np_object_mock.cc (renamed from o3d/gpu_plugin/base_np_object_mock.cc)2
-rw-r--r--o3d/gpu_plugin/np_utils/base_np_object_mock.h (renamed from o3d/gpu_plugin/base_np_object_mock.h)25
-rw-r--r--o3d/gpu_plugin/np_utils/base_np_object_unittest.cc (renamed from o3d/gpu_plugin/base_np_object_unittest.cc)4
-rw-r--r--o3d/gpu_plugin/np_utils/dispatched_np_object.cc76
-rw-r--r--o3d/gpu_plugin/np_utils/dispatched_np_object.h71
-rw-r--r--o3d/gpu_plugin/np_utils/dispatched_np_object_unittest.cc378
-rw-r--r--o3d/gpu_plugin/np_utils/np_dispatcher.h183
-rw-r--r--o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h84
-rw-r--r--o3d/gpu_plugin/np_utils/np_object_pointer.h74
-rw-r--r--o3d/gpu_plugin/np_utils/np_object_pointer_unittest.cc125
-rw-r--r--o3d/gpu_plugin/np_utils/np_variant_utils.cc108
-rw-r--r--o3d/gpu_plugin/np_utils/np_variant_utils.h142
-rw-r--r--o3d/gpu_plugin/np_utils/np_variant_utils_unittest.cc299
-rw-r--r--o3d/gpu_plugin/np_utils/npn_test_stub.cc64
-rw-r--r--o3d/gpu_plugin/np_utils/npn_test_stub.h23
18 files changed, 1671 insertions, 23 deletions
diff --git a/o3d/gpu_plugin/gpu_plugin.gyp b/o3d/gpu_plugin/gpu_plugin.gyp
index 6ab3335..43df8d2 100644
--- a/o3d/gpu_plugin/gpu_plugin.gyp
+++ b/o3d/gpu_plugin/gpu_plugin.gyp
@@ -20,9 +20,18 @@
'sources': [
'gpu_plugin.cc',
'gpu_plugin.h',
+ 'np_utils/base_np_object.cc',
+ 'np_utils/base_np_object.h',
+ 'np_utils/dispatched_np_object.cc',
+ 'np_utils/dispatched_np_object.h',
+ 'np_utils/np_dispatcher.h',
+ 'np_utils/np_dispatcher_specializations.h',
+ 'np_utils/np_object_pointer.h',
+ 'np_utils/np_variant_utils.cc',
+ 'np_utils/np_variant_utils.h',
],
},
-
+
# This is a standalone executable until O3D is fully moved over to using
# gyp. At that point these can become part of the regular O3D unit tests.
{
@@ -40,6 +49,14 @@
],
'sources': [
'gpu_plugin_unittest.cc',
+ 'np_utils/base_np_object_mock.cc',
+ 'np_utils/base_np_object_mock.h',
+ 'np_utils/base_np_object_unittest.cc',
+ 'np_utils/dispatched_np_object_unittest.cc',
+ 'np_utils/np_object_pointer_unittest.cc',
+ 'np_utils/np_variant_utils_unittest.cc',
+ 'np_utils/npn_test_stub.h',
+ 'np_utils/npn_test_stub.cc',
],
},
]
diff --git a/o3d/gpu_plugin/base_np_object.cc b/o3d/gpu_plugin/np_utils/base_np_object.cc
index 68b827e..a2d5f6b 100644
--- a/o3d/gpu_plugin/base_np_object.cc
+++ b/o3d/gpu_plugin/np_utils/base_np_object.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "o3d/gpu_plugin/base_np_object.h"
+#include "o3d/gpu_plugin/np_utils/base_np_object.h"
namespace o3d {
namespace gpu_plugin {
diff --git a/o3d/gpu_plugin/base_np_object.h b/o3d/gpu_plugin/np_utils/base_np_object.h
index 898732e..6944d72 100644
--- a/o3d/gpu_plugin/base_np_object.h
+++ b/o3d/gpu_plugin/np_utils/base_np_object.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef O3D_GPU_PLUGIN_NP_OBJECT_BASE_H_
-#define O3D_GPU_PLUGIN_NP_OBJECT_BASE_H_
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_BASE_NP_OBJECT_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_BASE_NP_OBJECT_H_
#include "third_party/npapi/bindings/npapi.h"
#include "third_party/npapi/bindings/npruntime.h"
@@ -19,9 +19,6 @@ class BaseNPObject : public NPObject {
template <typename T>
static const NPClass* GetNPClass();
- explicit BaseNPObject(NPP npp);
- virtual ~BaseNPObject();
-
NPP npp() const {
return npp_;
}
@@ -54,6 +51,12 @@ class BaseNPObject : public NPObject {
virtual bool Construct(const NPVariant* args,
uint32_t num_args,
NPVariant* result);
+
+ protected:
+
+ explicit BaseNPObject(NPP npp);
+ virtual ~BaseNPObject();
+
private:
// This template version of the NPClass allocate function creates a subclass
// of BaseNPObject.
@@ -130,4 +133,4 @@ const NPClass* BaseNPObject::GetNPClass() {
} // namespace gpu_plugin
} // namespace o3d
-#endif // O3D_GPU_PLUGIN_NP_OBJECT_BASE_H_
+#endif // O3D_GPU_PLUGIN_NP_UTILS_BASE_NP_OBJECT_H_
diff --git a/o3d/gpu_plugin/base_np_object_mock.cc b/o3d/gpu_plugin/np_utils/base_np_object_mock.cc
index 3955b4f..5dc8dbf 100644
--- a/o3d/gpu_plugin/base_np_object_mock.cc
+++ b/o3d/gpu_plugin/np_utils/base_np_object_mock.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "o3d/gpu_plugin/base_np_object_mock.h"
+#include "o3d/gpu_plugin/np_utils/base_np_object_mock.h"
namespace o3d {
namespace gpu_plugin {
diff --git a/o3d/gpu_plugin/base_np_object_mock.h b/o3d/gpu_plugin/np_utils/base_np_object_mock.h
index 9047eed..7b4ae1f 100644
--- a/o3d/gpu_plugin/base_np_object_mock.h
+++ b/o3d/gpu_plugin/np_utils/base_np_object_mock.h
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef O3D_GPU_PLUGIN_NP_OBJECT_BASE_MOCK_H_
-#define O3D_GPU_PLUGIN_NP_OBJECT_BASE_MOCK_H_
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_BASE_NP_OBJECT_MOCK_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_BASE_NP_OBJECT_MOCK_H_
-#include "o3d/gpu_plugin/base_np_object.h"
+#include "o3d/gpu_plugin/np_utils/base_np_object.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace o3d {
@@ -13,14 +13,6 @@ namespace gpu_plugin {
class MockBaseNPObject : public BaseNPObject {
public:
- explicit MockBaseNPObject(NPP npp) : BaseNPObject(npp) {
- ++count_;
- }
-
- ~MockBaseNPObject() {
- --count_;
- }
-
static int count() {
return count_;
}
@@ -37,6 +29,15 @@ class MockBaseNPObject : public BaseNPObject {
MOCK_METHOD2(Enumerate, bool(NPIdentifier**, uint32_t*));
MOCK_METHOD3(Construct, bool(const NPVariant*, uint32_t, NPVariant*));
+ protected:
+ explicit MockBaseNPObject(NPP npp) : BaseNPObject(npp) {
+ ++count_;
+ }
+
+ ~MockBaseNPObject() {
+ --count_;
+ }
+
private:
static int count_;
};
@@ -44,4 +45,4 @@ class MockBaseNPObject : public BaseNPObject {
} // namespace gpu_plugin
} // namespace o3d
-#endif // O3D_GPU_PLUGIN_NP_OBJECT_BASE_MOCK_H_
+#endif // O3D_GPU_PLUGIN_NP_UTILS_BASE_NP_OBJECT_MOCK_H_
diff --git a/o3d/gpu_plugin/base_np_object_unittest.cc b/o3d/gpu_plugin/np_utils/base_np_object_unittest.cc
index 9de2d94..26a5c61 100644
--- a/o3d/gpu_plugin/base_np_object_unittest.cc
+++ b/o3d/gpu_plugin/np_utils/base_np_object_unittest.cc
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "o3d/gpu_plugin/base_np_object_mock.h"
-#include "o3d/gpu_plugin/base_np_object.h"
+#include "o3d/gpu_plugin/np_utils/base_np_object_mock.h"
+#include "o3d/gpu_plugin/np_utils/base_np_object.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/o3d/gpu_plugin/np_utils/dispatched_np_object.cc b/o3d/gpu_plugin/np_utils/dispatched_np_object.cc
new file mode 100644
index 0000000..ef04a21
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/dispatched_np_object.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "o3d/gpu_plugin/np_utils/dispatched_np_object.h"
+
+namespace o3d {
+namespace gpu_plugin {
+
+DispatchedNPObject::DispatchedNPObject(NPP npp)
+ : BaseNPObject(npp) {
+}
+
+bool DispatchedNPObject::HasMethod(NPIdentifier name) {
+ for (BaseNPDispatcher* dispatcher = GetDynamicDispatcherChain();
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ if (dispatcher->name() == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DispatchedNPObject::Invoke(NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ for (BaseNPDispatcher* dispatcher = GetDynamicDispatcherChain();
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ if (dispatcher->name() == name && dispatcher->num_args() == num_args) {
+ if (dispatcher->Invoke(this, args, num_args, result))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DispatchedNPObject::Enumerate(NPIdentifier** names, uint32_t* num_names) {
+ // Count the number of names.
+ *num_names = 0;
+ for (BaseNPDispatcher* dispatcher = GetDynamicDispatcherChain();
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ ++(*num_names);
+ }
+
+ // Copy names into the array.
+ *names = static_cast<NPIdentifier*>(
+ NPN_MemAlloc((*num_names) * sizeof(**names)));
+ int i = 0;
+ for (BaseNPDispatcher* dispatcher = GetDynamicDispatcherChain();
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ (*names)[i] = dispatcher->name();
+ ++i;
+ }
+
+ return true;
+}
+
+BaseNPDispatcher* DispatchedNPObject::GetStaticDispatcherChain() {
+ return NULL;
+}
+
+BaseNPDispatcher* DispatchedNPObject::GetDynamicDispatcherChain() {
+ return NULL;
+}
+
+} // namespace gpu_plugin
+} // namespace o3d
diff --git a/o3d/gpu_plugin/np_utils/dispatched_np_object.h b/o3d/gpu_plugin/np_utils/dispatched_np_object.h
new file mode 100644
index 0000000..f2e016d5
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/dispatched_np_object.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_DISPATCHED_NP_OBJECT_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_DISPATCHED_NP_OBJECT_H_
+
+#include "o3d/gpu_plugin/np_utils/base_np_object.h"
+#include "o3d/gpu_plugin/np_utils/np_dispatcher.h"
+
+namespace o3d {
+namespace gpu_plugin {
+
+class BaseNPDispatcher;
+
+// DispatchedNPObject is a base class for NPObjects that automatically make
+// their regular member functions available as NPObject methods. Usage:
+//
+// class MyNPObject : public DispatchedNPObject {
+// public:
+// int MyMethod(bool a, float b);
+// protected:
+// NP_UTILS_BEGIN_DISPATCHER_CHAIN(MyNPObject, DispatchedNPObject)
+// NP_UTILS_DISPATCHER(MyMethod, int(bool, float))
+// NP_UTILS_END_DISPATCHER_CHAIN
+// };
+//
+// Multiple member functions may be listed in the dispatcher chain. Inheritance
+// is supported. The following types are supported as return types and parameter
+// types:
+// * bool
+// * int
+// * float
+// * double
+// * std::string
+// * NPObject*
+//
+class DispatchedNPObject : public BaseNPObject {
+ public:
+ explicit DispatchedNPObject(NPP npp);
+
+ // Returns whether a method with the given name is present in the dispatcher
+ // chain.
+ virtual bool HasMethod(NPIdentifier name);
+
+ // Search through dispatcher chain from most derived to least derived. If
+ // a member function with the same name and number of parameters is found,
+ // attempt to invoke it and return whether the invocation was successful.
+ virtual bool Invoke(NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result);
+
+ // Return the names of all the methods int he dispatcher chain.
+ virtual bool Enumerate(NPIdentifier** names, uint32_t* num_names);
+
+ protected:
+ // Get the dispatcher chain for this class and all its superclasses.
+ static BaseNPDispatcher* GetStaticDispatcherChain();
+
+ // Get the dispatcher chain for this object.
+ virtual BaseNPDispatcher* GetDynamicDispatcherChain();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DispatchedNPObject);
+};
+
+} // namespace gpu_plugin
+} // namespace o3d
+
+#endif // O3D_GPU_PLUGIN_NP_UTILS_DISPATCHED_NP_OBJECT_H_
diff --git a/o3d/gpu_plugin/np_utils/dispatched_np_object_unittest.cc b/o3d/gpu_plugin/np_utils/dispatched_np_object_unittest.cc
new file mode 100644
index 0000000..791491e
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/dispatched_np_object_unittest.cc
@@ -0,0 +1,378 @@
+// Copyright (c) 2006-2008 The Chromium Authors. 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 "o3d/gpu_plugin/np_utils/dispatched_np_object.h"
+#include "o3d/gpu_plugin/np_utils/np_dispatcher.h"
+#include "o3d/gpu_plugin/np_utils/npn_test_stub.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+
+namespace o3d {
+namespace gpu_plugin {
+
+// This mock class has a dispatcher chain with an entry for each mocked
+// function. The tests that follow that invoking an NPAPI method calls the
+// corresponding mocked member function.
+class MockDispatchedNPObject : public DispatchedNPObject {
+ public:
+ MockDispatchedNPObject()
+ : DispatchedNPObject(NULL) {
+ }
+
+ MOCK_METHOD0(VoidReturnNoParams, void());
+ MOCK_METHOD1(VoidReturnBoolParam, void(bool));
+ MOCK_METHOD1(VoidReturnIntParam, void(int));
+ MOCK_METHOD1(VoidReturnFloatParam, void(float));
+ MOCK_METHOD1(VoidReturnDoubleParam, void(double));
+ MOCK_METHOD1(VoidReturnStringParam, void(std::string));
+ MOCK_METHOD1(VoidReturnObjectParam, void(NPObject*));
+ MOCK_METHOD2(VoidReturnTwoParams, void(bool, int));
+ MOCK_METHOD0(Overloaded, void());
+ MOCK_METHOD1(Overloaded, void(bool));
+ MOCK_METHOD1(Overloaded, void(std::string));
+ MOCK_METHOD0(BoolReturn, bool());
+ MOCK_METHOD0(IntReturn, int());
+ MOCK_METHOD0(FloatReturn, float());
+ MOCK_METHOD0(DoubleReturn, double());
+ MOCK_METHOD0(StringReturn, std::string());
+ MOCK_METHOD0(ObjectReturn, NPObject*());
+
+ protected:
+ NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockDispatchedNPObject, DispatchedNPObject)
+ NP_UTILS_DISPATCHER(VoidReturnNoParams, void())
+ NP_UTILS_DISPATCHER(VoidReturnBoolParam, void(bool))
+ NP_UTILS_DISPATCHER(VoidReturnIntParam, void(int))
+ NP_UTILS_DISPATCHER(VoidReturnFloatParam, void(float))
+ NP_UTILS_DISPATCHER(VoidReturnDoubleParam, void(double))
+ NP_UTILS_DISPATCHER(VoidReturnStringParam, void(std::string))
+ NP_UTILS_DISPATCHER(VoidReturnObjectParam, void(NPObject*))
+ NP_UTILS_DISPATCHER(VoidReturnTwoParams, void(bool, int))
+ NP_UTILS_DISPATCHER(Overloaded, void())
+ NP_UTILS_DISPATCHER(Overloaded, void(bool))
+ NP_UTILS_DISPATCHER(Overloaded, void(std::string))
+ NP_UTILS_DISPATCHER(BoolReturn, bool())
+ NP_UTILS_DISPATCHER(IntReturn, int())
+ NP_UTILS_DISPATCHER(FloatReturn, float())
+ NP_UTILS_DISPATCHER(DoubleReturn, double())
+ NP_UTILS_DISPATCHER(StringReturn, std::string())
+ NP_UTILS_DISPATCHER(ObjectReturn, NPObject*());
+ NP_UTILS_END_DISPATCHER_CHAIN
+};
+
+class NPObjectDispatcherTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ object_ = new StrictMock<MockDispatchedNPObject>;
+
+ for (int i = 0; i != arraysize(args_); ++i) {
+ NULL_TO_NPVARIANT(args_[i]);
+ }
+ NULL_TO_NPVARIANT(result_);
+ }
+
+ virtual void TearDown() {
+ delete object_;
+ }
+
+ NPVariant args_[3];
+ NPVariant result_;
+ MockDispatchedNPObject* object_;
+};
+
+TEST_F(NPObjectDispatcherTest, CannotInvokeMissingFunction) {
+ EXPECT_FALSE(object_->Invoke(NPN_GetStringIdentifier("missing"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnNoParams) {
+ EXPECT_CALL(*object_, VoidReturnNoParams());
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnNoParams"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest,
+ CannotInvokeVoidReturnNoParamsWithTooManyParams) {
+ EXPECT_FALSE(object_->Invoke(NPN_GetStringIdentifier("voidReturnNoParams"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnIntParam) {
+ EXPECT_CALL(*object_, VoidReturnIntParam(7));
+
+ INT32_TO_NPVARIANT(7, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnIntParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnBoolParam) {
+ EXPECT_CALL(*object_, VoidReturnBoolParam(true));
+
+ BOOLEAN_TO_NPVARIANT(true, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnBoolParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnFloatParamWithDoubleParam) {
+ EXPECT_CALL(*object_, VoidReturnFloatParam(7.0f));
+
+ DOUBLE_TO_NPVARIANT(7.0, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnFloatParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnFloatParamWithIntParam) {
+ EXPECT_CALL(*object_, VoidReturnFloatParam(7.0f));
+
+ INT32_TO_NPVARIANT(7, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnFloatParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnDoubleParamWithDoubleParam) {
+ EXPECT_CALL(*object_, VoidReturnDoubleParam(7.0));
+
+ DOUBLE_TO_NPVARIANT(7.0, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnDoubleParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnDoubleParamWithIntParam) {
+ EXPECT_CALL(*object_, VoidReturnDoubleParam(7.0f));
+
+ INT32_TO_NPVARIANT(7, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnDoubleParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnStringParam) {
+ EXPECT_CALL(*object_, VoidReturnStringParam(std::string("hello")));
+
+ STRINGZ_TO_NPVARIANT("hello", args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnStringParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnObjectParamWithObject) {
+ EXPECT_CALL(*object_, VoidReturnObjectParam(object_));
+
+ OBJECT_TO_NPVARIANT(object_, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnObjectParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnObjectParamWithNull) {
+ EXPECT_CALL(*object_, VoidReturnObjectParam(NULL));
+
+ NULL_TO_NPVARIANT(args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnObjectParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeVoidReturnTwoParams) {
+ EXPECT_CALL(*object_, VoidReturnTwoParams(false, 7));
+
+ BOOLEAN_TO_NPVARIANT(false, args_[0]);
+ INT32_TO_NPVARIANT(7, args_[1]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("voidReturnTwoParams"),
+ args_,
+ 2,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeOverloadedWithNoParams) {
+ EXPECT_CALL(*object_, Overloaded());
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("overloaded"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeOverloadedWithOneStringParam) {
+ EXPECT_CALL(*object_, Overloaded(std::string("hello")));
+
+ STRINGZ_TO_NPVARIANT("hello", args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("overloaded"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeOverloadedWithOneBoolParam) {
+ EXPECT_CALL(*object_, Overloaded(true));
+
+ BOOLEAN_TO_NPVARIANT(true, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("overloaded"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeBoolReturn) {
+ EXPECT_CALL(*object_, BoolReturn()).WillOnce(Return(true));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("boolReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(result_));
+ EXPECT_TRUE(NPVARIANT_TO_BOOLEAN(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeIntReturn) {
+ EXPECT_CALL(*object_, IntReturn()).WillOnce(Return(7));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("intReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_INT32(result_));
+ EXPECT_EQ(7, NPVARIANT_TO_INT32(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeFloatReturn) {
+ EXPECT_CALL(*object_, FloatReturn()).WillOnce(Return(7.0f));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("floatReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(result_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeDoubleReturn) {
+ EXPECT_CALL(*object_, DoubleReturn()).WillOnce(Return(7.0));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("doubleReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(result_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeStringReturn) {
+ EXPECT_CALL(*object_, StringReturn()).WillOnce(Return(std::string("hello")));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("stringReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_STRING(result_));
+
+ NPString& str = NPVARIANT_TO_STRING(result_);
+ EXPECT_EQ(std::string("hello"),
+ std::string(str.UTF8Characters, str.UTF8Length));
+
+ // Callee is responsible for releasing string.
+ NPN_ReleaseVariantValue(&result_);
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeObjectReturnWithObject) {
+ EXPECT_CALL(*object_, ObjectReturn()).WillOnce(Return(object_));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("objectReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_OBJECT(result_));
+ EXPECT_EQ(object_, NPVARIANT_TO_OBJECT(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, CanInvokeObjectReturnWithNull) {
+ EXPECT_CALL(*object_, ObjectReturn())
+ .WillOnce(Return(static_cast<NPObject*>(NULL)));
+
+ EXPECT_TRUE(object_->Invoke(NPN_GetStringIdentifier("objectReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_NULL(result_));
+}
+
+TEST_F(NPObjectDispatcherTest, HasMethodReturnsTrueIfMatchingMemberVariable) {
+ EXPECT_TRUE(object_->HasMethod(NPN_GetStringIdentifier("objectReturn")));
+}
+
+TEST_F(NPObjectDispatcherTest, HasMethodReturnsTrueIfNoMatchingMemberVariable) {
+ EXPECT_FALSE(object_->HasMethod(NPN_GetStringIdentifier("missing")));
+}
+
+TEST_F(NPObjectDispatcherTest, EnumeratesAllAvailableMethods) {
+ NPIdentifier* names;
+ uint32_t num_names;
+ ASSERT_TRUE(object_->Enumerate(&names, &num_names));
+
+ // Don't compare all of them; this test would need to change every time new
+ // dispatchers were added to the test NPObject class. Just compare the first
+ // registered (last in the dispatcher chain) and that more than one is
+ // returned.
+ EXPECT_GT(num_names, 1u);
+ EXPECT_EQ(NPN_GetStringIdentifier("voidReturnNoParams"),
+ names[num_names - 1]);
+
+ NPN_MemFree(names);
+}
+
+} // namespace gpu_plugin
+} // namespace o3d
diff --git a/o3d/gpu_plugin/np_utils/np_dispatcher.h b/o3d/gpu_plugin/np_utils/np_dispatcher.h
new file mode 100644
index 0000000..7408e64
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_dispatcher.h
@@ -0,0 +1,183 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_NP_DISPATCHER_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_NP_DISPATCHER_H_
+
+#include <string>
+
+#include "o3d/gpu_plugin/np_utils/np_variant_utils.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+// These macros are used to make dispatcher chains. See the comment for the
+// DispatchedNPObject class.
+#define NP_UTILS_NP_UTILS_DISPATCHER_JOIN2(a, b) a ## b
+#define NP_UTILS_DISPATCHER_JOIN(a, b) NP_UTILS_NP_UTILS_DISPATCHER_JOIN2(a, b)
+#define NP_UTILS_DISPATCHER_UNIQUE \
+ NP_UTILS_DISPATCHER_JOIN(dispatcher, __LINE__)
+
+#define NP_UTILS_BEGIN_DISPATCHER_CHAIN(Class, BaseClass) \
+ static BaseNPDispatcher* GetStaticDispatcherChain() { \
+ typedef Class ThisClass; \
+ BaseNPDispatcher* top_dispatcher = BaseClass::GetStaticDispatcherChain(); \
+
+#define NP_UTILS_DISPATCHER(name, Signature) \
+ static NPDispatcher<ThisClass, Signature> \
+ NP_UTILS_DISPATCHER_UNIQUE( \
+ top_dispatcher, \
+ #name, \
+ &ThisClass::name); \
+ top_dispatcher = &NP_UTILS_DISPATCHER_UNIQUE; \
+
+#define NP_UTILS_END_DISPATCHER_CHAIN \
+ return top_dispatcher; \
+ } \
+ virtual BaseNPDispatcher* GetDynamicDispatcherChain() { \
+ static BaseNPDispatcher* top_dispatcher = GetStaticDispatcherChain(); \
+ return top_dispatcher; \
+ } \
+
+namespace o3d {
+namespace gpu_plugin {
+
+class BaseNPDispatcher {
+ public:
+ explicit BaseNPDispatcher(BaseNPDispatcher* next, const NPUTF8* name)
+ : next_(next) {
+ // Convert first character to lower case if it is the ASCII range.
+ // TODO(apatrick): do this correctly for non-ASCII characters.
+ std::string java_script_style_name(name);
+ if (isupper(java_script_style_name[0])) {
+ java_script_style_name[0] = tolower(java_script_style_name[0]);
+ }
+
+ name_ = NPN_GetStringIdentifier(java_script_style_name.c_str());
+ }
+
+ virtual ~BaseNPDispatcher() {
+ }
+
+ BaseNPDispatcher* next() const {
+ return next_;
+ }
+
+ NPIdentifier name() const {
+ return name_;
+ }
+
+ virtual int num_args() const = 0;
+
+ virtual bool Invoke(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) = 0;
+
+ private:
+ BaseNPDispatcher* next_;
+ NPIdentifier name_;
+ DISALLOW_COPY_AND_ASSIGN(BaseNPDispatcher);
+};
+
+// This class should never be instantiated. It is always specialized. Attempting
+// to instantiate it results in a compilation error. This might mean an
+// attempt to instantiate a dispatcher with more parameters than have been
+// specialized for. See the specialization code below.
+template <typename NPObjectType, typename FunctionType>
+struct NPDispatcher {
+};
+
+#define TO_NPVARIANT(index) \
+ T##index n##index; \
+ if (!NPVariantToValue(&n##index, args[index])) \
+ return false; \
+
+#define NUM_PARAMS 0
+#define PARAM_TYPENAMES
+#define PARAM_TYPES
+#define PARAM_NAMES
+#define PARAM_DECLS // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+
+#include "o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 1
+#define PARAM_TYPENAMES , typename T0
+#define PARAM_TYPES T0
+#define PARAM_NAMES n0
+#define PARAM_DECLS T0 n0; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+
+#include "o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 2
+#define PARAM_TYPENAMES , typename T0, typename T1
+#define PARAM_TYPES T0, T1
+#define PARAM_NAMES n0, n1
+#define PARAM_DECLS T0 n0; T1 n1; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+
+#include "o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 3
+#define PARAM_TYPENAMES , typename T0, typename T1, typename T2
+#define PARAM_TYPES T0, T1, T2
+#define PARAM_NAMES n0, n1, n2
+#define PARAM_DECLS T0 n0; T1 n1; T2 n2; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+ TO_NPVARIANT(2); \
+
+#include "o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 4
+#define PARAM_TYPENAMES , typename T0, typename T1, typename T2, typename T3
+#define PARAM_TYPES T0, T1, T2, T3
+#define PARAM_NAMES n0, n1, n2, n3
+#define PARAM_DECLS T0 n0; T1 n1; T2 n2; T3 n3; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+ TO_NPVARIANT(2); \
+ TO_NPVARIANT(3); \
+
+#include "o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 5
+#define PARAM_TYPENAMES , typename T0, typename T1, typename T2, typename T3, \
+ typename T4
+#define PARAM_TYPES T0, T1, T2, T3, T4
+#define PARAM_NAMES n0, n1, n2, n3, n4
+#define PARAM_DECLS T0 n0; T1 n1; T2 n2; T3 n3; T4 n4; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+ TO_NPVARIANT(2); \
+ TO_NPVARIANT(3); \
+ TO_NPVARIANT(4); \
+
+#include "o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#undef TO_NPVARIANT
+
+} // namespace gpu_plugin
+} // namespace o3d
+
+#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_DISPATCHER_H_
diff --git a/o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h b/o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h
new file mode 100644
index 0000000..2aa5d3a
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// There is deliberately no sentry here. This file is included multiple times,
+// once for each dispatcher specialiation arity.
+
+template <typename NPObjectType PARAM_TYPENAMES>
+class NPDispatcher<NPObjectType, void(PARAM_TYPES)>
+ : public BaseNPDispatcher {
+ typedef void (NPObjectType::*FunctionType)(PARAM_TYPES);
+ public:
+ NPDispatcher(BaseNPDispatcher* next,
+ const NPUTF8* name,
+ FunctionType function)
+ : BaseNPDispatcher(next, name),
+ function_(function) {
+ }
+
+ virtual bool Invoke(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ if (num_args != NUM_PARAMS)
+ return false;
+
+ PARAM_TO_NVPARIANT_CONVERSIONS
+
+ (static_cast<NPObjectType*>(object)->*function_)(PARAM_NAMES);
+ return true;
+ }
+
+ virtual int num_args() const {
+ return NUM_PARAMS;
+ }
+
+ private:
+ FunctionType function_;
+};
+
+template <typename NPObjectType, typename R PARAM_TYPENAMES>
+class NPDispatcher<NPObjectType, R(PARAM_TYPES)>
+ : public BaseNPDispatcher {
+ typedef R (NPObjectType::*FunctionType)(PARAM_TYPES);
+ public:
+ NPDispatcher(BaseNPDispatcher* next,
+ const NPUTF8* name,
+ FunctionType function)
+ : BaseNPDispatcher(next, name),
+ function_(function) {
+ }
+
+ virtual bool Invoke(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ if (num_args != NUM_PARAMS)
+ return false;
+
+ PARAM_TO_NVPARIANT_CONVERSIONS
+
+ ValueToNPVariant(
+ (static_cast<NPObjectType*>(object)->*function_)(PARAM_NAMES), result);
+ return true;
+ }
+
+ virtual int num_args() const {
+ return NUM_PARAMS;
+ }
+
+ private:
+ FunctionType function_;
+};
+
+#undef NUM_PARAMS
+#undef PARAM_TYPENAMES
+#undef PARAM_TYPES
+#undef PARAM_NAMES
+#undef PARAM_DECLS
+#undef PARAM_TO_NVPARIANT_CONVERSIONS
diff --git a/o3d/gpu_plugin/np_utils/np_object_pointer.h b/o3d/gpu_plugin/np_utils/np_object_pointer.h
new file mode 100644
index 0000000..6d8d2e0
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_object_pointer.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_NP_OBJECT_POINTER_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_NP_OBJECT_POINTER_H_
+
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace o3d {
+namespace gpu_plugin {
+
+// Smart pointer for NPObjects that automatically handles reference counting.
+template <typename NPObjectType>
+class NPObjectPointer {
+ public:
+ NPObjectPointer() : object_(NULL) {}
+
+ NPObjectPointer(const NPObjectPointer& rhs) : object_(rhs.object_) {
+ if (object_) {
+ NPN_RetainObject(object_);
+ }
+ }
+
+ explicit NPObjectPointer(NPObjectType* p) : object_(p) {
+ if (object_) {
+ NPN_RetainObject(object_);
+ }
+ }
+
+ ~NPObjectPointer() {
+ if (object_) {
+ NPN_ReleaseObject(object_);
+ }
+ }
+
+ NPObjectPointer& operator=(const NPObjectPointer& rhs) {
+ if (object_) {
+ NPN_ReleaseObject(object_);
+ }
+ object_ = rhs.object_;
+ if (object_) {
+ NPN_RetainObject(object_);
+ }
+ return *this;
+ }
+
+ // The NPObject convention for returning an NPObject pointer from a function
+ // is that the caller is responsible for releasing the reference count.
+ static NPObjectPointer FromReturned(NPObjectType* p) {
+ NPObjectPointer pointer(p);
+ if (p) {
+ NPN_ReleaseObject(p);
+ }
+ return pointer;
+ }
+
+ NPObjectType* Get() const {
+ return object_;
+ }
+
+ NPObjectType* operator->() const {
+ return object_;
+ }
+
+ private:
+ NPObjectType* object_;
+};
+
+} // namespace gpu_plugin
+} // namespace o3d
+
+#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_OBJECT_POINTER_H_
diff --git a/o3d/gpu_plugin/np_utils/np_object_pointer_unittest.cc b/o3d/gpu_plugin/np_utils/np_object_pointer_unittest.cc
new file mode 100644
index 0000000..3e96bd3
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_object_pointer_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "o3d/gpu_plugin/np_utils/base_np_object_mock.h"
+#include "o3d/gpu_plugin/np_utils/np_object_pointer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+
+namespace o3d {
+namespace gpu_plugin {
+
+class NPObjectPointerTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ np_class_ = const_cast<NPClass*>(
+ BaseNPObject::GetNPClass<StrictMock<MockBaseNPObject> >());
+
+ // Make sure no MockBaseNPObject objects exist before test.
+ ASSERT_EQ(0, MockBaseNPObject::count());
+
+ raw_pointer_ = static_cast<MockBaseNPObject*>(
+ NPN_CreateObject(NULL, np_class_));
+ }
+
+ virtual void TearDown() {
+ NPN_ReleaseObject(raw_pointer_);
+
+ // Make sure no MockBaseNPObject leaked an object.
+ ASSERT_EQ(0, MockBaseNPObject::count());
+ }
+
+ NPClass* np_class_;
+ MockBaseNPObject* raw_pointer_;
+};
+
+TEST_F(NPObjectPointerTest, PointerIsNullByDefault) {
+ NPObjectPointer<MockBaseNPObject> p;
+ ASSERT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeExplicitlyConstructedFromRawPointer) {
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockBaseNPObject> p(raw_pointer_);
+ ASSERT_TRUE(raw_pointer_ == p.Get());
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest,
+ PointerCanBeExplicitlyConstructedFromNullRawPointer) {
+ NPObjectPointer<MockBaseNPObject> p(NULL);
+ ASSERT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeCopyConstructed) {
+ NPObjectPointer<MockBaseNPObject> p1(raw_pointer_);
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockBaseNPObject> p2(p1);
+ ASSERT_TRUE(raw_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest,
+ PointerCanBeCopyConstructedFromNull) {
+ NPObjectPointer<MockBaseNPObject> p(NULL);
+ ASSERT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeAssigned) {
+ NPObjectPointer<MockBaseNPObject> p1(raw_pointer_);
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockBaseNPObject> p2;
+ p2 = p1;
+ ASSERT_TRUE(raw_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+
+ p2 = NPObjectPointer<MockBaseNPObject>();
+ ASSERT_TRUE(NULL == p2.Get());
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+
+ p2 = p1;
+ ASSERT_TRUE(raw_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest, ArrowOperatorCanBeUsedToAccessNPObjectMembers) {
+ NPIdentifier name = NPN_GetStringIdentifier("hello");
+
+ EXPECT_CALL(*raw_pointer_, HasProperty(name)).WillOnce(Return(true));
+
+ NPObjectPointer<MockBaseNPObject> p(raw_pointer_);
+ EXPECT_TRUE(p->HasProperty(name));
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromReturnedNPObject) {
+ NPN_RetainObject(raw_pointer_);
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockBaseNPObject> p(
+ NPObjectPointer<MockBaseNPObject>::FromReturned(raw_pointer_));
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromReturnedNullNPObject) {
+ NPObjectPointer<MockBaseNPObject> p(
+ NPObjectPointer<MockBaseNPObject>::FromReturned(NULL));
+ EXPECT_TRUE(NULL == p.Get());
+}
+
+} // namespace gpu_plugin
+} // namespace o3d
diff --git a/o3d/gpu_plugin/np_utils/np_variant_utils.cc b/o3d/gpu_plugin/np_utils/np_variant_utils.cc
new file mode 100644
index 0000000..c8ec811
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_variant_utils.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "o3d/gpu_plugin/np_utils/np_variant_utils.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace o3d {
+namespace gpu_plugin {
+
+bool NPVariantToValue(bool* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_BOOLEAN(variant)) {
+ *value = NPVARIANT_TO_BOOLEAN(variant);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(int* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_INT32(variant)) {
+ *value = NPVARIANT_TO_INT32(variant);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(float* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_DOUBLE(variant)) {
+ *value = static_cast<float>(NPVARIANT_TO_DOUBLE(variant));
+ return true;
+ } else if (NPVARIANT_IS_INT32(variant)) {
+ *value = static_cast<float>(NPVARIANT_TO_INT32(variant));
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(double* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_DOUBLE(variant)) {
+ *value = NPVARIANT_TO_DOUBLE(variant);
+ return true;
+ } else if (NPVARIANT_IS_INT32(variant)) {
+ *value = NPVARIANT_TO_INT32(variant);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(std::string* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_STRING(variant)) {
+ const NPString& str = NPVARIANT_TO_STRING(variant);
+ *value = std::string(str.UTF8Characters, str.UTF8Length);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(NPObject** value, const NPVariant& variant) {
+ if (NPVARIANT_IS_NULL(variant)) {
+ *value = NULL;
+ return true;
+ } else if (NPVARIANT_IS_OBJECT(variant)) {
+ *value = NPVARIANT_TO_OBJECT(variant);
+ return true;
+ }
+
+ return false;
+}
+
+void ValueToNPVariant(bool value, NPVariant* variant) {
+ BOOLEAN_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(int value, NPVariant* variant) {
+ INT32_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(float value, NPVariant* variant) {
+ DOUBLE_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(double value, NPVariant* variant) {
+ DOUBLE_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(const std::string& value, NPVariant* variant) {
+ NPUTF8* p = static_cast<NPUTF8*>(NPN_MemAlloc(value.length()));
+ memcpy(p, value.c_str(), value.length());
+ STRINGN_TO_NPVARIANT(p, value.length(), *variant);
+}
+
+void ValueToNPVariant(NPObject* value, NPVariant* variant) {
+ if (value) {
+ NPN_RetainObject(value);
+ OBJECT_TO_NPVARIANT(value, *variant);
+ } else {
+ NULL_TO_NPVARIANT(*variant);
+ }
+}
+
+} // namespace gpu_plugin
+} // namespace o3d
diff --git a/o3d/gpu_plugin/np_utils/np_variant_utils.h b/o3d/gpu_plugin/np_utils/np_variant_utils.h
new file mode 100644
index 0000000..4272ffb
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_variant_utils.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_NP_VARIANT_UTILS_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_NP_VARIANT_UTILS_H_
+
+#include <string>
+
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace o3d {
+namespace gpu_plugin {
+
+// Convert NPVariant to C++ type. Returns whether the conversion was successful.
+bool NPVariantToValue(bool* value, const NPVariant& variant);
+bool NPVariantToValue(int* value, const NPVariant& variant);
+bool NPVariantToValue(float* value, const NPVariant& variant);
+bool NPVariantToValue(double* value, const NPVariant& variant);
+bool NPVariantToValue(std::string* value, const NPVariant& variant);
+bool NPVariantToValue(NPObject** value, const NPVariant& variant);
+
+// Convert C++ type to NPVariant.
+void ValueToNPVariant(bool value, NPVariant* variant);
+void ValueToNPVariant(int value, NPVariant* variant);
+void ValueToNPVariant(float value, NPVariant* variant);
+void ValueToNPVariant(double value, NPVariant* variant);
+void ValueToNPVariant(const std::string& value, NPVariant* variant);
+void ValueToNPVariant(NPObject* value, NPVariant* variant);
+
+// NPVariant that autmatically releases in destructor.
+class SmartNPVariant {
+ public:
+ SmartNPVariant() {
+ VOID_TO_NPVARIANT(variant_);
+ }
+
+ ~SmartNPVariant() {
+ Release();
+ }
+
+ template <typename T>
+ bool GetValue(T* v) const {
+ return NPVariantToValue(v, variant_);
+ }
+
+ template <typename T>
+ void SetValue(const T& v) {
+ ValueToNPVariant(v, &variant_);
+ }
+
+ void Release() {
+ NPN_ReleaseVariantValue(&variant_);
+ VOID_TO_NPVARIANT(variant_);
+ }
+
+ NPVariant& GetVariant() {
+ return variant_;
+ }
+
+ const NPVariant& GetVariant() const {
+ return variant_;
+ }
+
+ private:
+ NPVariant variant_;
+ DISALLOW_COPY_AND_ASSIGN(SmartNPVariant);
+};
+
+// These allow a method to be invoked with automatic conversion of C++
+// types to variants for arguments and return values.
+
+inline bool NPInvokeVoid(NPP npp, NPObject* object, NPIdentifier name) {
+ SmartNPVariant result;
+ return NPN_Invoke(npp, object, name, NULL, 0,
+ &result.GetVariant());
+}
+
+template<typename R>
+bool NPInvoke(NPP npp, NPObject* object, NPIdentifier name,
+ R* r) {
+ SmartNPVariant result;
+ if (NPN_Invoke(npp, object, name, NULL, 0,
+ &result.GetVariant())) {
+ return result.GetValue(r);
+ }
+ return false;
+}
+
+template<typename P0>
+bool NPInvokeVoid(NPP npp, NPObject* object, NPIdentifier name,
+ P0 p0) {
+ SmartNPVariant args[1];
+ args[0].SetValue(p0);
+ SmartNPVariant result;
+ return NPN_Invoke(npp, object, name, &args[0].GetVariant(), 1,
+ &result.GetVariant());
+}
+
+template<typename R, typename P0>
+bool NPInvoke(NPP npp, NPObject* object, NPIdentifier name,
+ P0 p0, R* r) {
+ SmartNPVariant args[1];
+ args[0].SetValue(p0);
+ SmartNPVariant result;
+ if (NPN_Invoke(npp, object, name, &args[0].GetVariant(), 1,
+ &result.GetVariant())) {
+ return result.GetValue(r);
+ }
+ return false;
+}
+
+template<typename P0, typename P1>
+bool NPInvokeVoid(NPP npp, NPObject* object, NPIdentifier name,
+ P0 p0, P1 p1) {
+ SmartNPVariant args[2];
+ args[0].SetValue(p0);
+ args[1].SetValue(p1);
+ SmartNPVariant result;
+ return NPN_Invoke(npp, object, name, &args[0].GetVariant(), 2,
+ &result.GetVariant());
+}
+
+template<typename R, typename P0, typename P1>
+bool NPInvoke(NPP npp, NPObject* object, NPIdentifier name,
+ P0 p0, P1 p1, R* r) {
+ SmartNPVariant args[2];
+ args[0].SetValue(p0);
+ args[1].SetValue(p1);
+ SmartNPVariant result;
+ if (NPN_Invoke(npp, object, name, &args[0].GetVariant(), 2,
+ &result.GetVariant())) {
+ return result.GetValue(r);
+ }
+ return false;
+}
+
+} // namespace gpu_plugin
+} // namespace o3d
+
+#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_VARIANT_UTILS_H_
diff --git a/o3d/gpu_plugin/np_utils/np_variant_utils_unittest.cc b/o3d/gpu_plugin/np_utils/np_variant_utils_unittest.cc
new file mode 100644
index 0000000..fdf40ce
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/np_variant_utils_unittest.cc
@@ -0,0 +1,299 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "o3d/gpu_plugin/np_utils/base_np_object_mock.h"
+#include "o3d/gpu_plugin/np_utils/np_variant_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::MakeMatcher;
+using testing::Matcher;
+using testing::Pointee;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace o3d {
+namespace gpu_plugin {
+
+class NPVariantUtilsTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ np_class_ = const_cast<NPClass*>(
+ BaseNPObject::GetNPClass<StrictMock<MockBaseNPObject> >());
+
+ // Make sure no MockBaseNPObject objects exist before test.
+ ASSERT_EQ(0, MockBaseNPObject::count());
+ }
+
+ virtual void TearDown() {
+ // Make sure no MockBaseNPObject leaked an object.
+ ASSERT_EQ(0, MockBaseNPObject::count());
+ }
+
+ NPP_t npp_;
+ NPClass* np_class_;
+ NPVariant variant_;
+};
+
+TEST_F(NPVariantUtilsTest, TestBoolNPVariantToValue) {
+ bool v;
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_FALSE(v);
+
+ BOOLEAN_TO_NPVARIANT(true, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_TRUE(v);
+
+ INT32_TO_NPVARIANT(7, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestIntNPVariantToValue) {
+ INT32_TO_NPVARIANT(7, variant_);
+
+ int v1;
+ EXPECT_TRUE(NPVariantToValue(&v1, variant_));
+ EXPECT_EQ(7, v1);
+
+ float v2;
+ EXPECT_TRUE(NPVariantToValue(&v2, variant_));
+ EXPECT_EQ(7.0f, v2);
+
+ double v3;
+ EXPECT_TRUE(NPVariantToValue(&v3, variant_));
+ EXPECT_EQ(7.0, v3);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v1, variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestFloatNPVariantToValue) {
+ float v;
+
+ DOUBLE_TO_NPVARIANT(7.0, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(7.0f, v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestDoubleNPVariantToValue) {
+ double v;
+
+ DOUBLE_TO_NPVARIANT(7.0, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(7.0, v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestStringNPVariantToValue) {
+ std::string v;
+
+ STRINGZ_TO_NPVARIANT("hello", variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(std::string("hello"), v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestObjectNPVariantToValue) {
+ NPObject* object = NPN_CreateObject(NULL, np_class_);
+ NPObject* v;
+
+ OBJECT_TO_NPVARIANT(object, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(object, v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+
+ NPN_ReleaseObject(object);
+}
+
+TEST_F(NPVariantUtilsTest, TestNullNPVariantToValue) {
+ NPObject* v;
+
+ NULL_TO_NPVARIANT(variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_TRUE(NULL == v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestBoolValueToNPVariant) {
+ ValueToNPVariant(true, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(variant_));
+ EXPECT_TRUE(NPVARIANT_TO_BOOLEAN(variant_));
+
+ ValueToNPVariant(false, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(variant_));
+ EXPECT_FALSE(NPVARIANT_TO_BOOLEAN(variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestIntValueToNPVariant) {
+ ValueToNPVariant(7, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_INT32(variant_));
+ EXPECT_EQ(7, NPVARIANT_TO_INT32(variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestFloatValueToNPVariant) {
+ ValueToNPVariant(7.0f, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(variant_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestDoubleValueToNPVariant) {
+ ValueToNPVariant(7.0, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(variant_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(variant_));
+}
+
+TEST_F(NPVariantUtilsTest, TestStringValueToNPVariant) {
+ ValueToNPVariant(std::string("hello"), &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_STRING(variant_));
+ EXPECT_EQ(std::string("hello"),
+ std::string(variant_.value.stringValue.UTF8Characters,
+ variant_.value.stringValue.UTF8Length));
+}
+
+TEST_F(NPVariantUtilsTest, TestObjectValueToNPVariant) {
+ NPObject* object = NPN_CreateObject(NULL, np_class_);
+
+ ValueToNPVariant(object, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_OBJECT(variant_));
+ EXPECT_EQ(object, NPVARIANT_TO_OBJECT(variant_));
+
+ NPN_ReleaseVariantValue(&variant_);
+ NPN_ReleaseObject(object);
+}
+
+TEST_F(NPVariantUtilsTest, TestNullValueToNPVariant) {
+ ValueToNPVariant(static_cast<NPObject*>(NULL), &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_NULL(variant_));
+}
+
+template <typename T>
+class VariantMatcher : public testing::MatcherInterface<const NPVariant&> {
+ public:
+ explicit VariantMatcher(const T& value) : value_(value) {
+ }
+
+ virtual bool Matches(const NPVariant& variant) const {
+ T other_value;
+ return NPVariantToValue(&other_value, variant) && other_value == value_;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "equals " << value_;
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not equal " << value_;
+ }
+
+ private:
+ T value_;
+};
+
+template <typename T>
+Matcher<const NPVariant&> VariantMatches(const T& value) {
+ return MakeMatcher(new VariantMatcher<T>(value));
+}
+
+TEST_F(NPVariantUtilsTest, CanInvokeVoidMethodWithNativeTypes) {
+ NPIdentifier name = NPN_GetStringIdentifier("foo");
+ MockBaseNPObject* object = static_cast<MockBaseNPObject*>(
+ NPN_CreateObject(NULL, np_class_));
+
+ VOID_TO_NPVARIANT(variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(true)));
+
+ EXPECT_TRUE(NPInvokeVoid(NULL, object, name, 7));
+
+ NPN_ReleaseObject(object);
+}
+
+TEST_F(NPVariantUtilsTest, InvokeVoidMethodCanFail) {
+ NPIdentifier name = NPN_GetStringIdentifier("foo");
+ MockBaseNPObject* object = static_cast<MockBaseNPObject*>(
+ NPN_CreateObject(NULL, np_class_));
+
+ VOID_TO_NPVARIANT(variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(false)));
+
+ EXPECT_FALSE(NPInvokeVoid(NULL, object, name, 7));
+
+ NPN_ReleaseObject(object);
+}
+
+TEST_F(NPVariantUtilsTest, CanInvokeNonVoidMethodWithNativeTypes) {
+ NPIdentifier name = NPN_GetStringIdentifier("foo");
+ MockBaseNPObject* object = static_cast<MockBaseNPObject*>(
+ NPN_CreateObject(NULL, np_class_));
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(true)));
+
+ double r;
+ EXPECT_TRUE(NPInvoke(NULL, object, name, 7, &r));
+ EXPECT_EQ(1.5, r);
+
+ NPN_ReleaseObject(object);
+}
+
+TEST_F(NPVariantUtilsTest, InvokeNonVoidMethodCanFail) {
+ NPIdentifier name = NPN_GetStringIdentifier("foo");
+ MockBaseNPObject* object = static_cast<MockBaseNPObject*>(
+ NPN_CreateObject(NULL, np_class_));
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(false)));
+
+ double r;
+ EXPECT_FALSE(NPInvoke(NULL, object, name, 7, &r));
+
+ NPN_ReleaseObject(object);
+}
+
+TEST_F(NPVariantUtilsTest, InvokeNonVoidMethodFailsIfResultIsIncompatible) {
+ NPIdentifier name = NPN_GetStringIdentifier("foo");
+ MockBaseNPObject* object = static_cast<MockBaseNPObject*>(
+ NPN_CreateObject(NULL, np_class_));
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(true)));
+
+ int r;
+ EXPECT_FALSE(NPInvoke(NULL, object, name, 7, &r));
+
+ NPN_ReleaseObject(object);
+}
+
+} // namespace gpu_plugin
+} // namespace o3d
diff --git a/o3d/gpu_plugin/np_utils/npn_test_stub.cc b/o3d/gpu_plugin/np_utils/npn_test_stub.cc
new file mode 100644
index 0000000..4e8b472
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/npn_test_stub.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+
+#include <set>
+#include <string>
+
+#include "o3d/gpu_plugin/np_utils/npn_test_stub.h"
+
+// Simple implementation of subset of the NPN functions for testing.
+
+namespace {
+ std::set<std::string> names;
+}
+
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name) {
+ std::set<std::string>::iterator it = names.find(name);
+ if (it == names.end()) {
+ it = names.insert(name).first;
+ }
+ return const_cast<NPUTF8*>((*it).c_str());
+}
+
+void* NPN_MemAlloc(size_t size) {
+ return malloc(size);
+}
+
+void NPN_MemFree(void* p) {
+ free(p);
+}
+
+NPObject* NPN_CreateObject(NPP npp, NPClass* cl) {
+ NPObject* object = cl->allocate(npp, cl);
+ object->referenceCount = 1;
+ object->_class = cl;
+ return object;
+}
+
+NPObject* NPN_RetainObject(NPObject* object) {
+ ++object->referenceCount;
+ return object;
+}
+
+void NPN_ReleaseObject(NPObject* object) {
+ --object->referenceCount;
+ if (object->referenceCount == 0) {
+ object->_class->deallocate(object);
+ }
+}
+
+void NPN_ReleaseVariantValue(NPVariant* variant) {
+ if (NPVARIANT_IS_STRING(*variant)) {
+ NPN_MemFree(const_cast<NPUTF8*>(variant->value.stringValue.UTF8Characters));
+ } else if (NPVARIANT_IS_OBJECT(*variant)) {
+ NPN_ReleaseObject(NPVARIANT_TO_OBJECT(*variant));
+ }
+}
+
+bool NPN_Invoke(NPP npp, NPObject* object, NPIdentifier name,
+ const NPVariant* args, uint32_t num_args, NPVariant* result) {
+ return object->_class->invoke(object, name, args, num_args, result);
+}
diff --git a/o3d/gpu_plugin/np_utils/npn_test_stub.h b/o3d/gpu_plugin/np_utils/npn_test_stub.h
new file mode 100644
index 0000000..9567c17
--- /dev/null
+++ b/o3d/gpu_plugin/np_utils/npn_test_stub.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef O3D_GPU_PLUGIN_NP_UTILS_NPN_TEST_STUB_H_
+#define O3D_GPU_PLUGIN_NP_UTILS_NPN_TEST_STUB_H_
+
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+// Simple implementation of subset of the NPN functions for testing.
+
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name);
+void* NPN_MemAlloc(size_t size);
+void NPN_MemFree(void* p);
+NPObject* NPN_CreateObject(NPP npp, NPClass* cl);
+NPObject* NPN_RetainObject(NPObject* object);
+void NPN_ReleaseObject(NPObject* object);
+void NPN_ReleaseVariantValue(NPVariant* variant);
+bool NPN_Invoke(NPP npp, NPObject* object, NPIdentifier name,
+ const NPVariant* args, uint32_t num_args, NPVariant* result);
+
+#endif // O3D_GPU_PLUGIN_NP_UTILS_NPN_TEST_STUB_H_