diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-24 23:41:07 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-24 23:41:07 +0000 |
commit | e50d02901c840370bdccd2fcdf460754649b0874 (patch) | |
tree | 92c5995ac1f3a198c6e434b058aef5493aea8127 | |
parent | 8d19b928672734f9ecd34e3492420fd2d42b8e3a (diff) | |
download | chromium_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
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_ |