diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-11 18:48:49 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-11 18:48:49 +0000 |
commit | 85c5b0230b1a9a9d8e02ad6049c31bf55eb5c076 (patch) | |
tree | a4d8ddd09d0beeffa01b2ad9222698cd914b4717 /o3d/gpu_plugin | |
parent | 5222bb1495ef2e9a6294da8a8f1b9c1dae2e54e4 (diff) | |
download | chromium_src-85c5b0230b1a9a9d8e02ad6049c31bf55eb5c076.zip chromium_src-85c5b0230b1a9a9d8e02ad6049c31bf55eb5c076.tar.gz chromium_src-85c5b0230b1a9a9d8e02ad6049c31bf55eb5c076.tar.bz2 |
Reverting 31676.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31682 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/gpu_plugin')
48 files changed, 5858 insertions, 0 deletions
diff --git a/o3d/gpu_plugin/command_buffer.cc b/o3d/gpu_plugin/command_buffer.cc new file mode 100644 index 0000000..15f52da --- /dev/null +++ b/o3d/gpu_plugin/command_buffer.cc @@ -0,0 +1,143 @@ +// 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/command_buffer.h" + +using ::base::SharedMemory; + +namespace gpu_plugin { + +CommandBuffer::CommandBuffer(NPP npp) + : npp_(npp), + size_(0), + get_offset_(0), + put_offset_(0), + token_(0), + parse_error_(0), + error_status_(false) { + // Element zero is always NULL. + registered_objects_.push_back(linked_ptr<SharedMemory>()); +} + +CommandBuffer::~CommandBuffer() { +} + +bool CommandBuffer::Initialize(::base::SharedMemory* ring_buffer) { + DCHECK(ring_buffer); + + // Fail if already initialized. + if (ring_buffer_.get()) + return false; + + size_t size_in_bytes = ring_buffer->max_size(); + size_ = size_in_bytes / sizeof(int32); + ring_buffer_.reset(ring_buffer); + + return true; +} + +SharedMemory* CommandBuffer::GetRingBuffer() { + return ring_buffer_.get(); +} + +int32 CommandBuffer::GetSize() { + return size_; +} + +int32 CommandBuffer::SyncOffsets(int32 put_offset) { + if (put_offset < 0 || put_offset >= size_) + return -1; + + put_offset_ = put_offset; + + if (put_offset_change_callback_.get()) { + put_offset_change_callback_->Run(); + } + + return get_offset_; +} + +int32 CommandBuffer::GetGetOffset() { + return get_offset_; +} + +void CommandBuffer::SetGetOffset(int32 get_offset) { + DCHECK(get_offset >= 0 && get_offset < size_); + get_offset_ = get_offset; +} + +int32 CommandBuffer::GetPutOffset() { + return put_offset_; +} + +void CommandBuffer::SetPutOffsetChangeCallback(Callback0::Type* callback) { + put_offset_change_callback_.reset(callback); +} + +int32 CommandBuffer::CreateTransferBuffer(size_t size) { + linked_ptr<SharedMemory> buffer(new SharedMemory); + if (!buffer->Create(std::wstring(), false, false, size)) + return -1; + + if (unused_registered_object_elements_.empty()) { + // Check we haven't exceeded the range that fits in a 32-bit integer. + int32 handle = static_cast<int32>(registered_objects_.size()); + if (handle != registered_objects_.size()) + return -1; + + registered_objects_.push_back(buffer); + return handle; + } + + int32 handle = *unused_registered_object_elements_.begin(); + unused_registered_object_elements_.erase( + unused_registered_object_elements_.begin()); + DCHECK(!registered_objects_[handle].get()); + registered_objects_[handle] = buffer; + return handle; +} + +void CommandBuffer::DestroyTransferBuffer(int32 handle) { + if (handle <= 0) + return; + + if (static_cast<size_t>(handle) >= registered_objects_.size()) + return; + + registered_objects_[handle].reset(); + unused_registered_object_elements_.insert(handle); + + // Remove all null objects from the end of the vector. This allows the vector + // to shrink when, for example, all objects are unregistered. Note that this + // loop never removes element zero, which is always NULL. + while (registered_objects_.size() > 1 && !registered_objects_.back().get()) { + registered_objects_.pop_back(); + unused_registered_object_elements_.erase( + static_cast<int32>(registered_objects_.size())); + } +} + +::base::SharedMemory* CommandBuffer::GetTransferBuffer(int32 handle) { + if (handle < 0) + return NULL; + + if (static_cast<size_t>(handle) >= registered_objects_.size()) + return NULL; + + return registered_objects_[handle].get(); +} + +int32 CommandBuffer::ResetParseError() { + int32 last_error = parse_error_; + parse_error_ = 0; + return last_error; +} + +void CommandBuffer::SetParseError(int32 parse_error) { + if (parse_error_ == 0) { + parse_error_ = parse_error; + } +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/command_buffer.h b/o3d/gpu_plugin/command_buffer.h new file mode 100644 index 0000000..84457c0 --- /dev/null +++ b/o3d/gpu_plugin/command_buffer.h @@ -0,0 +1,130 @@ +// 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_COMMAND_BUFFER_H_ +#define O3D_GPU_PLUGIN_COMMAND_BUFFER_H_ + +#include <set> +#include <vector> + +#include "base/linked_ptr.h" +#include "base/scoped_ptr.h" +#include "base/shared_memory.h" +#include "base/task.h" +#include "o3d/gpu_plugin/np_utils/default_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_dispatcher.h" + +namespace gpu_plugin { + +// An NPObject that implements a shared memory command buffer and a synchronous +// API to manage the put and get pointers. +class CommandBuffer : public DefaultNPObject<NPObject> { + public: + explicit CommandBuffer(NPP npp); + virtual ~CommandBuffer(); + + // Initialize the command buffer with the given ring buffer. Takes ownership + // of ring buffer. + virtual bool Initialize(::base::SharedMemory* ring_buffer); + + // Gets the shared memory ring buffer object for the command buffer. + virtual ::base::SharedMemory* GetRingBuffer(); + + virtual int32 GetSize(); + + // The writer calls this to update its put offset. This function returns the + // reader's most recent get offset. Does not return until after the put offset + // change callback has been invoked. Returns -1 if the put offset is invalid. + virtual int32 SyncOffsets(int32 put_offset); + + // Returns the current get offset. This can be called from any thread. + virtual int32 GetGetOffset(); + + // Sets the current get offset. This can be called from any thread. + virtual void SetGetOffset(int32 get_offset); + + // Returns the current put offset. This can be called from any thread. + virtual int32 GetPutOffset(); + + // Sets a callback that should be posted on another thread whenever the put + // offset is changed. The callback must not return until some progress has + // been made (unless the command buffer is empty), i.e. the + // get offset must have changed. It need not process the entire command + // buffer though. This allows concurrency between the writer and the reader + // while giving the writer a means of waiting for the reader to make some + // progress before attempting to write more to the command buffer. Avoiding + // the use of a synchronization primitive like a condition variable to + // synchronize reader and writer reduces the risk of deadlock. + // Takes ownership of callback. The callback is invoked on the plugin thread. + virtual void SetPutOffsetChangeCallback(Callback0::Type* callback); + + // Create a shared memory transfer buffer and return a handle that uniquely + // identifies it or -1 on error. + virtual int32 CreateTransferBuffer(size_t size); + + // Destroy a shared memory transfer buffer and recycle the handle. + virtual void DestroyTransferBuffer(int32 id); + + // Get the shared memory associated with a handle. + virtual ::base::SharedMemory* GetTransferBuffer(int32 handle); + + // Get the current token value. This is used for by the writer to defer + // changes to shared memory objects until the reader has reached a certain + // point in the command buffer. The reader is responsible for updating the + // token value, for example in response to an asynchronous set token command + // embedded in the command buffer. The default token value is zero. + int32 GetToken() { + return token_; + } + + // Allows the reader to update the current token value. + void SetToken(int32 token) { + token_ = token; + } + + // Get the current parse error and reset it to zero. Zero means no error. Non- + // zero means error. The default error status is zero. + int32 ResetParseError(); + + // Allows the reader to set the current parse error. + void SetParseError(int32 parse_error); + + // Returns whether the command buffer is in the error state. + bool GetErrorStatus() { + return error_status_; + } + + // Allows the reader to set the error status. Once in an error state, the + // command buffer cannot recover and ceases to process commands. + void RaiseErrorStatus() { + error_status_ = true; + } + + NP_UTILS_BEGIN_DISPATCHER_CHAIN(CommandBuffer, DefaultNPObject<NPObject>) + NP_UTILS_DISPATCHER(GetSize, int32()) + NP_UTILS_DISPATCHER(SyncOffsets, int32(int32 get_offset)) + NP_UTILS_DISPATCHER(GetGetOffset, int32()); + NP_UTILS_DISPATCHER(GetPutOffset, int32()); + NP_UTILS_DISPATCHER(GetToken, int32()); + NP_UTILS_DISPATCHER(ResetParseError, int32()); + NP_UTILS_DISPATCHER(GetErrorStatus, bool()); + NP_UTILS_END_DISPATCHER_CHAIN + + private: + NPP npp_; + scoped_ptr< ::base::SharedMemory> ring_buffer_; + int32 size_; + int32 get_offset_; + int32 put_offset_; + scoped_ptr<Callback0::Type> put_offset_change_callback_; + std::vector<linked_ptr< ::base::SharedMemory> > registered_objects_; + std::set<int32> unused_registered_object_elements_; + int32 token_; + int32 parse_error_; + bool error_status_; +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_COMMAND_BUFFER_H_ diff --git a/o3d/gpu_plugin/command_buffer_mock.h b/o3d/gpu_plugin/command_buffer_mock.h new file mode 100644 index 0000000..ab82bdb --- /dev/null +++ b/o3d/gpu_plugin/command_buffer_mock.h @@ -0,0 +1,42 @@ +// 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_COMMAND_BUFFER_MOCK_H_ +#define O3D_GPU_PLUGIN_COMMAND_BUFFER_MOCK_H_ + +#include "o3d/gpu_plugin/command_buffer.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace gpu_plugin { + +// An NPObject that implements a shared memory command buffer and a synchronous +// API to manage the put and get pointers. +class MockCommandBuffer : public CommandBuffer { + public: + explicit MockCommandBuffer(NPP npp) : CommandBuffer(npp) { + ON_CALL(*this, GetRingBuffer()) + .WillByDefault(testing::Return(static_cast<::base::SharedMemory*>(NULL))); + ON_CALL(*this, GetTransferBuffer(testing::_)) + .WillByDefault(testing::Return(static_cast<::base::SharedMemory*>(NULL))); + } + + MOCK_METHOD1(Initialize, bool(::base::SharedMemory* ring_buffer)); + MOCK_METHOD0(GetRingBuffer, ::base::SharedMemory*()); + MOCK_METHOD0(GetSize, int32()); + MOCK_METHOD1(SyncOffsets, int32(int32 put_offset)); + MOCK_METHOD0(GetGetOffset, int32()); + MOCK_METHOD1(SetGetOffset, void(int32 get_offset)); + MOCK_METHOD0(GetPutOffset, int32()); + MOCK_METHOD1(SetPutOffsetChangeCallback, void(Callback0::Type* callback)); + MOCK_METHOD1(CreateTransferBuffer, int32(size_t size)); + MOCK_METHOD1(DestroyTransferBuffer, void(int32 handle)); + MOCK_METHOD1(GetTransferBuffer, ::base::SharedMemory*(int32 handle)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockCommandBuffer); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_COMMAND_BUFFER_MOCK_H_ diff --git a/o3d/gpu_plugin/command_buffer_unittest.cc b/o3d/gpu_plugin/command_buffer_unittest.cc new file mode 100644 index 0000000..5041d48 --- /dev/null +++ b/o3d/gpu_plugin/command_buffer_unittest.cc @@ -0,0 +1,182 @@ +// 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 "base/thread.h" +#include "o3d/gpu_plugin/command_buffer.h" +#include "o3d/gpu_plugin/np_utils/np_browser_mock.h" +#include "o3d/gpu_plugin/np_utils/dynamic_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_object_mock.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +using base::SharedMemory; +using testing::_; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +namespace gpu_plugin { + +class CommandBufferTest : public testing::Test { + protected: + virtual void SetUp() { + command_buffer_ = NPCreateObject<CommandBuffer>(NULL); + } + + MockNPBrowser mock_browser_; + NPObjectPointer<CommandBuffer> command_buffer_; +}; + +TEST_F(CommandBufferTest, NullRingBufferByDefault) { + EXPECT_TRUE(NULL == command_buffer_->GetRingBuffer()); +} + +TEST_F(CommandBufferTest, InitializesCommandBuffer) { + SharedMemory* ring_buffer = new SharedMemory; + EXPECT_TRUE(ring_buffer->Create(std::wstring(), false, false, 1024)); + EXPECT_TRUE(command_buffer_->Initialize(ring_buffer)); + EXPECT_TRUE(ring_buffer == command_buffer_->GetRingBuffer()); + EXPECT_EQ(256, command_buffer_->GetSize()); +} + +TEST_F(CommandBufferTest, InitializeFailsSecondTime) { + SharedMemory* ring_buffer = new SharedMemory; + EXPECT_TRUE(command_buffer_->Initialize(ring_buffer)); + EXPECT_FALSE(command_buffer_->Initialize(ring_buffer)); +} + +TEST_F(CommandBufferTest, GetAndPutOffsetsDefaultToZero) { + EXPECT_EQ(0, command_buffer_->GetGetOffset()); + EXPECT_EQ(0, command_buffer_->GetPutOffset()); +} + +class MockCallback : public CallbackRunner<Tuple0> { + public: + MOCK_METHOD1(RunWithParams, void(const Tuple0&)); +}; + +TEST_F(CommandBufferTest, CanSyncGetAndPutOffset) { + SharedMemory* ring_buffer = new SharedMemory; + ring_buffer->Create(std::wstring(), false, false, 1024); + + EXPECT_TRUE(command_buffer_->Initialize(ring_buffer)); + + StrictMock<MockCallback>* put_offset_change_callback = + new StrictMock<MockCallback>; + command_buffer_->SetPutOffsetChangeCallback(put_offset_change_callback); + + EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); + EXPECT_EQ(0, command_buffer_->SyncOffsets(2)); + EXPECT_EQ(2, command_buffer_->GetPutOffset()); + + EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); + EXPECT_EQ(0, command_buffer_->SyncOffsets(4)); + EXPECT_EQ(4, command_buffer_->GetPutOffset()); + + command_buffer_->SetGetOffset(2); + EXPECT_EQ(2, command_buffer_->GetGetOffset()); + EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); + EXPECT_EQ(2, command_buffer_->SyncOffsets(6)); + + EXPECT_EQ(-1, command_buffer_->SyncOffsets(-1)); + EXPECT_EQ(-1, command_buffer_->SyncOffsets(1024)); +} + +TEST_F(CommandBufferTest, ZeroHandleMapsToNull) { + EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(0)); +} + +TEST_F(CommandBufferTest, NegativeHandleMapsToNull) { + EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(-1)); +} + +TEST_F(CommandBufferTest, OutOfRangeHandleMapsToNull) { + EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(1)); +} + +TEST_F(CommandBufferTest, CanCreateTransferBuffers) { + int32 handle = command_buffer_->CreateTransferBuffer(1024); + EXPECT_EQ(1, handle); + SharedMemory* buffer = command_buffer_->GetTransferBuffer(handle); + ASSERT_TRUE(NULL != buffer); + EXPECT_EQ(1024, buffer->max_size()); +} + +TEST_F(CommandBufferTest, CreateTransferBufferReturnsDistinctHandles) { + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); +} + +TEST_F(CommandBufferTest, CreateTransferBufferReusesUnregisteredHandles) { + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); + EXPECT_EQ(2, command_buffer_->CreateTransferBuffer(1024)); + command_buffer_->DestroyTransferBuffer(1); + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); + EXPECT_EQ(3, command_buffer_->CreateTransferBuffer(1024)); +} + +TEST_F(CommandBufferTest, CannotUnregisterHandleZero) { + command_buffer_->DestroyTransferBuffer(0); + EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(0)); + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); +} + +TEST_F(CommandBufferTest, CannotUnregisterNegativeHandles) { + command_buffer_->DestroyTransferBuffer(-1); + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); +} + +TEST_F(CommandBufferTest, CannotUnregisterUnregisteredHandles) { + command_buffer_->DestroyTransferBuffer(1); + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); +} + +// Testing this case specifically because there is an optimization that takes +// a different code path in this case. +TEST_F(CommandBufferTest, UnregistersLastRegisteredHandle) { + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); + command_buffer_->DestroyTransferBuffer(1); + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); +} + +// Testing this case specifically because there is an optimization that takes +// a different code path in this case. +TEST_F(CommandBufferTest, UnregistersTwoLastRegisteredHandles) { + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); + EXPECT_EQ(2, command_buffer_->CreateTransferBuffer(1024)); + command_buffer_->DestroyTransferBuffer(2); + command_buffer_->DestroyTransferBuffer(1); + EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); +} + +TEST_F(CommandBufferTest, DefaultTokenIsZero) { + EXPECT_EQ(0, command_buffer_->GetToken()); +} + +TEST_F(CommandBufferTest, CanSetToken) { + command_buffer_->SetToken(7); + EXPECT_EQ(7, command_buffer_->GetToken()); +} + +TEST_F(CommandBufferTest, DefaultParseErrorIsNoError) { + EXPECT_EQ(0, command_buffer_->ResetParseError()); +} + +TEST_F(CommandBufferTest, CanSetAndResetParseError) { + command_buffer_->SetParseError(1); + EXPECT_EQ(1, command_buffer_->ResetParseError()); + EXPECT_EQ(0, command_buffer_->ResetParseError()); +} + +TEST_F(CommandBufferTest, DefaultErrorStatusIsFalse) { + EXPECT_FALSE(command_buffer_->GetErrorStatus()); +} + +TEST_F(CommandBufferTest, CanRaiseErrorStatus) { + command_buffer_->RaiseErrorStatus(); + EXPECT_TRUE(command_buffer_->GetErrorStatus()); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin.cc b/o3d/gpu_plugin/gpu_plugin.cc new file mode 100644 index 0000000..fa270f7 --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin.cc @@ -0,0 +1,136 @@ +// 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/gpu_plugin.h" +#include "o3d/gpu_plugin/gpu_plugin_object_factory.h" +#include "o3d/gpu_plugin/np_utils/np_browser.h" +#include "o3d/gpu_plugin/np_utils/np_plugin_object.h" +#include "o3d/gpu_plugin/np_utils/np_plugin_object_factory.h" + +#if defined(O3D_IN_CHROME) +#include "webkit/glue/plugins/nphostapi.h" +#else +#include "o3d/third_party/npapi/include/npfunctions.h" +#endif + +namespace gpu_plugin { + +// Definitions of NPAPI plugin entry points. + +namespace { +NPBrowser* g_browser; +GPUPluginObjectFactory g_plugin_object_factory; + +NPError NPP_New(NPMIMEType plugin_type, NPP instance, + uint16 mode, int16 argc, char* argn[], + char* argv[], NPSavedData* saved) { + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + PluginObject* plugin_object = + NPPluginObjectFactory::get()->CreatePluginObject(instance, plugin_type); + if (!plugin_object) + return NPERR_GENERIC_ERROR; + + instance->pdata = plugin_object; + + NPError error = plugin_object->New(plugin_type, argc, argn, argv, saved); + if (error != NPERR_NO_ERROR) { + plugin_object->Release(); + } + + return error; +} + +NPError NPP_Destroy(NPP instance, NPSavedData** saved) { + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata); + NPError error = plugin_object->Destroy(saved); + + if (error == NPERR_NO_ERROR) { + plugin_object->Release(); + } + + return error; +} + +NPError NPP_SetWindow(NPP instance, NPWindow* window) { + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata); + return plugin_object->SetWindow(window); +} + +int16 NPP_HandleEvent(NPP instance, void* event) { + if (!instance) + return 0; + + PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata); + return plugin_object->HandleEvent(static_cast<NPEvent*>(event)); +} + +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) { + if (!instance) + return NPERR_INVALID_INSTANCE_ERROR; + + PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata); + switch (variable) { + case NPPVpluginScriptableNPObject: + *reinterpret_cast<NPObject**>(value) = + plugin_object->GetScriptableNPObject(); + return NPERR_NO_ERROR; + default: + return NPERR_GENERIC_ERROR; + } +} + +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) { + return NPERR_NO_ERROR; +} +} + +NPError NP_GetEntryPoints(NPPluginFuncs* funcs) { + funcs->newp = NPP_New; + funcs->destroy = NPP_Destroy; + funcs->setwindow = NPP_SetWindow; + funcs->event = NPP_HandleEvent; + funcs->getvalue = NPP_GetValue; + funcs->setvalue = NPP_SetValue; + return NPERR_NO_ERROR; +} + +#if defined(OS_LINUX) +NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs, + NPPluginFuncs* plugin_funcs) { +#else +NPError NP_Initialize(NPNetscapeFuncs *browser_funcs) { +#endif + if (!browser_funcs) + return NPERR_INVALID_FUNCTABLE_ERROR; + + if (g_browser) + return NPERR_GENERIC_ERROR; + +#if defined(OS_LINUX) + NP_GetEntryPoints(plugin_funcs); +#endif + + g_browser = new NPBrowser(browser_funcs); + + return NPERR_NO_ERROR; +} + +NPError NP_Shutdown() { + if (!g_browser) + return NPERR_GENERIC_ERROR; + + delete g_browser; + g_browser = NULL; + + return NPERR_NO_ERROR; +} +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin.gyp b/o3d/gpu_plugin/gpu_plugin.gyp new file mode 100644 index 0000000..c604a30 --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin.gyp @@ -0,0 +1,162 @@ +# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'includes': [ + '../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'np_utils', + 'type': '<(library)', + 'dependencies': [ + '../../base/base.gyp:base', + '../build/o3d_in_chrome.gyp:o3d_in_chrome', + ], + 'include_dirs': [ + '../..', + '../../third_party/npapi', + ], + 'all_dependent_settings': { + 'include_dirs': [ + '../..', + '../../third_party/npapi', + ], + }, # 'all_dependent_settings' + 'sources': [ + 'np_utils/default_np_object.h', + 'np_utils/dynamic_np_object.cc', + 'np_utils/dynamic_np_object.h', + 'np_utils/np_browser.cc', + 'np_utils/np_browser.h', + 'np_utils/np_browser_mock.h', + 'np_utils/np_browser_stub.cc', + 'np_utils/np_browser_stub.h', + 'np_utils/np_class.h', + 'np_utils/np_dispatcher.cc', + 'np_utils/np_dispatcher.h', + 'np_utils/np_dispatcher_specializations.h', + 'np_utils/np_headers.h', + 'np_utils/np_object_mock.h', + 'np_utils/np_object_pointer.h', + 'np_utils/np_plugin_object.h', + 'np_utils/np_plugin_object_mock.h', + 'np_utils/np_plugin_object_factory.cc', + 'np_utils/np_plugin_object_factory.h', + 'np_utils/np_plugin_object_factory_mock.h', + 'np_utils/np_utils.cc', + 'np_utils/np_utils.h', + 'np_utils/webkit_browser.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. + { + 'target_name': 'np_utils_unittests', + 'type': 'executable', + 'dependencies': [ + 'np_utils', + '../../testing/gmock.gyp:gmock', + '../../testing/gmock.gyp:gmockmain', + '../../testing/gtest.gyp:gtest', + ], + 'include_dirs': [ + '../..', + ], + 'all_dependent_settings': { + 'include_dirs': [ + '../..', + ], + }, # 'all_dependent_settings' + 'sources': [ + 'np_utils/dispatched_np_object_unittest.cc', + 'np_utils/dynamic_np_object_unittest.cc', + 'np_utils/np_class_unittest.cc', + 'np_utils/np_object_pointer_unittest.cc', + 'np_utils/np_utils_unittest.cc', + ], + }, + + # These can eventually be merged back into the gpu_plugin target. There + # separated for now so O3D can statically link against them and use command + # buffers in-process without the GPU plugin. + { + 'target_name': 'command_buffer', + 'type': '<(library)', + 'dependencies': [ + '../../base/base.gyp:base', + '../command_buffer/command_buffer.gyp:command_buffer_service', + 'np_utils', + ], + 'all_dependent_settings': { + 'include_dirs': [ + '../..', + ], + }, # 'all_dependent_settings' + 'sources': [ + 'command_buffer.cc', + 'command_buffer.h', + 'command_buffer_mock.h', + 'gpu_processor.h', + 'gpu_processor.cc', + 'gpu_processor_mock.h', + 'gpu_processor_win.cc', + ], + }, + + { + 'target_name': 'gpu_plugin', + 'type': '<(library)', + 'dependencies': [ + '../../base/base.gyp:base', + 'command_buffer', + 'np_utils', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'gpu_plugin.cc', + 'gpu_plugin.h', + 'gpu_plugin_object.cc', + 'gpu_plugin_object.h', + 'gpu_plugin_object_win.cc', + 'gpu_plugin_object_factory.cc', + 'gpu_plugin_object_factory.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. + { + 'target_name': 'gpu_plugin_unittests', + 'type': 'executable', + 'dependencies': [ + '../command_buffer/command_buffer.gyp:command_buffer_service', + 'gpu_plugin', + 'np_utils', + '../../testing/gmock.gyp:gmock', + '../../testing/gmock.gyp:gmockmain', + '../../testing/gtest.gyp:gtest', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'command_buffer_unittest.cc', + 'gpu_plugin_unittest.cc', + 'gpu_plugin_object_unittest.cc', + 'gpu_plugin_object_factory_unittest.cc', + 'gpu_processor_unittest.cc', + ], + }, + ] +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/o3d/gpu_plugin/gpu_plugin.h b/o3d/gpu_plugin/gpu_plugin.h new file mode 100644 index 0000000..1cefa29 --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin.h @@ -0,0 +1,30 @@ +// 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_GPU_PLUGIN_H_ +#define O3D_GPU_PLUGIN_GPU_PLUGIN_H_ + +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +typedef struct _NPPluginFuncs NPPluginFuncs; +typedef struct _NPNetscapeFuncs NPNetscapeFuncs; + +namespace gpu_plugin { + +// Declarations of NPAPI plugin entry points. + +NPError NP_GetEntryPoints(NPPluginFuncs* funcs); + +#if defined(OS_LINUX) +NPError NP_Initialize(NPNetscapeFuncs *browser_funcs, + NPPluginFuncs* plugin_funcs); +#else +NPError NP_Initialize(NPNetscapeFuncs* browser_funcs); +#endif + +NPError NP_Shutdown(); + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_GPU_PLUGIN_H_ diff --git a/o3d/gpu_plugin/gpu_plugin_object.cc b/o3d/gpu_plugin/gpu_plugin_object.cc new file mode 100644 index 0000000..801cbca --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object.cc @@ -0,0 +1,117 @@ +// 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 "base/logging.h" +#include "o3d/gpu_plugin/np_utils/np_utils.h" +#include "o3d/gpu_plugin/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_processor.h" + +using ::base::SharedMemory; + +namespace gpu_plugin { + +const NPUTF8 GPUPluginObject::kPluginType[] = + "application/vnd.google.chrome.gpu-plugin"; + +GPUPluginObject::GPUPluginObject(NPP npp) + : npp_(npp), + status_(kWaitingForNew), + command_buffer_(NPCreateObject<CommandBuffer>(npp)), + processor_(new GPUProcessor(npp, command_buffer_.Get())) { + memset(&window_, 0, sizeof(window_)); +} + +NPError GPUPluginObject::New(NPMIMEType plugin_type, + int16 argc, + char* argn[], + char* argv[], + NPSavedData* saved) { + if (status_ != kWaitingForNew) + return NPERR_GENERIC_ERROR; + + status_ = kWaitingForSetWindow; + + return NPERR_NO_ERROR; +} + +NPError GPUPluginObject::SetWindow(NPWindow* new_window) { + if (status_ == kWaitingForNew || status_ == kDestroyed) + return NPERR_GENERIC_ERROR; + + // PlatformSpecificSetWindow advances the status depending on what happens. + NPError error = PlatformSpecificSetWindow(new_window); + if (error == NPERR_NO_ERROR) { + window_ = *new_window; + + if (event_sync_.Get()) { + NPInvokeVoid(npp_, + event_sync_, + "resize", + static_cast<int32>(window_.width), + static_cast<int32>(window_.height)); + } + } else { + memset(&window_, 0, sizeof(window_)); + } + + return error; +} + +int16 GPUPluginObject::HandleEvent(NPEvent* event) { + return 0; +} + +NPError GPUPluginObject::Destroy(NPSavedData** saved) { + if (status_ == kWaitingForNew || status_ == kDestroyed) + return NPERR_GENERIC_ERROR; + + if (command_buffer_.Get()) { + command_buffer_->SetPutOffsetChangeCallback(NULL); + } + + status_ = kDestroyed; + + return NPERR_NO_ERROR; +} + +void GPUPluginObject::Release() { + DCHECK(status_ == kWaitingForNew || status_ == kDestroyed); + NPBrowser::get()->ReleaseObject(this); +} + +NPObject*GPUPluginObject::GetScriptableNPObject() { + NPBrowser::get()->RetainObject(this); + return this; +} + +NPObjectPointer<NPObject> GPUPluginObject::OpenCommandBuffer() { + if (status_ == kInitializationSuccessful) + return command_buffer_; + + // SetWindow must have been called before OpenCommandBuffer. + // PlatformSpecificSetWindow advances the status to + // kWaitingForOpenCommandBuffer. + if (status_ != kWaitingForOpenCommandBuffer) + return NPObjectPointer<NPObject>(); + + scoped_ptr<SharedMemory> ring_buffer(new SharedMemory); + if (!ring_buffer->Create(std::wstring(), false, false, kCommandBufferSize)) + return NPObjectPointer<NPObject>(); + + if (command_buffer_->Initialize(ring_buffer.release())) { + if (processor_->Initialize(static_cast<HWND>(window_.window))) { + command_buffer_->SetPutOffsetChangeCallback( + NewCallback(processor_.get(), + &GPUProcessor::ProcessCommands)); + status_ = kInitializationSuccessful; + return command_buffer_; + } + } + + return NPObjectPointer<CommandBuffer>(); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_object.h b/o3d/gpu_plugin/gpu_plugin_object.h new file mode 100644 index 0000000..63f44fb --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object.h @@ -0,0 +1,132 @@ +// 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_GPU_PLUGIN_OBJECT_H_ +#define O3D_GPU_PLUGIN_GPU_PLUGIN_OBJECT_H_ + +#include <string> + +#include "base/ref_counted.h" +#include "base/thread.h" +#include "o3d/gpu_plugin/command_buffer.h" +#include "o3d/gpu_plugin/gpu_processor.h" +#include "o3d/gpu_plugin/np_utils/default_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_dispatcher.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" +#include "o3d/gpu_plugin/np_utils/np_plugin_object.h" +#include "o3d/gpu_plugin/np_utils/np_utils.h" + +namespace gpu_plugin { + +// The scriptable object for the GPU plugin. +class GPUPluginObject : public DefaultNPObject<NPObject>, + public PluginObject { + public: + static const int32 kCommandBufferSize = 1024 * 1024; + + enum Status { + // In the state of waiting for the named function to be called to continue + // the initialization sequence. + kWaitingForNew, + kWaitingForSetWindow, + kWaitingForOpenCommandBuffer, + + // Initialization either succeeded or failed. + kInitializationSuccessful, + kInitializationFailed, + + // Destroy has now been called and the plugin object cannot be used. + kDestroyed, + }; + + static const NPUTF8 kPluginType[]; + + explicit GPUPluginObject(NPP npp); + + virtual NPError New(NPMIMEType plugin_type, + int16 argc, + char* argn[], + char* argv[], + NPSavedData* saved); + + virtual NPError SetWindow(NPWindow* new_window); + const NPWindow& GetWindow() { return window_; } + + virtual int16 HandleEvent(NPEvent* event); + + virtual NPError Destroy(NPSavedData** saved); + + virtual void Release(); + + virtual NPObject* GetScriptableNPObject(); + + // Returns the current initialization status. See Status enum. + int32 GetStatus() { + return status_; + } + + // Get the width of the plugin window. + int32 GetWidth() { + return window_.width; + } + + // Get the height of the plugin window. + int32 GetHeight() { + return window_.height; + } + + // Set the object that receives notifications of GPU plugin object events + // such as resize and keyboard and mouse input. + void SetEventSync(NPObjectPointer<NPObject> event_sync) { + event_sync_ = event_sync; + } + + NPObjectPointer<NPObject> GetEventSync() { + return event_sync_; + } + + // Initializes and returns the command buffer object. Returns NULL if the + // command buffer cannot be initialized, for example if the plugin does not + // yet have a window handle. + NPObjectPointer<NPObject> OpenCommandBuffer(); + + // Set the status for testing. + void set_status(Status status) { + status_ = status; + } + + // Replace the default command buffer for testing. + void set_command_buffer( + const NPObjectPointer<CommandBuffer>& command_buffer) { + command_buffer_ = command_buffer; + } + + // Replace the default GPU processor for testing. + void set_gpu_processor(const scoped_refptr<GPUProcessor>& processor) { + processor_ = processor; + } + + NP_UTILS_BEGIN_DISPATCHER_CHAIN(GPUPluginObject, DefaultNPObject<NPObject>) + NP_UTILS_DISPATCHER(GetStatus, int32()); + NP_UTILS_DISPATCHER(GetWidth, int32()); + NP_UTILS_DISPATCHER(GetHeight, int32()); + NP_UTILS_DISPATCHER(SetEventSync, void(NPObjectPointer<NPObject> sync)); + NP_UTILS_DISPATCHER(GetEventSync, NPObjectPointer<NPObject>()); + NP_UTILS_DISPATCHER(OpenCommandBuffer, NPObjectPointer<NPObject>()) + NP_UTILS_END_DISPATCHER_CHAIN + + private: + NPError PlatformSpecificSetWindow(NPWindow* new_window); + + NPP npp_; + Status status_; + NPWindow window_; + NPObjectPointer<CommandBuffer> command_buffer_; + scoped_refptr<GPUProcessor> processor_; + NPObjectPointer<NPObject> event_sync_; +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_GPU_PLUGIN_OBJECT_H_ diff --git a/o3d/gpu_plugin/gpu_plugin_object_factory.cc b/o3d/gpu_plugin/gpu_plugin_object_factory.cc new file mode 100644 index 0000000..7727f50 --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object_factory.cc @@ -0,0 +1,27 @@ +// 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/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_plugin_object_factory.h" +#include "o3d/gpu_plugin/np_utils/np_utils.h" + +namespace gpu_plugin { + +GPUPluginObjectFactory::GPUPluginObjectFactory() { +} + +GPUPluginObjectFactory::~GPUPluginObjectFactory() { +} + +PluginObject* GPUPluginObjectFactory::CreatePluginObject( + NPP npp, + NPMIMEType plugin_type) { + if (strcmp(plugin_type, GPUPluginObject::kPluginType) == 0) { + return NPCreateObject<GPUPluginObject>(npp).ToReturned(); + } + + return NULL; +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_object_factory.h b/o3d/gpu_plugin/gpu_plugin_object_factory.h new file mode 100644 index 0000000..d038297 --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object_factory.h @@ -0,0 +1,26 @@ +// 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_GPU_PLUGIN_OBJECT_FACTORY_H_ +#define O3D_GPU_PLUGIN_GPU_PLUGIN_OBJECT_FACTORY_H_ + +#include "o3d/gpu_plugin/np_utils/np_plugin_object_factory.h" + +namespace gpu_plugin { + +// Plugin object factory for creating the GPUPluginObject. +class GPUPluginObjectFactory : public NPPluginObjectFactory { + public: + GPUPluginObjectFactory(); + virtual ~GPUPluginObjectFactory(); + + virtual PluginObject* CreatePluginObject(NPP npp, NPMIMEType plugin_type); + + private: + DISALLOW_COPY_AND_ASSIGN(GPUPluginObjectFactory); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_GPU_PLUGIN_OBJECT_FACTORY_H_ diff --git a/o3d/gpu_plugin/gpu_plugin_object_factory_unittest.cc b/o3d/gpu_plugin/gpu_plugin_object_factory_unittest.cc new file mode 100644 index 0000000..8a3413d --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object_factory_unittest.cc @@ -0,0 +1,39 @@ +// 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/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_plugin_object_factory.h" +#include "o3d/gpu_plugin/np_utils/np_browser_stub.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu_plugin { + +class PluginObjectFactoryTest : public testing::Test { + protected: + virtual void SetUp() { + factory_ = new GPUPluginObjectFactory; + } + + virtual void TearDown() { + delete factory_; + } + + StubNPBrowser stub_browser_; + GPUPluginObjectFactory* factory_; +}; + +TEST_F(PluginObjectFactoryTest, ReturnsNullForUnknownMimeType) { + PluginObject* plugin_object = factory_->CreatePluginObject( + NULL, "application/unknown"); + EXPECT_TRUE(NULL == plugin_object); +} + +TEST_F(PluginObjectFactoryTest, CreatesGPUPlugin) { + PluginObject* plugin_object = factory_->CreatePluginObject( + NULL, const_cast<NPMIMEType>(GPUPluginObject::kPluginType)); + EXPECT_TRUE(NULL != plugin_object); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_object_unittest.cc b/o3d/gpu_plugin/gpu_plugin_object_unittest.cc new file mode 100644 index 0000000..8bc7bfb --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object_unittest.cc @@ -0,0 +1,346 @@ +// 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/command_buffer_mock.h" +#include "o3d/gpu_plugin/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_processor_mock.h" +#include "o3d/gpu_plugin/np_utils/np_browser_mock.h" +#include "o3d/gpu_plugin/np_utils/dynamic_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_object_mock.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +#if defined(O3D_IN_CHROME) +#include "webkit/glue/plugins/nphostapi.h" +#else +#include "o3d/third_party/npapi/include/npfunctions.h" +#endif + +using ::base::SharedMemory; + +using testing::_; +using testing::DoAll; +using testing::Invoke; +using testing::NotNull; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +namespace gpu_plugin { + +class MockSystemNPObject : public DefaultNPObject<NPObject> { + public: + explicit MockSystemNPObject(NPP npp) { + } + + MOCK_METHOD1(CreateSharedMemory, NPObjectPointer<NPObject>(int32 size)); + + NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockSystemNPObject, DefaultNPObject<NPObject>) + NP_UTILS_DISPATCHER(CreateSharedMemory, + NPObjectPointer<NPObject>(int32 size)) + NP_UTILS_END_DISPATCHER_CHAIN + + private: + DISALLOW_COPY_AND_ASSIGN(MockSystemNPObject); +}; + +class GPUPluginObjectTest : public testing::Test { + protected: + virtual void SetUp() { + plugin_object_ = NPCreateObject<GPUPluginObject>(NULL); + + command_buffer_ = NPCreateObject<MockCommandBuffer>(NULL); + plugin_object_->set_command_buffer(command_buffer_); + + processor_ = new MockGPUProcessor(NULL, command_buffer_.Get()); + plugin_object_->set_gpu_processor(processor_.get()); + + window_object_ = NPCreateObject<DynamicNPObject>(NULL); + ON_CALL(mock_browser_, GetWindowNPObject(NULL)) + .WillByDefault(Return(window_object_.ToReturned())); + + chromium_object_ = NPCreateObject<DynamicNPObject>(NULL); + NPSetProperty(NULL, window_object_, "chromium", chromium_object_); + + system_object_ = NPCreateObject<StrictMock<MockSystemNPObject> >(NULL); + NPSetProperty(NULL, chromium_object_, "system", system_object_); + } + + MockNPBrowser mock_browser_; + NPObjectPointer<GPUPluginObject> plugin_object_; + NPObjectPointer<MockCommandBuffer> command_buffer_; + scoped_refptr<MockGPUProcessor> processor_; + NPObjectPointer<DynamicNPObject> window_object_; + NPObjectPointer<DynamicNPObject> chromium_object_; + NPObjectPointer<MockSystemNPObject> system_object_; +}; + +namespace { +template <typename T> +void DeleteObject(T* object) { + delete object; +} +} // namespace anonymous + + +TEST_F(GPUPluginObjectTest, CanInstantiateAndDestroyPluginObject) { + EXPECT_EQ(GPUPluginObject::kWaitingForNew, plugin_object_->GetStatus()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + EXPECT_EQ(GPUPluginObject::kWaitingForSetWindow, plugin_object_->GetStatus()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); + + EXPECT_EQ(GPUPluginObject::kDestroyed, plugin_object_->GetStatus()); +} + +TEST_F(GPUPluginObjectTest, DestroyFailsIfNotInitialized) { + EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->Destroy(NULL)); +} + +TEST_F(GPUPluginObjectTest, NewFailsIfAlreadyInitialized) { + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + EXPECT_EQ(GPUPluginObject::kWaitingForSetWindow, plugin_object_->GetStatus()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); + + EXPECT_EQ(GPUPluginObject::kDestroyed, plugin_object_->GetStatus()); +} + +TEST_F(GPUPluginObjectTest, NewFailsIfObjectHasPreviouslyBeenDestroyed) { + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); + + EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + EXPECT_EQ(GPUPluginObject::kDestroyed, plugin_object_->GetStatus()); +} + +TEST_F(GPUPluginObjectTest, WindowIsNullBeforeSetWindowCalled) { + NPWindow window = plugin_object_->GetWindow(); + EXPECT_EQ(NULL, window.window); +} + +TEST_F(GPUPluginObjectTest, CanSetWindow) { + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + NPWindow window = {0}; + window.window = &window; + window.x = 7; + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->SetWindow(&window)); + EXPECT_EQ(0, memcmp(&window, &plugin_object_->GetWindow(), sizeof(window))); + EXPECT_EQ(GPUPluginObject::kWaitingForOpenCommandBuffer, + plugin_object_->GetStatus()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); +} + +TEST_F(GPUPluginObjectTest, CanGetWindowSize) { + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + NPWindow window = {0}; + window.window = &window; + window.x = 10; + window.y = 10; + window.width = 100; + window.height = 200; + + EXPECT_EQ(0, plugin_object_->GetWidth()); + EXPECT_EQ(0, plugin_object_->GetHeight()); + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->SetWindow(&window)); + EXPECT_EQ(100, plugin_object_->GetWidth()); + EXPECT_EQ(200, plugin_object_->GetHeight()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); +} + +TEST_F(GPUPluginObjectTest, SetWindowFailsIfNotInitialized) { + NPWindow window = {0}; + EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->SetWindow(&window)); + EXPECT_EQ(GPUPluginObject::kWaitingForNew, plugin_object_->GetStatus()); +} + +TEST_F(GPUPluginObjectTest, CanGetScriptableNPObject) { + NPObject* scriptable_object = plugin_object_->GetScriptableNPObject(); + EXPECT_EQ(plugin_object_.Get(), scriptable_object); + NPBrowser::get()->ReleaseObject(scriptable_object); +} + +TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsInitializedCommandBuffer) { + EXPECT_CALL(*command_buffer_.Get(), Initialize(NotNull())) + .WillOnce(DoAll(Invoke(DeleteObject<SharedMemory>), + Return(true))); + + EXPECT_CALL(*processor_.get(), Initialize(NULL)) + .WillOnce(Return(true)); + + EXPECT_CALL(*command_buffer_.Get(), SetPutOffsetChangeCallback(NotNull())) + .WillOnce(Invoke(DeleteObject<Callback0::Type>)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + // Set status as though SetWindow has been called. Avoids having to create a + // valid window handle to pass to SetWindow in tests. + plugin_object_->set_status(GPUPluginObject::kWaitingForOpenCommandBuffer); + + EXPECT_EQ(command_buffer_, plugin_object_->OpenCommandBuffer()); + + // Calling OpenCommandBuffer again just returns the existing command buffer. + EXPECT_EQ(command_buffer_, plugin_object_->OpenCommandBuffer()); + + EXPECT_EQ(GPUPluginObject::kInitializationSuccessful, + plugin_object_->GetStatus()); + + EXPECT_CALL(*command_buffer_.Get(), SetPutOffsetChangeCallback(NULL)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); +} + +TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsNullIfWindowNotReady) { + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + // Set status as though SetWindow has not been called. + plugin_object_->set_status(GPUPluginObject::kWaitingForSetWindow); + + EXPECT_EQ(NPObjectPointer<NPObject>(), plugin_object_->OpenCommandBuffer()); + + EXPECT_EQ(GPUPluginObject::kWaitingForSetWindow, plugin_object_->GetStatus()); +} + + +TEST_F(GPUPluginObjectTest, + OpenCommandBufferReturnsNullIfCommandBufferCannotInitialize) { + EXPECT_CALL(*command_buffer_.Get(), Initialize(NotNull())) + .WillOnce(DoAll(Invoke(DeleteObject<SharedMemory>), + Return(false))); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + // Set status as though SetWindow has been called. Avoids having to create a + // valid window handle to pass to SetWindow in tests. + plugin_object_->set_status(GPUPluginObject::kWaitingForOpenCommandBuffer); + + EXPECT_EQ(NPObjectPointer<NPObject>(), plugin_object_->OpenCommandBuffer()); + + EXPECT_EQ(GPUPluginObject::kWaitingForOpenCommandBuffer, + plugin_object_->GetStatus()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); +} + +TEST_F(GPUPluginObjectTest, + OpenCommandBufferReturnsNullIGPUProcessorCannotInitialize) { + EXPECT_CALL(*command_buffer_.Get(), Initialize(NotNull())) + .WillOnce(DoAll(Invoke(DeleteObject<SharedMemory>), + Return(true))); + + EXPECT_CALL(*processor_.get(), Initialize(NULL)) + .WillOnce(Return(false)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + // Set status as though SetWindow has been called. Avoids having to create a + // valid window handle to pass to SetWindow in tests. + plugin_object_->set_status(GPUPluginObject::kWaitingForOpenCommandBuffer); + + EXPECT_EQ(NPObjectPointer<NPObject>(), plugin_object_->OpenCommandBuffer()); + + EXPECT_EQ(GPUPluginObject::kWaitingForOpenCommandBuffer, + plugin_object_->GetStatus()); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); +} + +class MockEventSync : public DefaultNPObject<NPObject> { + public: + explicit MockEventSync(NPP npp) { + } + + MOCK_METHOD2(Resize, void(int32 width, int32 height)); + + NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockEventSync, DefaultNPObject<NPObject>) + NP_UTILS_DISPATCHER(Resize, void(int32 width, int32 height)) + NP_UTILS_END_DISPATCHER_CHAIN + + private: + DISALLOW_COPY_AND_ASSIGN(MockEventSync); +}; + +TEST_F(GPUPluginObjectTest, SendsResizeEventOnSetWindow) { + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", + 0, + NULL, + NULL, + NULL)); + + NPObjectPointer<MockEventSync> event_sync = + NPCreateObject<MockEventSync>(NULL); + plugin_object_->SetEventSync(event_sync); + + EXPECT_CALL(*event_sync.Get(), Resize(100, 200)); + + NPWindow window = {0}; + window.window = &window; + window.x = 10; + window.y = 10; + window.width = 100; + window.height = 200; + + plugin_object_->SetWindow(&window); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_object_win.cc b/o3d/gpu_plugin/gpu_plugin_object_win.cc new file mode 100644 index 0000000..5ff5cf5 --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_object_win.cc @@ -0,0 +1,62 @@ +// 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 <windows.h> + +#include "o3d/gpu_plugin/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_processor.h" + +namespace gpu_plugin { + +namespace { +const LPCTSTR kPluginObjectProperty = TEXT("GPUPluginObject"); +const LPCTSTR kOriginalWindowProc = TEXT("GPUPluginObjectOriginalWindowProc"); + +LRESULT CALLBACK WindowProc(HWND handle, + UINT message, + WPARAM w_param, + LPARAM l_param) { + return ::DefWindowProc(handle, message, w_param, l_param); +} +} // namespace anonymous + +NPError GPUPluginObject::PlatformSpecificSetWindow(NPWindow* new_window) { + // Detach properties from old window and restore the original window proc. + if (window_.window) { + HWND handle = reinterpret_cast<HWND>(window_.window); + ::RemoveProp(handle, kPluginObjectProperty); + + LONG original_window_proc = reinterpret_cast<LONG>( + ::GetProp(handle, kOriginalWindowProc)); + ::SetWindowLong(handle, GWL_WNDPROC, + original_window_proc); + ::RemoveProp(handle, kOriginalWindowProc); + } + + // Attach properties to new window and set a new window proc. + if (new_window->window) { + HWND handle = reinterpret_cast<HWND>(new_window->window); + ::SetProp(handle, + kPluginObjectProperty, + reinterpret_cast<HANDLE>(this)); + + LONG original_window_proc = ::GetWindowLong(handle, GWL_WNDPROC); + ::SetProp(handle, + kOriginalWindowProc, + reinterpret_cast<HANDLE>(original_window_proc)); + ::SetWindowLong(handle, GWL_WNDPROC, + reinterpret_cast<LONG>(WindowProc)); + + status_ = kWaitingForOpenCommandBuffer; + } else { + status_ = kWaitingForSetWindow; + if (processor_) { + processor_->Destroy(); + } + } + + return NPERR_NO_ERROR; +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_unittest.cc b/o3d/gpu_plugin/gpu_plugin_unittest.cc new file mode 100644 index 0000000..0bc53fd --- /dev/null +++ b/o3d/gpu_plugin/gpu_plugin_unittest.cc @@ -0,0 +1,305 @@ +// 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/gpu_plugin.h" +#include "o3d/gpu_plugin/gpu_plugin_object.h" +#include "o3d/gpu_plugin/np_utils/np_object_mock.h" +#include "o3d/gpu_plugin/np_utils/np_plugin_object_factory_mock.h" +#include "o3d/gpu_plugin/np_utils/np_plugin_object_mock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(O3D_IN_CHROME) +#include "webkit/glue/plugins/nphostapi.h" +#else +#include "o3d/third_party/npapi/include/npfunctions.h" +#endif + +#if defined(OS_LINUX) +#define INITIALIZE_PLUGIN_FUNCS , &plugin_funcs_ +#else +#define INITIALIZE_PLUGIN_FUNCS +#endif + +using testing::_; +using testing::DoAll; +using testing::NiceMock; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +namespace gpu_plugin { + +class GPUPluginTest : public testing::Test { + protected: + virtual void SetUp() { + memset(&npp_, 0, sizeof(npp_)); + memset(&browser_funcs_, 0, sizeof(browser_funcs_)); + memset(&plugin_funcs_, 0, sizeof(plugin_funcs_)); + + plugin_object_factory_ = new StrictMock<MockPluginObjectFactory>; + + np_class_ = NPGetClass<StrictMock<MockNPObject> >(); + } + + virtual void TearDown() { + delete plugin_object_factory_; + } + + NPP_t npp_; + NPNetscapeFuncs browser_funcs_; + NPPluginFuncs plugin_funcs_; + MockPluginObjectFactory* plugin_object_factory_; + const NPClass* np_class_; +}; + +TEST_F(GPUPluginTest, GetEntryPointsSetsNeededFunctionPointers) { +#if defined(OS_LINUX) + NPError error = gpu_plugin::NP_Initialize(&browser_funcs_, + &plugin_funcs_); + gpu_plugin::NP_Shutdown(); +#else + NPError error = gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); +#endif + + EXPECT_EQ(NPERR_NO_ERROR, error); + EXPECT_TRUE(NULL != plugin_funcs_.newp); + EXPECT_TRUE(NULL != plugin_funcs_.destroy); + EXPECT_TRUE(NULL != plugin_funcs_.setwindow); + EXPECT_TRUE(NULL != plugin_funcs_.event); + EXPECT_TRUE(NULL != plugin_funcs_.getvalue); + EXPECT_TRUE(NULL != plugin_funcs_.setvalue); +} + +TEST_F(GPUPluginTest, CanInitializeAndShutdownPlugin) { + EXPECT_EQ(NPERR_NO_ERROR, + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS)); + EXPECT_EQ(NPERR_NO_ERROR, gpu_plugin::NP_Shutdown()); +} + +TEST_F(GPUPluginTest, InitializeFailsIfBrowserFuncsIsNull) { + EXPECT_EQ(NPERR_INVALID_FUNCTABLE_ERROR, + gpu_plugin::NP_Initialize(NULL INITIALIZE_PLUGIN_FUNCS)); +} + +TEST_F(GPUPluginTest, InitializeFailsIfAlreadyInitialized) { + EXPECT_EQ(NPERR_NO_ERROR, + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS)); + EXPECT_EQ(NPERR_GENERIC_ERROR, + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS)); + EXPECT_EQ(NPERR_NO_ERROR, gpu_plugin::NP_Shutdown()); +} + +TEST_F(GPUPluginTest, ShutdownFailsIfNotInitialized) { + EXPECT_EQ(NPERR_GENERIC_ERROR, gpu_plugin::NP_Shutdown()); +} + +TEST_F(GPUPluginTest, NewReturnsErrorForInvalidInstance) { + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.newp( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + NULL, 0, 0, NULL, NULL, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, GetValueReturnsErrorForInvalidInstance) { + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + int* result = NULL; + EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.getvalue( + NULL, NPPVjavaClass, &result)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, DestroyReturnsErrorForInvalidInstance) { + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.destroy(NULL, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, SetWindowReturnsErrorForInvalidInstance) { + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.setwindow(NULL, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, HandleEventReturnsFalseForInvalidInstance) { + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(0, plugin_funcs_.event(NULL, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, NewCreatesAPluginObjectAndInitializesIt) { + StrictMock<MockPluginObject> plugin_object; + + EXPECT_CALL(*plugin_object_factory_, CreatePluginObject( + &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType))) + .WillOnce(Return(&plugin_object)); + + NPObject scriptable_object; + + EXPECT_CALL(plugin_object, New( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + 0, NULL, NULL, NULL)) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, GetScriptableNPObject()) + .WillOnce(Return(&scriptable_object)); + + EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL))) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, Release()); + + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + &npp_, 0, 0, NULL, NULL, NULL)); + + NPObject* result; + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.getvalue( + &npp_, NPPVpluginScriptableNPObject, &result)); + EXPECT_EQ(&scriptable_object, result); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, NewFailsIfPluginObjectFactoryFails) { + EXPECT_CALL(*plugin_object_factory_, CreatePluginObject( + &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType))) + .WillOnce(Return(static_cast<PluginObject*>(NULL))); + + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_funcs_.newp( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + &npp_, 0, 0, NULL, NULL, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, SetWindowForwardsToPluginObject) { + StrictMock<MockPluginObject> plugin_object; + + EXPECT_CALL(*plugin_object_factory_, CreatePluginObject( + &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType))) + .WillOnce(Return(&plugin_object)); + + EXPECT_CALL(plugin_object, New( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + 0, NULL, NULL, NULL)) + .WillOnce(Return(NPERR_NO_ERROR)); + + NPWindow window = {0}; + + EXPECT_CALL(plugin_object, SetWindow(&window)) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL))) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, Release()); + + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + &npp_, 0, 0, NULL, NULL, NULL)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.setwindow(&npp_, &window)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, HandleEventForwardsToPluginObject) { + StrictMock<MockPluginObject> plugin_object; + + EXPECT_CALL(*plugin_object_factory_, CreatePluginObject( + &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType))) + .WillOnce(Return(&plugin_object)); + + EXPECT_CALL(plugin_object, New( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + 0, NULL, NULL, NULL)) + .WillOnce(Return(NPERR_NO_ERROR)); + + NPEvent event = {0}; + + EXPECT_CALL(plugin_object, HandleEvent(&event)) + .WillOnce(Return(7)); + + EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL))) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, Release()); + + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + &npp_, 0, 0, NULL, NULL, NULL)); + + EXPECT_EQ(7, plugin_funcs_.event(&npp_, &event)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +TEST_F(GPUPluginTest, GetValueReturnsErrorForUnknownVariable) { + StrictMock<MockPluginObject> plugin_object; + + EXPECT_CALL(*plugin_object_factory_, CreatePluginObject( + &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType))) + .WillOnce(Return(&plugin_object)); + + EXPECT_CALL(plugin_object, New( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + 0, NULL, NULL, NULL)) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL))) + .WillOnce(Return(NPERR_NO_ERROR)); + + EXPECT_CALL(plugin_object, Release()); + + gpu_plugin::NP_GetEntryPoints(&plugin_funcs_); + gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp( + const_cast<NPMIMEType>(GPUPluginObject::kPluginType), + &npp_, 0, 0, NULL, NULL, NULL)); + + int* result = NULL; + EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_funcs_.getvalue( + &npp_, NPPVjavaClass, &result)); + + EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL)); + + gpu_plugin::NP_Shutdown(); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_processor.cc b/o3d/gpu_plugin/gpu_processor.cc new file mode 100644 index 0000000..f554fb5 --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor.cc @@ -0,0 +1,80 @@ +// 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/gpu_processor.h" + +using ::base::SharedMemory; + +namespace gpu_plugin { + +GPUProcessor::~GPUProcessor() { +} + +namespace { +void InvokeProcessCommands(void* data) { + static_cast<GPUProcessor*>(data)->ProcessCommands(); +} +} // namespace anonymous + +void GPUProcessor::ProcessCommands() { + if (command_buffer_->GetErrorStatus()) + return; + + parser_->set_put(command_buffer_->GetPutOffset()); + + int commands_processed = 0; + while (commands_processed < commands_per_update_ && !parser_->IsEmpty()) { + command_buffer::parse_error::ParseError parse_error = + parser_->ProcessCommand(); + switch (parse_error) { + case command_buffer::parse_error::kParseUnknownCommand: + case command_buffer::parse_error::kParseInvalidArguments: + command_buffer_->SetParseError(parse_error); + break; + + case command_buffer::parse_error::kParseInvalidSize: + case command_buffer::parse_error::kParseOutOfBounds: + command_buffer_->SetParseError(parse_error); + command_buffer_->RaiseErrorStatus(); + return; + } + + ++commands_processed; + } + + command_buffer_->SetGetOffset(static_cast<int32>(parser_->get())); + + if (!parser_->IsEmpty()) { + NPBrowser::get()->PluginThreadAsyncCall(npp_, InvokeProcessCommands, this); + } +} + +void *GPUProcessor::GetSharedMemoryAddress(int32 shm_id) { + SharedMemory* shared_memory = command_buffer_->GetTransferBuffer(shm_id); + if (!shared_memory) + return NULL; + + if (!shared_memory->memory()) { + if (!shared_memory->Map(shared_memory->max_size())) + return NULL; + } + + return shared_memory->memory(); +} + +// TODO(apatrick): Consolidate this with the above and return both the address +// and size. +size_t GPUProcessor::GetSharedMemorySize(int32 shm_id) { + SharedMemory* shared_memory = command_buffer_->GetTransferBuffer(shm_id); + if (!shared_memory) + return 0; + + return shared_memory->max_size(); +} + +void GPUProcessor::set_token(int32 token) { + command_buffer_->SetToken(token); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_processor.h b/o3d/gpu_plugin/gpu_processor.h new file mode 100644 index 0000000..49c6eea --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor.h @@ -0,0 +1,119 @@ +// 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_GPU_PROCESSOR_H_ +#define O3D_GPU_PLUGIN_GPU_PROCESSOR_H_ + +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/shared_memory.h" +#include "o3d/command_buffer/service/cmd_buffer_engine.h" +#include "o3d/command_buffer/service/cmd_parser.h" +#include "o3d/command_buffer/service/gapi_decoder.h" +#include "o3d/gpu_plugin/command_buffer.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" + +#if defined(CB_SERVICE_D3D9) +#include "o3d/command_buffer/service/gapi_d3d9.h" +#elif defined(CB_SERVICE_GL) +#include "o3d/command_buffer/service/gapi_gl.h" +#else +#error command buffer service not defined +#endif + +namespace gpu_plugin { + +// This class processes commands in a command buffer. It is event driven and +// posts tasks to the current message loop to do additional work. +class GPUProcessor : public ::base::RefCounted<GPUProcessor>, + public command_buffer::CommandBufferEngine { + public: +#if defined(CB_SERVICE_D3D9) + typedef command_buffer::o3d::GAPID3D9 GPUGAPIInterface; +#elif defined(CB_SERVICE_GL) + typedef command_buffer::o3d::GAPIGL GPUGAPIInterface; +#else +#error command buffer service not defined +#endif + + GPUProcessor(NPP npp, + CommandBuffer* command_buffer); + + // This constructor is for unit tests. + GPUProcessor(NPP npp, + CommandBuffer* command_buffer, + GPUGAPIInterface* gapi, + command_buffer::o3d::GAPIDecoder* decoder, + command_buffer::CommandParser* parser, + int commands_per_update); + + virtual bool Initialize(HWND hwnd); + + virtual ~GPUProcessor(); + + virtual void Destroy(); + + virtual void ProcessCommands(); + +#if defined(OS_WIN) + virtual bool SetWindow(HWND handle, int width, int height); +#endif + + // Implementation of CommandBufferEngine. + + // Gets the base address of a registered shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + virtual void *GetSharedMemoryAddress(int32 shm_id); + + // Gets the size of a registered shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + virtual size_t GetSharedMemorySize(int32 shm_id); + + // Sets the token value. + virtual void set_token(int32 token); + + private: + NPP npp_; + + // The GPUProcessor holds a weak reference to the CommandBuffer. The + // CommandBuffer owns the GPUProcessor and holds a strong reference to it + // through the ProcessCommands callback. + CommandBuffer* command_buffer_; + + scoped_ptr< ::base::SharedMemory> mapped_ring_buffer_; + int commands_per_update_; + + scoped_ptr<GPUGAPIInterface> gapi_; + scoped_ptr<command_buffer::o3d::GAPIDecoder> decoder_; + scoped_ptr<command_buffer::CommandParser> parser_; +}; + +} // namespace gpu_plugin + +// Callbacks to the GPUProcessor hold a reference count. +template <typename Method> +class CallbackStorage<gpu_plugin::GPUProcessor, Method> { + public: + CallbackStorage(gpu_plugin::GPUProcessor* obj, Method method) + : obj_(obj), + meth_(method) { + DCHECK(obj_); + obj_->AddRef(); + } + + ~CallbackStorage() { + obj_->Release(); + } + + protected: + gpu_plugin::GPUProcessor* obj_; + Method meth_; + + private: + DISALLOW_COPY_AND_ASSIGN(CallbackStorage); +}; + +#endif // O3D_GPU_PLUGIN_GPU_PROCESSOR_H_ diff --git a/o3d/gpu_plugin/gpu_processor_mock.h b/o3d/gpu_plugin/gpu_processor_mock.h new file mode 100644 index 0000000..d98f5af --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor_mock.h @@ -0,0 +1,41 @@ +// 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_GPU_PROCESSOR_MOCK_H_ +#define O3D_GPU_PLUGIN_GPU_PROCESSOR_MOCK_H_ + +#include "o3d/gpu_plugin/gpu_processor.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace gpu_plugin { + +class MockGPUProcessor : public GPUProcessor { + public: + MockGPUProcessor(NPP npp, + CommandBuffer* command_buffer) + : GPUProcessor(npp, command_buffer) { + } + +#if defined(OS_WIN) + MOCK_METHOD1(Initialize, bool(HWND handle)); +#endif + + MOCK_METHOD0(Destroy, void()); + MOCK_METHOD0(ProcessCommands, void()); + +#if defined(OS_WIN) + MOCK_METHOD3(SetWindow, bool(HWND handle, int width, int height)); +#endif + + MOCK_METHOD1(GetSharedMemoryAddress, void*(int32 shm_id)); + MOCK_METHOD1(GetSharedMemorySize, size_t(int32 shm_id)); + MOCK_METHOD1(set_token, void(int32 token)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockGPUProcessor); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_GPU_PROCESSOR_MOCK_H_ diff --git a/o3d/gpu_plugin/gpu_processor_unittest.cc b/o3d/gpu_plugin/gpu_processor_unittest.cc new file mode 100644 index 0000000..74c593c --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor_unittest.cc @@ -0,0 +1,309 @@ +// 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 "base/at_exit.h" +#include "base/message_loop.h" +#include "o3d/command_buffer/service/mocks.h" +#include "o3d/gpu_plugin/command_buffer_mock.h" +#include "o3d/gpu_plugin/gpu_processor.h" +#include "o3d/gpu_plugin/np_utils/np_browser_mock.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +using ::base::SharedMemory; + +using testing::_; +using testing::DoAll; +using testing::Invoke; +using testing::NiceMock; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +namespace gpu_plugin { + +const size_t kRingBufferSize = 1024; +const size_t kRingBufferEntries = kRingBufferSize / sizeof(int32); + +class GPUProcessorTest : public testing::Test { + protected: + virtual void SetUp() { + shared_memory_.reset(new SharedMemory); + shared_memory_->Create(std::wstring(), false, false, kRingBufferSize); + shared_memory_->Map(kRingBufferSize); + buffer_ = static_cast<int32*>(shared_memory_->memory()); + + memset(buffer_, 0, kRingBufferSize); + + // Don't mock PluginThreadAsyncCall. Have it schedule the task. + ON_CALL(mock_browser_, PluginThreadAsyncCall(_, _, _)) + .WillByDefault(Invoke(&mock_browser_, + &MockNPBrowser::ConcretePluginThreadAsyncCall)); + + command_buffer_ = NPCreateObject<MockCommandBuffer>(NULL); + ON_CALL(*command_buffer_.Get(), GetRingBuffer()) + .WillByDefault(Return(shared_memory_.get())); + ON_CALL(*command_buffer_.Get(), GetSize()) + .WillByDefault(Return(kRingBufferEntries)); + +#if defined(OS_WIN) + gapi_ = new GPUProcessor::GPUGAPIInterface; +#endif + + async_api_.reset(new StrictMock<command_buffer::AsyncAPIMock>); + + decoder_ = new command_buffer::o3d::GAPIDecoder(gapi_); + + parser_ = new command_buffer::CommandParser(buffer_, + kRingBufferEntries, + 0, + kRingBufferEntries, + 0, + async_api_.get()); + + processor_ = new GPUProcessor(NULL, + command_buffer_.Get(), + gapi_, + decoder_, + parser_, + 2); + } + + virtual void TearDown() { + // Ensure that any unexpected tasks posted by the GPU processor are executed + // in order to fail the test. + MessageLoop::current()->RunAllPending(); + } + + base::AtExitManager at_exit_manager; + MessageLoop message_loop; + MockNPBrowser mock_browser_; + NPObjectPointer<MockCommandBuffer> command_buffer_; + scoped_ptr<SharedMemory> shared_memory_; + int32* buffer_; + command_buffer::o3d::GAPIDecoder* decoder_; + command_buffer::CommandParser* parser_; + scoped_ptr<command_buffer::AsyncAPIMock> async_api_; + scoped_refptr<GPUProcessor> processor_; + +#if defined(OS_WIN) + GPUProcessor::GPUGAPIInterface* gapi_; +#endif +}; + +TEST_F(GPUProcessorTest, ProcessorDoesNothingIfRingBufferIsEmpty) { + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, SetGetOffset(0)); + + processor_->ProcessCommands(); + + EXPECT_EQ(command_buffer::parse_error::kParseNoError, + command_buffer_->ResetParseError()); + EXPECT_FALSE(command_buffer_->GetErrorStatus()); +} + +TEST_F(GPUProcessorTest, ProcessesOneCommand) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 2; + buffer_[1] = 123; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(2)); + EXPECT_CALL(*command_buffer_, SetGetOffset(2)); + + EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + processor_->ProcessCommands(); + + EXPECT_EQ(command_buffer::parse_error::kParseNoError, + command_buffer_->ResetParseError()); + EXPECT_FALSE(command_buffer_->GetErrorStatus()); +} + +TEST_F(GPUProcessorTest, ProcessesTwoCommands) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 2; + buffer_[1] = 123; + header[2].command = 8; + header[2].size = 1; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(3)); + EXPECT_CALL(*command_buffer_, SetGetOffset(3)); + + EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, PostsTaskToFinishRemainingCommands) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 2; + buffer_[1] = 123; + header[2].command = 8; + header[2].size = 1; + header[3].command = 9; + header[3].size = 1; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(4)); + + EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + EXPECT_CALL(*command_buffer_, SetGetOffset(3)); + + processor_->ProcessCommands(); + + // ProcessCommands is called a second time when the pending task is run. + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(4)); + + EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + EXPECT_CALL(*command_buffer_, SetGetOffset(4)); + + MessageLoop::current()->RunAllPending(); +} + +TEST_F(GPUProcessorTest, SetsErrorCodeOnCommandBuffer) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 1; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(1)); + EXPECT_CALL(*command_buffer_, SetGetOffset(1)); + + EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0])) + .WillOnce(Return( + command_buffer::parse_error::kParseUnknownCommand)); + + processor_->ProcessCommands(); + + EXPECT_EQ(command_buffer::parse_error::kParseUnknownCommand, + command_buffer_->ResetParseError()); + EXPECT_FALSE(command_buffer_->GetErrorStatus()); +} + +TEST_F(GPUProcessorTest, + RecoverableParseErrorsAreNotClearedByFollowingSuccessfulCommands) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 1; + header[1].command = 8; + header[1].size = 1; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(2)); + EXPECT_CALL(*command_buffer_, SetGetOffset(2)); + + EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0])) + .WillOnce(Return( + command_buffer::parse_error::kParseUnknownCommand)); + + EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[1])) + .WillOnce(Return(command_buffer::parse_error::kParseNoError)); + + processor_->ProcessCommands(); + + EXPECT_EQ(command_buffer::parse_error::kParseUnknownCommand, + command_buffer_->ResetParseError()); + EXPECT_FALSE(command_buffer_->GetErrorStatus()); +} + +TEST_F(GPUProcessorTest, UnrecoverableParseErrorsRaiseTheErrorStatus) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 1; + header[1].command = 8; + header[1].size = 1; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(2)); + + EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0])) + .WillOnce(Return(command_buffer::parse_error::kParseInvalidSize)); + + processor_->ProcessCommands(); + + EXPECT_EQ(command_buffer::parse_error::kParseInvalidSize, + command_buffer_->ResetParseError()); + EXPECT_TRUE(command_buffer_->GetErrorStatus()); +} + +TEST_F(GPUProcessorTest, ProcessCommandsDoesNothingAfterUnrecoverableError) { + command_buffer::CommandHeader* header = + reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]); + header[0].command = 7; + header[0].size = 1; + header[1].command = 8; + header[1].size = 1; + + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(2)); + + EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0])) + .WillOnce(Return(command_buffer::parse_error::kParseInvalidSize)); + + processor_->ProcessCommands(); + processor_->ProcessCommands(); + + EXPECT_EQ(command_buffer::parse_error::kParseInvalidSize, + command_buffer_->ResetParseError()); + EXPECT_TRUE(command_buffer_->GetErrorStatus()); +} + +TEST_F(GPUProcessorTest, CanGetAddressOfSharedMemory) { + EXPECT_CALL(*command_buffer_.Get(), GetTransferBuffer(7)) + .WillOnce(Return(shared_memory_.get())); + + EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryAddress(7)); +} + +ACTION_P2(SetPointee, address, value) { + *address = value; +} + +TEST_F(GPUProcessorTest, GetAddressOfSharedMemoryMapsMemoryIfUnmapped) { + EXPECT_CALL(*command_buffer_.Get(), GetTransferBuffer(7)) + .WillOnce(Return(shared_memory_.get())); + + EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryAddress(7)); +} + +TEST_F(GPUProcessorTest, CanGetSizeOfSharedMemory) { + EXPECT_CALL(*command_buffer_.Get(), GetTransferBuffer(7)) + .WillOnce(Return(shared_memory_.get())); + + EXPECT_EQ(kRingBufferSize, processor_->GetSharedMemorySize(7)); +} + +TEST_F(GPUProcessorTest, SetTokenForwardsToCommandBuffer) { + processor_->set_token(7); + EXPECT_EQ(7, command_buffer_->GetToken()); +} + +} // namespace gpu_plugin
\ No newline at end of file diff --git a/o3d/gpu_plugin/gpu_processor_win.cc b/o3d/gpu_plugin/gpu_processor_win.cc new file mode 100644 index 0000000..21a1c4a --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor_win.cc @@ -0,0 +1,85 @@ +// 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 <windows.h> + +#include "o3d/gpu_plugin/gpu_processor.h" + +using ::base::SharedMemory; + +namespace gpu_plugin { + +GPUProcessor::GPUProcessor(NPP npp, + CommandBuffer* command_buffer) + : npp_(npp), + command_buffer_(command_buffer), + commands_per_update_(100) { + DCHECK(command_buffer); + gapi_.reset(new GPUGAPIInterface); + decoder_.reset(new command_buffer::o3d::GAPIDecoder(gapi_.get())); + decoder_->set_engine(this); +} + +GPUProcessor::GPUProcessor(NPP npp, + CommandBuffer* command_buffer, + GPUGAPIInterface* gapi, + command_buffer::o3d::GAPIDecoder* decoder, + command_buffer::CommandParser* parser, + int commands_per_update) + : npp_(npp), + command_buffer_(command_buffer), + commands_per_update_(commands_per_update) { + DCHECK(command_buffer); + gapi_.reset(gapi); + decoder_.reset(decoder); + parser_.reset(parser); +} + +bool GPUProcessor::Initialize(HWND handle) { + DCHECK(handle); + + // Cannot reinitialize. + if (gapi_->hwnd() != NULL) + return false; + + // Map the ring buffer and create the parser. + SharedMemory* ring_buffer = command_buffer_->GetRingBuffer(); + if (ring_buffer) { + size_t size = ring_buffer->max_size(); + if (!ring_buffer->Map(size)) { + return false; + } + + void* ptr = ring_buffer->memory(); + parser_.reset(new command_buffer::CommandParser(ptr, size, 0, size, 0, + decoder_.get())); + } else { + parser_.reset(new command_buffer::CommandParser(NULL, 0, 0, 0, 0, + decoder_.get())); + } + + // Initialize GAPI immediately if the window handle is valid. + gapi_->set_hwnd(handle); + return gapi_->Initialize(); +} + +void GPUProcessor::Destroy() { + // Destroy GAPI if window handle has not already become invalid. + if (gapi_->hwnd()) { + gapi_->Destroy(); + gapi_->set_hwnd(NULL); + } +} + +bool GPUProcessor::SetWindow(HWND handle, int width, int height) { + if (handle == NULL) { + // Destroy GAPI when the window handle becomes invalid. + Destroy(); + return true; + } else { + return Initialize(handle); + } +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/default_np_object.h b/o3d/gpu_plugin/np_utils/default_np_object.h new file mode 100644 index 0000000..388a043 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/default_np_object.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. + +#ifndef O3D_GPU_PLUGIN_NP_UTILS_DEFAULT_NP_OBJECT_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_DEFAULT_NP_OBJECT_H_ + +#include "base/basictypes.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +namespace gpu_plugin { + +class BaseNPDispatcher; + +// This class implements each of the functions in the NPClass interface. They +// all return error by default. Note that these are not virtual functions and +// this is not an interface. This class can be used as a mixin so that an +// NPObject class does not need to implement every NPClass function but rather +// inherits a default from DefaultNPObject. +template <typename RootClass> +class DefaultNPObject : public RootClass { + public: + void Invalidate() {} + + bool HasMethod(NPIdentifier name) { + return false; + } + + bool Invoke(NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return false; + } + + bool InvokeDefault(const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return false; + } + + bool HasProperty(NPIdentifier name) { + return false; + } + + bool GetProperty(NPIdentifier name, NPVariant* result) { + return false; + } + + bool SetProperty(NPIdentifier name, const NPVariant* value) { + return false; + } + + bool RemoveProperty(NPIdentifier name) { + return false; + } + + bool Enumerate(NPIdentifier** names, + uint32_t* count) { + *names = NULL; + *count = 0; + return true; + } + + bool Construct(const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return false; + } + + static BaseNPDispatcher* GetDispatcherChain() { + return NULL; + } + + protected: + DefaultNPObject() {} + virtual ~DefaultNPObject() {} + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultNPObject); +}; +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_DEFAULT_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..9e660da --- /dev/null +++ b/o3d/gpu_plugin/np_utils/dispatched_np_object_unittest.cc @@ -0,0 +1,403 @@ +// 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/default_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_browser_stub.h" +#include "o3d/gpu_plugin/np_utils/np_dispatcher.h" +#include "o3d/gpu_plugin/np_utils/np_object_mock.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::Return; +using testing::StrictMock; + +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 DefaultNPObject<NPObject> { + public: + explicit MockDispatchedNPObject(NPP npp) { + } + + 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(NPObjectPointer<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, NPObjectPointer<NPObject>()); + + NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockDispatchedNPObject, DefaultNPObject<NPObject>) + 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(NPObjectPointer<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, NPObjectPointer<NPObject>()); + NP_UTILS_END_DISPATCHER_CHAIN +}; + +class DispatchedNPObjectTest : public testing::Test { + protected: + virtual void SetUp() { + object_ = NPCreateObject<StrictMock<MockDispatchedNPObject> >(NULL); + passed_object_ = NPCreateObject<MockNPObject>(NULL); + + for (int i = 0; i != arraysize(args_); ++i) { + NULL_TO_NPVARIANT(args_[i]); + } + NULL_TO_NPVARIANT(result_); + } + + StubNPBrowser stub_browser_; + NPVariant args_[3]; + NPVariant result_; + NPObjectPointer<MockDispatchedNPObject> object_; + NPObjectPointer<NPObject> passed_object_; +}; + +TEST_F(DispatchedNPObjectTest, CannotInvokeMissingFunction) { + EXPECT_FALSE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("missing"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnNoParams) { + EXPECT_CALL(*object_, VoidReturnNoParams()); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnNoParams"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, + CannotInvokeVoidReturnNoParamsWithTooManyParams) { + EXPECT_FALSE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnNoParams"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnIntParam) { + EXPECT_CALL(*object_, VoidReturnIntParam(7)); + + INT32_TO_NPVARIANT(7, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnIntParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnBoolParam) { + EXPECT_CALL(*object_, VoidReturnBoolParam(true)); + + BOOLEAN_TO_NPVARIANT(true, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnBoolParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnFloatParamWithDoubleParam) { + EXPECT_CALL(*object_, VoidReturnFloatParam(7.0f)); + + DOUBLE_TO_NPVARIANT(7.0, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnFloatParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnFloatParamWithIntParam) { + EXPECT_CALL(*object_, VoidReturnFloatParam(7.0f)); + + INT32_TO_NPVARIANT(7, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnFloatParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnDoubleParamWithDoubleParam) { + EXPECT_CALL(*object_, VoidReturnDoubleParam(7.0)); + + DOUBLE_TO_NPVARIANT(7.0, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnDoubleParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnDoubleParamWithIntParam) { + EXPECT_CALL(*object_, VoidReturnDoubleParam(7.0f)); + + INT32_TO_NPVARIANT(7, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnDoubleParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnStringParam) { + EXPECT_CALL(*object_, VoidReturnStringParam(std::string("hello"))); + + STRINGZ_TO_NPVARIANT("hello", args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnStringParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnObjectParamWithObject) { + EXPECT_CALL(*object_, VoidReturnObjectParam(passed_object_)); + + OBJECT_TO_NPVARIANT(passed_object_.Get(), args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnObjectParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnObjectParamWithNull) { + EXPECT_CALL( + *object_, + VoidReturnObjectParam(NPObjectPointer<NPObject>())); + + NULL_TO_NPVARIANT(args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnObjectParam"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnTwoParams) { + EXPECT_CALL(*object_, VoidReturnTwoParams(false, 7)); + + BOOLEAN_TO_NPVARIANT(false, args_[0]); + INT32_TO_NPVARIANT(7, args_[1]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("voidReturnTwoParams"), + args_, + 2, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeOverloadedWithNoParams) { + EXPECT_CALL(*object_, Overloaded()); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("overloaded"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeOverloadedWithOneStringParam) { + EXPECT_CALL(*object_, Overloaded(std::string("hello"))); + + STRINGZ_TO_NPVARIANT("hello", args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("overloaded"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeOverloadedWithOneBoolParam) { + EXPECT_CALL(*object_, Overloaded(true)); + + BOOLEAN_TO_NPVARIANT(true, args_[0]); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("overloaded"), + args_, + 1, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_VOID(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeBoolReturn) { + EXPECT_CALL(*object_, BoolReturn()).WillOnce(Return(true)); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("boolReturn"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(result_)); + EXPECT_TRUE(NPVARIANT_TO_BOOLEAN(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeIntReturn) { + EXPECT_CALL(*object_, IntReturn()).WillOnce(Return(7)); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("intReturn"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_INT32(result_)); + EXPECT_EQ(7, NPVARIANT_TO_INT32(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeFloatReturn) { + EXPECT_CALL(*object_, FloatReturn()).WillOnce(Return(7.0f)); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("floatReturn"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_DOUBLE(result_)); + EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeDoubleReturn) { + EXPECT_CALL(*object_, DoubleReturn()).WillOnce(Return(7.0)); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("doubleReturn"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_DOUBLE(result_)); + EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(result_)); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeStringReturn) { + EXPECT_CALL(*object_, StringReturn()).WillOnce(Return(std::string("hello"))); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->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. + NPBrowser::get()->ReleaseVariantValue(&result_); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeObjectReturnWithObject) { + EXPECT_CALL(*object_, ObjectReturn()).WillOnce(Return(passed_object_)); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("objectReturn"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_OBJECT(result_)); + EXPECT_EQ(passed_object_.Get(), NPVARIANT_TO_OBJECT(result_)); + + NPBrowser::get()->ReleaseVariantValue(&result_); +} + +TEST_F(DispatchedNPObjectTest, CanInvokeObjectReturnWithNull) { + EXPECT_CALL(*object_, ObjectReturn()) + .WillOnce(Return(NPObjectPointer<NPObject>())); + + EXPECT_TRUE(object_->Invoke( + NPBrowser::get()->GetStringIdentifier("objectReturn"), + NULL, + 0, + &result_)); + EXPECT_TRUE(NPVARIANT_IS_NULL(result_)); +} + +TEST_F(DispatchedNPObjectTest, HasMethodReturnsTrueIfMatchingMemberVariable) { + EXPECT_TRUE(object_->HasMethod( + NPBrowser::get()->GetStringIdentifier("objectReturn"))); +} + +TEST_F(DispatchedNPObjectTest, HasMethodReturnsTrueIfNoMatchingMemberVariable) { + EXPECT_FALSE(object_->HasMethod( + NPBrowser::get()->GetStringIdentifier("missing"))); +} + +TEST_F(DispatchedNPObjectTest, 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(NPBrowser::get()->GetStringIdentifier("voidReturnNoParams"), + names[num_names - 1]); + + NPBrowser::get()->MemFree(names); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/dynamic_np_object.cc b/o3d/gpu_plugin/np_utils/dynamic_np_object.cc new file mode 100644 index 0000000..6c5a309 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/dynamic_np_object.cc @@ -0,0 +1,59 @@ +// 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/dynamic_np_object.h" + +namespace gpu_plugin { + +DynamicNPObject::DynamicNPObject(NPP npp) { +} + +void DynamicNPObject::Invalidate() { + for (PropertyMap::iterator it = properties_.begin(); + it != properties_.end(); + ++it) { + it->second.Invalidate(); + } +} + +bool DynamicNPObject::HasProperty(NPIdentifier name) { + PropertyMap::iterator it = properties_.find(name); + return it != properties_.end(); +} + +bool DynamicNPObject::GetProperty(NPIdentifier name, NPVariant* result) { + PropertyMap::iterator it = properties_.find(name); + if (it == properties_.end()) + return false; + + it->second.CopyTo(result); + return true; +} + +bool DynamicNPObject::SetProperty(NPIdentifier name, const NPVariant* value) { + properties_[name] = *value; + return true; +} + +bool DynamicNPObject::RemoveProperty(NPIdentifier name) { + properties_.erase(name); + return false; +} + +bool DynamicNPObject::Enumerate(NPIdentifier** names, uint32_t* count) { + *names = static_cast<NPIdentifier*>( + NPBrowser::get()->MemAlloc(properties_.size() * sizeof(*names))); + *count = properties_.size(); + + int i = 0; + for (PropertyMap::iterator it = properties_.begin(); + it != properties_.end(); + ++it) { + (*names)[i] = it->first; + ++i; + } + + return true; +} +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/dynamic_np_object.h b/o3d/gpu_plugin/np_utils/dynamic_np_object.h new file mode 100644 index 0000000..b80a160 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/dynamic_np_object.h @@ -0,0 +1,35 @@ +// 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_DYNAMIC_NP_OBJECT_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_DYNAMIC_NP_OBJECT_H_ + +#include <map> + +#include "o3d/gpu_plugin/np_utils/default_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_utils.h" + +namespace gpu_plugin { + +// NPObjects of this type have a dictionary of property name / variant pairs +// that can be changed at runtime through NPAPI. +class DynamicNPObject : public DefaultNPObject<NPObject> { + public: + explicit DynamicNPObject(NPP npp); + + void Invalidate(); + bool HasProperty(NPIdentifier name); + bool GetProperty(NPIdentifier name, NPVariant* result); + bool SetProperty(NPIdentifier name, const NPVariant* value); + bool RemoveProperty(NPIdentifier name); + bool Enumerate(NPIdentifier** names, uint32_t* count); + + private: + typedef std::map<NPIdentifier, SmartNPVariant> PropertyMap; + PropertyMap properties_; + DISALLOW_COPY_AND_ASSIGN(DynamicNPObject); +}; +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_DYNAMIC_NP_OBJECT_H_ diff --git a/o3d/gpu_plugin/np_utils/dynamic_np_object_unittest.cc b/o3d/gpu_plugin/np_utils/dynamic_np_object_unittest.cc new file mode 100644 index 0000000..6a73167 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/dynamic_np_object_unittest.cc @@ -0,0 +1,83 @@ +// 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/dynamic_np_object.h" +#include "o3d/gpu_plugin/np_utils/np_browser_stub.h" +#include "o3d/gpu_plugin/np_utils/np_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::Return; +using testing::StrictMock; + +namespace gpu_plugin { + +class NPDynamicNPObjectTest : public testing::Test { + protected: + virtual void SetUp() { + object_ = NPCreateObject<DynamicNPObject>(NULL); + } + + StubNPBrowser stub_browser_; + NPObjectPointer<DynamicNPObject> object_; +}; + +TEST_F(NPDynamicNPObjectTest, HasPropertyReturnsFalseForMissingProperty) { + EXPECT_FALSE(NPHasProperty(NULL, object_, "missing")); +} + +TEST_F(NPDynamicNPObjectTest, GetPropertyReturnsFalseForMissingProperty) { + int32 r; + EXPECT_FALSE(NPGetProperty(NULL, object_, "missing", &r)); +} + +TEST_F(NPDynamicNPObjectTest, CanSetProperty) { + EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", 7)); + int32 r; + EXPECT_TRUE(NPHasProperty(NULL, object_, "foo")); + EXPECT_TRUE(NPGetProperty(NULL, object_, "foo", &r)); + EXPECT_EQ(7, r); +} + +TEST_F(NPDynamicNPObjectTest, CanRemoveProperty) { + EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", 7)); + EXPECT_TRUE(NPHasProperty(NULL, object_, "foo")); + EXPECT_FALSE(NPRemoveProperty(NULL, object_, "foo")); + EXPECT_FALSE(NPHasProperty(NULL, object_, "foo")); + int32 r; + EXPECT_FALSE(NPGetProperty(NULL, object_, "foo", &r)); +} + +TEST_F(NPDynamicNPObjectTest, CanEnumerateProperties) { + EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", 7)); + + NPIdentifier* names; + uint32 num_names; + EXPECT_TRUE(object_->_class->enumerate(object_.Get(), &names, &num_names)); + + EXPECT_EQ(1, num_names); + EXPECT_EQ(NPBrowser::get()->GetStringIdentifier("foo"), names[0]); + + NPBrowser::get()->MemFree(names); +} + +// Properties should not be +TEST_F(NPDynamicNPObjectTest, InvalidateNullsObjectProperties) { + EXPECT_EQ(1, object_->referenceCount); + { + EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", object_)); + EXPECT_TRUE(NPHasProperty(NULL, object_, "foo")); + object_->_class->invalidate(object_.Get()); + EXPECT_TRUE(NPHasProperty(NULL, object_, "foo")); + NPObjectPointer<DynamicNPObject> r; + EXPECT_TRUE(NPGetProperty(NULL, object_, "foo", &r)); + EXPECT_TRUE(NULL == r.Get()); + } + // Invalidate did not release object + EXPECT_EQ(2, object_->referenceCount); + NPBrowser::get()->ReleaseObject(object_.Get()); +} +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_browser.cc b/o3d/gpu_plugin/np_utils/np_browser.cc new file mode 100644 index 0000000..3fc9185 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_browser.cc @@ -0,0 +1,128 @@ +// 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_browser.h" +#include "base/logging.h" + +#if defined(O3D_IN_CHROME) +#include "webkit/glue/plugins/nphostapi.h" +#else +#include "o3d/third_party/npapi/include/npfunctions.h" +#endif + +namespace gpu_plugin { + +NPBrowser* NPBrowser::browser_; + +NPBrowser::NPBrowser(NPNetscapeFuncs* funcs) + : netscape_funcs_(funcs) { + // Make this the first browser in the linked list. + previous_browser_ = browser_; + browser_ = this; +} + +NPBrowser::~NPBrowser() { + // Remove this browser from the linked list. + DCHECK(browser_ == this); + browser_ = previous_browser_; +} + +NPIdentifier NPBrowser::GetStringIdentifier(const NPUTF8* name) { + return netscape_funcs_->getstringidentifier(name); +} + +void* NPBrowser::MemAlloc(size_t size) { + return netscape_funcs_->memalloc(size); +} + +void NPBrowser::MemFree(void* p) { + netscape_funcs_->memfree(p); +} + +NPObject* NPBrowser::CreateObject(NPP npp, const NPClass* cl) { + return netscape_funcs_->createobject(npp, const_cast<NPClass*>(cl)); +} + +NPObject* NPBrowser::RetainObject(NPObject* object) { + return netscape_funcs_->retainobject(object); +} + +void NPBrowser::ReleaseObject(NPObject* object) { + netscape_funcs_->releaseobject(object); +} + +void NPBrowser::ReleaseVariantValue(NPVariant* variant) { + netscape_funcs_->releasevariantvalue(variant); +} + +bool NPBrowser::HasProperty(NPP npp, + NPObject* object, + NPIdentifier name) { + return netscape_funcs_->hasproperty(npp, object, name); +} + +bool NPBrowser::GetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + NPVariant* result) { + return netscape_funcs_->getproperty(npp, object, name, result); +} + +bool NPBrowser::SetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* result) { + return netscape_funcs_->setproperty(npp, object, name, result); +} + +bool NPBrowser::RemoveProperty(NPP npp, + NPObject* object, + NPIdentifier name) { + return netscape_funcs_->removeproperty(npp, object, name); +} + +bool NPBrowser::HasMethod(NPP npp, + NPObject* object, + NPIdentifier name) { + return netscape_funcs_->hasmethod(npp, object, name); +} + +bool NPBrowser::Invoke(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return netscape_funcs_->invoke(npp, object, name, args, num_args, result); +} + +NPObject* NPBrowser::GetWindowNPObject(NPP npp) { + NPObject* window; + if (NPERR_NO_ERROR == netscape_funcs_->getvalue(npp, + NPNVWindowNPObject, + &window)) { + return window; + } else { + return NULL; + } +} + +void NPBrowser::PluginThreadAsyncCall(NPP npp, + PluginThreadAsyncCallProc callback, + void* data) { + netscape_funcs_->pluginthreadasynccall(npp, callback, data); +} + +uint32 NPBrowser::ScheduleTimer(NPP npp, + uint32 interval, + bool repeat, + TimerProc callback) { + return netscape_funcs_->scheduletimer(npp, interval, repeat, callback); +} + +void NPBrowser::UnscheduleTimer(NPP npp, uint32 timer_id) { + netscape_funcs_->unscheduletimer(npp, timer_id); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_browser.h b/o3d/gpu_plugin/np_utils/np_browser.h new file mode 100644 index 0000000..5e71aac --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_browser.h @@ -0,0 +1,95 @@ +// 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_BROWSER_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_H_ + +#include "base/basictypes.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +typedef struct _NPNetscapeFuncs NPNetscapeFuncs; + +namespace gpu_plugin { + +// This class exposes the functions provided by the browser to a plugin (the +// ones prefixed NPN_). +class NPBrowser { + public: + explicit NPBrowser(NPNetscapeFuncs* funcs); + virtual ~NPBrowser(); + + static NPBrowser* get() { + return browser_; + } + + // Standard functions from NPNetscapeFuncs. + + virtual NPIdentifier GetStringIdentifier(const NPUTF8* name); + + virtual void* MemAlloc(size_t size); + + virtual void MemFree(void* p); + + virtual NPObject* CreateObject(NPP npp, const NPClass* cl); + + virtual NPObject* RetainObject(NPObject* object); + + virtual void ReleaseObject(NPObject* object); + + virtual void ReleaseVariantValue(NPVariant* variant); + + virtual bool HasProperty(NPP npp, + NPObject* object, + NPIdentifier name); + + virtual bool GetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + NPVariant* result); + + virtual bool SetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* result); + + virtual bool RemoveProperty(NPP npp, + NPObject* object, + NPIdentifier name); + + virtual bool HasMethod(NPP npp, + NPObject* object, + NPIdentifier name); + + virtual bool Invoke(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result); + + virtual NPObject* GetWindowNPObject(NPP npp); + + typedef void (*PluginThreadAsyncCallProc)(void* data); + virtual void PluginThreadAsyncCall(NPP npp, + PluginThreadAsyncCallProc callback, + void* data); + + typedef void (*TimerProc)(NPP npp, uint32 timer_id); + virtual uint32 ScheduleTimer(NPP npp, + uint32 interval, + bool repeat, + TimerProc callback); + + virtual void UnscheduleTimer(NPP npp, uint32 timer_id); + + private: + static NPBrowser* browser_; + NPBrowser* previous_browser_; + NPNetscapeFuncs* netscape_funcs_; + DISALLOW_COPY_AND_ASSIGN(NPBrowser); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_H_ diff --git a/o3d/gpu_plugin/np_utils/np_browser_mock.h b/o3d/gpu_plugin/np_utils/np_browser_mock.h new file mode 100644 index 0000000..9175e42 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_browser_mock.h @@ -0,0 +1,50 @@ +// 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_BROWSER_MOCK_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_MOCK_H_ + +#include "o3d/gpu_plugin/np_utils/np_browser_stub.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace gpu_plugin { + +// This mocks certain member functions of the stub browser. Those relating +// to identifiers, memory management, reference counting and forwarding to +// NPObjects are deliberately not mocked so the mock browser can be used as +// normal for these calls. +class MockNPBrowser : public StubNPBrowser { + public: + NPObject* ConcreteCreateObject(NPP npp, const NPClass* cl) { + return StubNPBrowser::CreateObject(npp, cl); + } + + MockNPBrowser() { + // Do not mock CreateObject by default but allow it to be mocked so object + // creation can be intercepted. + ON_CALL(*this, CreateObject(testing::_, testing::_)) + .WillByDefault(testing::Invoke(this, + &MockNPBrowser::ConcreteCreateObject)); + } + + void ConcretePluginThreadAsyncCall(NPP npp, + PluginThreadAsyncCallProc callback, + void* data) { + return StubNPBrowser::PluginThreadAsyncCall(npp, callback, data); + } + + MOCK_METHOD2(CreateObject, NPObject*(NPP npp, const NPClass* cl)); + MOCK_METHOD1(GetWindowNPObject, NPObject*(NPP cpp)); + MOCK_METHOD3(PluginThreadAsyncCall, + void(NPP npp, PluginThreadAsyncCallProc callback, void* data)); + MOCK_METHOD4(ScheduleTimer, uint32(NPP npp, + uint32 interval, + bool repeat, + TimerProc callback)); + MOCK_METHOD2(UnscheduleTimer, void(NPP npp, uint32 timer_id)); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_MOCK_H_ diff --git a/o3d/gpu_plugin/np_utils/np_browser_stub.cc b/o3d/gpu_plugin/np_utils/np_browser_stub.cc new file mode 100644 index 0000000..f20bbda --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_browser_stub.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/np_browser_stub.h" +#include "base/logging.h" +#include "base/message_loop.h" + +namespace gpu_plugin { + +StubNPBrowser::StubNPBrowser() : NPBrowser(NULL) { +} + +StubNPBrowser::~StubNPBrowser() { +} + +NPIdentifier StubNPBrowser::GetStringIdentifier(const NPUTF8* name) { + static std::set<std::string> names; + 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* StubNPBrowser::MemAlloc(size_t size) { + return malloc(size); +} + +void StubNPBrowser::MemFree(void* p) { + free(p); +} + +NPObject* StubNPBrowser::CreateObject(NPP npp, const NPClass* cl) { + NPObject* object = cl->allocate(npp, const_cast<NPClass*>(cl)); + object->referenceCount = 1; + object->_class = const_cast<NPClass*>(cl); + return object; +} + +NPObject* StubNPBrowser::RetainObject(NPObject* object) { + ++object->referenceCount; + return object; +} + +void StubNPBrowser::ReleaseObject(NPObject* object) { + DCHECK_GE(object->referenceCount, 0u); + --object->referenceCount; + if (object->referenceCount == 0) { + object->_class->deallocate(object); + } +} + +void StubNPBrowser::ReleaseVariantValue(NPVariant* variant) { + if (NPVARIANT_IS_STRING(*variant)) { + MemFree(const_cast<NPUTF8*>(variant->value.stringValue.UTF8Characters)); + } else if (NPVARIANT_IS_OBJECT(*variant)) { + ReleaseObject(NPVARIANT_TO_OBJECT(*variant)); + } +} + +bool StubNPBrowser::HasProperty(NPP npp, + NPObject* object, + NPIdentifier name) { + return object->_class->hasProperty(object, name); +} + +bool StubNPBrowser::GetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + NPVariant* result) { + return object->_class->getProperty(object, name, result); +} + +bool StubNPBrowser::SetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* result) { + return object->_class->setProperty(object, name, result); +} + +bool StubNPBrowser::RemoveProperty(NPP npp, + NPObject* object, + NPIdentifier name) { + return object->_class->removeProperty(object, name); +} + +bool StubNPBrowser::HasMethod(NPP npp, + NPObject* object, + NPIdentifier name) { + return object->_class->hasMethod(object, name); +} + +bool StubNPBrowser::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); +} + +NPObject* StubNPBrowser::GetWindowNPObject(NPP npp) { + return NULL; +} + +void StubNPBrowser::PluginThreadAsyncCall( + NPP npp, + PluginThreadAsyncCallProc callback, + void* data) { + MessageLoop::current()->PostTask(FROM_HERE, + NewRunnableFunction(callback, data)); +} + +uint32 StubNPBrowser::ScheduleTimer(NPP npp, + uint32 interval, + bool repeat, + TimerProc callback) { + return 0; +} + +void StubNPBrowser::UnscheduleTimer(NPP npp, uint32 timer_id) { +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_browser_stub.h b/o3d/gpu_plugin/np_utils/np_browser_stub.h new file mode 100644 index 0000000..0740244 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_browser_stub.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. + +#ifndef O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_STUB_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_STUB_H_ + +#include <set> +#include <string> + +#include "o3d/gpu_plugin/np_utils/np_browser.h" + +namespace gpu_plugin { + +// Simple implementation of subset of the NPN functions for testing. +class StubNPBrowser : public NPBrowser { + public: + StubNPBrowser(); + virtual ~StubNPBrowser(); + + // Standard functions from NPNetscapeFuncs. + + virtual NPIdentifier GetStringIdentifier(const NPUTF8* name); + + virtual void* MemAlloc(size_t size); + + virtual void MemFree(void* p); + + virtual NPObject* CreateObject(NPP npp, const NPClass* cl); + + virtual NPObject* RetainObject(NPObject* object); + + virtual void ReleaseObject(NPObject* object); + + virtual void ReleaseVariantValue(NPVariant* variant); + + virtual bool HasProperty(NPP npp, + NPObject* object, + NPIdentifier name); + + virtual bool GetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + NPVariant* result); + + virtual bool SetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* result); + + virtual bool RemoveProperty(NPP npp, + NPObject* object, + NPIdentifier name); + + virtual bool HasMethod(NPP npp, + NPObject* object, + NPIdentifier name); + virtual bool Invoke(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result); + + virtual NPObject* GetWindowNPObject(NPP npp); + + virtual void PluginThreadAsyncCall(NPP npp, + PluginThreadAsyncCallProc callback, + void* data); + + virtual uint32 ScheduleTimer(NPP npp, + uint32 interval, + bool repeat, + TimerProc callback); + + virtual void UnscheduleTimer(NPP npp, uint32 timer_id); + + private: + DISALLOW_COPY_AND_ASSIGN(StubNPBrowser); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_BROWSER_STUB_H_ diff --git a/o3d/gpu_plugin/np_utils/np_class.h b/o3d/gpu_plugin/np_utils/np_class.h new file mode 100644 index 0000000..a6d557e --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_class.h @@ -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. + +#ifndef O3D_GPU_PLUGIN_NP_UTILS_NP_CLASS_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_CLASS_H_ + +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +// This file implements NPGetClass<T>. This function returns an NPClass +// that can be used to instantiate an NPObject subclass T. The NPClass +// function pointers will invoke the most derived corresponding member +// functions in T. + +namespace gpu_plugin { + +namespace np_class_impl { + // This template version of the NPClass allocate function creates a subclass + // of BaseNPObject. + template <typename NPObjectType> + static NPObject* Allocate(NPP npp, NPClass*) { + return new NPObjectType(npp); + } + + // These implementations of the NPClass functions forward to the virtual + // functions in DefaultNPObject. + template <typename NPObjectType> + static void Deallocate(NPObject* object) { + delete static_cast<NPObjectType*>(object); + } + + template <typename NPObjectType> + static void Invalidate(NPObject* object) { + return static_cast<NPObjectType*>(object)->Invalidate(); + } + + template <typename NPObjectType> + static bool HasMethod(NPObject* object, NPIdentifier name) { + return static_cast<NPObjectType*>(object)->HasMethod(name); + } + + template <typename NPObjectType> + static bool Invoke(NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return static_cast<NPObjectType*>(object)->Invoke( + name, args, num_args, result); + } + + template <typename NPObjectType> + static bool InvokeDefault(NPObject* object, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return static_cast<NPObjectType*>(object)->InvokeDefault( + args, num_args, result); + } + + template <typename NPObjectType> + static bool HasProperty(NPObject* object, NPIdentifier name) { + return static_cast<NPObjectType*>(object)->HasProperty(name); + } + + template <typename NPObjectType> + static bool GetProperty(NPObject* object, + NPIdentifier name, + NPVariant* result) { + return static_cast<NPObjectType*>(object)->GetProperty(name, result); + } + + template <typename NPObjectType> + static bool SetProperty(NPObject* object, + NPIdentifier name, + const NPVariant* value) { + return static_cast<NPObjectType*>(object)->SetProperty(name, value); + } + + template <typename NPObjectType> + static bool RemoveProperty(NPObject* object, NPIdentifier name) { + return static_cast<NPObjectType*>(object)->RemoveProperty(name); + } + + template <typename NPObjectType> + static bool Enumerate(NPObject* object, + NPIdentifier** names, + uint32_t* count) { + return static_cast<NPObjectType*>(object)->Enumerate(names, count); + }; + + template <typename NPObjectType> + static bool Construct(NPObject* object, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return static_cast<NPObjectType*>(object)->Construct( + args, num_args, result); + } +} // namespace np_class_impl; + +template <typename NPObjectType> +const NPClass* NPGetClass() { + static const NPClass np_class = { + NP_CLASS_STRUCT_VERSION, + np_class_impl::Allocate<NPObjectType>, + np_class_impl::Deallocate<NPObjectType>, + np_class_impl::Invalidate<NPObjectType>, + np_class_impl::HasMethod<NPObjectType>, + np_class_impl::Invoke<NPObjectType>, + np_class_impl::InvokeDefault<NPObjectType>, + np_class_impl::HasProperty<NPObjectType>, + np_class_impl::GetProperty<NPObjectType>, + np_class_impl::SetProperty<NPObjectType>, + np_class_impl::RemoveProperty<NPObjectType>, + np_class_impl::Enumerate<NPObjectType>, + np_class_impl::Construct<NPObjectType>, + }; + return &np_class; +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_CLASS_H_ diff --git a/o3d/gpu_plugin/np_utils/np_class_unittest.cc b/o3d/gpu_plugin/np_utils/np_class_unittest.cc new file mode 100644 index 0000000..a58f47a --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_class_unittest.cc @@ -0,0 +1,143 @@ +// 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_class.h" +#include "o3d/gpu_plugin/np_utils/np_object_mock.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::StrictMock; + +namespace gpu_plugin { + +class NPClassTest : public testing::Test { + protected: + virtual void SetUp() { + np_class = NPGetClass<StrictMock<MockNPObject> >(); + + // Dummy identifier is never used with real NPAPI so it can point to + // anything. + identifier = this; + } + + virtual void TearDown() { + } + + NPP_t npp_; + const NPClass* np_class; + NPIdentifier identifier; + NPVariant args[3]; + NPVariant result; +}; + +TEST_F(NPClassTest, AllocateAndDeallocateObject) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + EXPECT_TRUE(NULL != object); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, InvalidateForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, Invalidate()); + np_class->invalidate(object); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, HasMethodForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, HasMethod(identifier)); + np_class->hasMethod(object, identifier); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, InvokeForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, Invoke(identifier, args, 3, &result)); + np_class->invoke(object, identifier, args, 3, &result); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, InvokeDefaultForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, InvokeDefault(args, 3, &result)); + np_class->invokeDefault(object, args, 3, &result); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, HasPropertyForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, HasProperty(identifier)); + np_class->hasProperty(object, identifier); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, GetPropertyForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, GetProperty(identifier, &result)); + np_class->getProperty(object, identifier, &result); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, SetPropertyForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, SetProperty(identifier, &result)); + np_class->setProperty(object, identifier, &result); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, RemovePropertyForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, RemoveProperty(identifier)); + np_class->removeProperty(object, identifier); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, EnumerateForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + NPIdentifier* identifier = NULL; + uint32_t count; + EXPECT_CALL(*object, Enumerate(&identifier, &count)); + np_class->enumerate(object, &identifier, &count); + + np_class->deallocate(object); +} + +TEST_F(NPClassTest, ConstructForwards) { + MockNPObject* object = static_cast<MockNPObject*>( + np_class->allocate(&npp_, const_cast<NPClass*>(np_class))); + + EXPECT_CALL(*object, Construct(args, 3, &result)); + np_class->construct(object, args, 3, &result); + + np_class->deallocate(object); +} +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_dispatcher.cc b/o3d/gpu_plugin/np_utils/np_dispatcher.cc new file mode 100644 index 0000000..06658b4 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_dispatcher.cc @@ -0,0 +1,85 @@ +// 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_dispatcher.h" + +namespace gpu_plugin { + +bool DispatcherHasMethodHelper(BaseNPDispatcher* chain, + NPObject* object, + NPIdentifier name) { + for (BaseNPDispatcher* dispatcher = chain; + dispatcher; + dispatcher = dispatcher->next()) { + if (dispatcher->name() == name) { + return true; + } + } + + return false; +} + +bool DispatcherInvokeHelper(BaseNPDispatcher* chain, + NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + VOID_TO_NPVARIANT(*result); + + for (BaseNPDispatcher* dispatcher = chain; + dispatcher; + dispatcher = dispatcher->next()) { + if (dispatcher->name() == name && dispatcher->num_args() == num_args) { + if (dispatcher->Invoke(object, args, num_args, result)) + return true; + } + } + + return false; +} + +bool DispatcherEnumerateHelper(BaseNPDispatcher* chain, + NPObject* object, + NPIdentifier** names, + uint32_t* num_names) { + // Count the number of names. + *num_names = 0; + for (BaseNPDispatcher* dispatcher = chain; + dispatcher; + dispatcher = dispatcher->next()) { + ++(*num_names); + } + + // Copy names into the array. + *names = static_cast<NPIdentifier*>( + NPBrowser::get()->MemAlloc((*num_names) * sizeof(**names))); + int i = 0; + for (BaseNPDispatcher* dispatcher = chain; + dispatcher; + dispatcher = dispatcher->next()) { + (*names)[i] = dispatcher->name(); + ++i; + } + + return true; +} + +BaseNPDispatcher::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_ = NPBrowser::get()->GetStringIdentifier( + java_script_style_name.c_str()); +} + +BaseNPDispatcher::~BaseNPDispatcher() { +} + +} // namespace gpu_plugin 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..bc4ac02 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_dispatcher.h @@ -0,0 +1,222 @@ +// 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_utils.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +// Dispatchers make regular member functions available as NPObject methods. +// Usage: +// +// class MyNPObject : public DefaultNPObject<NPObject> { +// public: +// int MyMethod(bool a, float b); +// 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* +// + +// These macros are used to make dispatcher chains. +#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* GetDispatcherChain() { \ + typedef Class ThisClass; \ + BaseNPDispatcher* top_dispatcher = BaseClass::GetDispatcherChain(); \ + +#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; \ + } \ + bool HasMethod(NPIdentifier name) { \ + return DispatcherHasMethodHelper(GetDispatcherChain(), this, name); \ + } \ + bool Invoke(NPIdentifier name, \ + const NPVariant* args, \ + uint32_t num_args, \ + NPVariant* result) { \ + return DispatcherInvokeHelper(GetDispatcherChain(), \ + this, \ + name, \ + args, \ + num_args, \ + result); \ + } \ + bool Enumerate(NPIdentifier** names, uint32_t* num_names) { \ + return DispatcherEnumerateHelper(GetDispatcherChain(), \ + this, \ + names, \ + num_names); \ + } \ + +namespace gpu_plugin { + +class BaseNPDispatcher { + public: + BaseNPDispatcher(BaseNPDispatcher* next, const NPUTF8* name); + + 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); +}; + +bool DispatcherHasMethodHelper(BaseNPDispatcher* chain, + NPObject* object, + NPIdentifier name); + +bool DispatcherInvokeHelper(BaseNPDispatcher* chain, + NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result); + +bool DispatcherEnumerateHelper(BaseNPDispatcher* chain, + NPObject* object, + NPIdentifier** names, + uint32_t* num_names); + +// 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 + +#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..62fb8c4 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h @@ -0,0 +1,85 @@ +// 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 header guard here. This file is included multiple +// times, once for each dispatcher specialiation arity. Do not include this +// file directly. Include np_dispatcher.h instead. + +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_headers.h b/o3d/gpu_plugin/np_utils/np_headers.h new file mode 100644 index 0000000..89e666a --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_headers.h @@ -0,0 +1,16 @@ +// 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_HEADERS_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_HEADERS_H_ + +#if defined(O3D_IN_CHROME) +#include "third_party/npapi/bindings/npapi.h" +#include "third_party/npapi/bindings/npruntime.h" +#else +#include "o3d/third_party/npapi/include/npapi.h" +#include "o3d/third_party/npapi/include/npruntime.h" +#endif + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_HEADERS_H_ diff --git a/o3d/gpu_plugin/np_utils/np_object_mock.h b/o3d/gpu_plugin/np_utils/np_object_mock.h new file mode 100644 index 0000000..84e0912 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_object_mock.h @@ -0,0 +1,36 @@ +// 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_MOCK_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_OBJECT_MOCK_H_ + +#include "o3d/gpu_plugin/np_utils/np_browser.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace gpu_plugin { + +class MockNPObject : public NPObject { + public: + explicit MockNPObject(NPP npp) { + } + + MOCK_METHOD0(Invalidate, void()); + MOCK_METHOD1(HasMethod, bool(NPIdentifier)); + MOCK_METHOD4(Invoke, + bool(NPIdentifier, const NPVariant*, uint32_t, NPVariant*)); + MOCK_METHOD3(InvokeDefault, bool(const NPVariant*, uint32_t, NPVariant*)); + MOCK_METHOD1(HasProperty, bool(NPIdentifier)); + MOCK_METHOD2(GetProperty, bool(NPIdentifier, NPVariant*)); + MOCK_METHOD2(SetProperty, bool(NPIdentifier, const NPVariant*)); + MOCK_METHOD1(RemoveProperty, bool(NPIdentifier)); + MOCK_METHOD2(Enumerate, bool(NPIdentifier**, uint32_t*)); + MOCK_METHOD3(Construct, bool(const NPVariant*, uint32_t, NPVariant*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockNPObject); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_OBJECT_MOCK_H_ 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..5cf3bbe --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_object_pointer.h @@ -0,0 +1,119 @@ +// 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 "base/logging.h" +#include "o3d/gpu_plugin/np_utils/np_browser.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +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_) { + Retain(); + } + + explicit NPObjectPointer(NPObjectType* p) : object_(p) { + Retain(); + } + + template <typename RHS> + NPObjectPointer(const NPObjectPointer<RHS>& rhs) : object_(rhs.Get()) { + Retain(); + } + + ~NPObjectPointer() { + Release(); + } + + NPObjectPointer& operator=(const NPObjectPointer& rhs) { + if (object_ == rhs.Get()) + return *this; + + Release(); + object_ = rhs.object_; + Retain(); + return *this; + } + + template <typename RHS> + NPObjectPointer& operator=(const NPObjectPointer<RHS>& rhs) { + if (object_ == rhs.Get()) + return *this; + + Release(); + object_ = rhs.Get(); + Retain(); + return *this; + } + + template <class RHS> + bool operator==(const NPObjectPointer<RHS>& rhs) const { + return object_ == rhs.Get(); + } + + template <class RHS> + bool operator!=(const NPObjectPointer<RHS>& rhs) const { + return object_ != rhs.Get(); + } + + // 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); + pointer.Release(); + return pointer; + } + + // The NPObject convention for returning an NPObject pointer from a function + // is that the caller is responsible for releasing the reference count. + NPObjectType* ToReturned() const { + Retain(); + return object_; + } + + NPObjectType* Get() const { + return object_; + } + + NPObjectType* operator->() const { + return object_; + } + + NPObjectType& operator*() const { + return *object_; + } + + private: + void Retain() const { + if (object_) { + NPBrowser::get()->RetainObject(object_); + } + } + + void Release() const { + if (object_) { + NPBrowser::get()->ReleaseObject(object_); + } + } + + NPObjectType* object_; +}; + +// For test diagnostics. +template <typename NPObjectType> +std::ostream& operator<<(std::ostream& stream, + const NPObjectPointer<NPObjectType>& pointer) { + return stream << pointer.Get(); +} +} // namespace gpu_plugin + +#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..c043c08 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_object_pointer_unittest.cc @@ -0,0 +1,220 @@ +// 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_class.h" +#include "o3d/gpu_plugin/np_utils/np_object_mock.h" +#include "o3d/gpu_plugin/np_utils/np_browser_stub.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 gpu_plugin { + +class DerivedNPObject : public MockNPObject { + public: + explicit DerivedNPObject(NPP npp) : MockNPObject(npp) { + } +}; + +class NPObjectPointerTest : public testing::Test { + protected: + virtual void SetUp() { + np_class_ = NPGetClass<StrictMock<MockNPObject> >(); + + raw_pointer_ = static_cast<MockNPObject*>( + NPBrowser::get()->CreateObject(NULL, np_class_)); + + raw_derived_pointer_ = static_cast<DerivedNPObject*>( + NPBrowser::get()->CreateObject(NULL, np_class_)); + } + + virtual void TearDown() { + NPBrowser::get()->ReleaseObject(raw_pointer_); + NPBrowser::get()->ReleaseObject(raw_derived_pointer_); + } + + StubNPBrowser stub_browser_; + const NPClass* np_class_; + MockNPObject* raw_pointer_; + DerivedNPObject* raw_derived_pointer_; +}; + +TEST_F(NPObjectPointerTest, PointerIsNullByDefault) { + NPObjectPointer<MockNPObject> p; + ASSERT_TRUE(NULL == p.Get()); +} + +TEST_F(NPObjectPointerTest, PointerCanBeExplicitlyConstructedFromRawPointer) { + EXPECT_EQ(1, raw_pointer_->referenceCount); + { + NPObjectPointer<MockNPObject> 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<MockNPObject> p(NULL); + ASSERT_TRUE(NULL == p.Get()); +} + +TEST_F(NPObjectPointerTest, PointerCanBeCopyConstructed) { + NPObjectPointer<MockNPObject> p1(raw_pointer_); + EXPECT_EQ(2, raw_pointer_->referenceCount); + { + NPObjectPointer<MockNPObject> p2(p1); + ASSERT_TRUE(raw_pointer_ == p2.Get()); + EXPECT_EQ(3, raw_pointer_->referenceCount); + } + EXPECT_EQ(2, raw_pointer_->referenceCount); +} + +TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromDerived) { + NPObjectPointer<DerivedNPObject> p1(raw_derived_pointer_); + EXPECT_EQ(2, raw_derived_pointer_->referenceCount); + { + NPObjectPointer<MockNPObject> p2(p1); + ASSERT_TRUE(raw_derived_pointer_ == p2.Get()); + EXPECT_EQ(3, raw_derived_pointer_->referenceCount); + } + EXPECT_EQ(2, raw_derived_pointer_->referenceCount); +} + +TEST_F(NPObjectPointerTest, + PointerCanBeCopyConstructedFromNull) { + NPObjectPointer<MockNPObject> p(NULL); + ASSERT_TRUE(NULL == p.Get()); +} + +TEST_F(NPObjectPointerTest, PointerCanBeAssigned) { + NPObjectPointer<MockNPObject> p1(raw_pointer_); + EXPECT_EQ(2, raw_pointer_->referenceCount); + { + NPObjectPointer<MockNPObject> p2; + p2 = p1; + ASSERT_TRUE(raw_pointer_ == p2.Get()); + EXPECT_EQ(3, raw_pointer_->referenceCount); + + p2 = NPObjectPointer<MockNPObject>(); + 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, PointerCanBeAssignedToSelf) { + NPObjectPointer<MockNPObject> p(raw_pointer_); + NPBrowser::get()->ReleaseObject(raw_pointer_); + EXPECT_EQ(1, raw_pointer_->referenceCount); + p = p; + EXPECT_EQ(1, raw_pointer_->referenceCount); + NPBrowser::get()->RetainObject(raw_pointer_); +} + +TEST_F(NPObjectPointerTest, PointerCanBeAssignedDerived) { + NPObjectPointer<DerivedNPObject> p1(raw_derived_pointer_); + EXPECT_EQ(2, raw_derived_pointer_->referenceCount); + { + NPObjectPointer<MockNPObject> p2; + p2 = p1; + ASSERT_TRUE(raw_derived_pointer_ == p2.Get()); + EXPECT_EQ(3, raw_derived_pointer_->referenceCount); + + p2 = NPObjectPointer<MockNPObject>(); + ASSERT_TRUE(NULL == p2.Get()); + EXPECT_EQ(2, raw_derived_pointer_->referenceCount); + + p2 = p1; + ASSERT_TRUE(raw_derived_pointer_ == p2.Get()); + EXPECT_EQ(3, raw_derived_pointer_->referenceCount); + } + EXPECT_EQ(2, raw_derived_pointer_->referenceCount); +} + +TEST_F(NPObjectPointerTest, DerivedPointerCanBeAssignedToSelf) { + NPObjectPointer<MockNPObject> p1(raw_derived_pointer_); + NPObjectPointer<DerivedNPObject> p2(raw_derived_pointer_); + NPBrowser::get()->ReleaseObject(raw_derived_pointer_); + NPBrowser::get()->ReleaseObject(raw_derived_pointer_); + EXPECT_EQ(1, raw_derived_pointer_->referenceCount); + p1 = p2; + EXPECT_EQ(1, raw_derived_pointer_->referenceCount); + NPBrowser::get()->RetainObject(raw_derived_pointer_); + NPBrowser::get()->RetainObject(raw_derived_pointer_); +} + +TEST_F(NPObjectPointerTest, CanComparePointersForEqual) { + NPObjectPointer<MockNPObject> p1(raw_pointer_); + NPObjectPointer<DerivedNPObject> p2(raw_derived_pointer_); + EXPECT_TRUE(p1 == p1); + EXPECT_FALSE(p1 == p2); + EXPECT_FALSE(p2 == p1); + EXPECT_FALSE(p1 == NPObjectPointer<MockNPObject>()); +} + +TEST_F(NPObjectPointerTest, CanComparePointersForNotEqual) { + NPObjectPointer<MockNPObject> p1(raw_pointer_); + NPObjectPointer<DerivedNPObject> p2(raw_derived_pointer_); + EXPECT_FALSE(p1 != p1); + EXPECT_TRUE(p1 != p2); + EXPECT_TRUE(p2 != p1); + EXPECT_TRUE(p1 != NPObjectPointer<MockNPObject>()); +} + +TEST_F(NPObjectPointerTest, ArrowOperatorCanBeUsedToAccessNPObjectMembers) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("hello"); + + EXPECT_CALL(*raw_pointer_, HasProperty(name)).WillOnce(Return(true)); + + NPObjectPointer<MockNPObject> p(raw_pointer_); + EXPECT_TRUE(p->HasProperty(name)); +} + +TEST_F(NPObjectPointerTest, StarOperatorReturnsNPObjectReference) { + NPObjectPointer<MockNPObject> p(raw_pointer_); + EXPECT_EQ(raw_pointer_, &*p); +} + +TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromReturnedNPObject) { + NPBrowser::get()->RetainObject(raw_pointer_); + EXPECT_EQ(2, raw_pointer_->referenceCount); + { + NPObjectPointer<MockNPObject> p( + NPObjectPointer<MockNPObject>::FromReturned(raw_pointer_)); + EXPECT_EQ(2, raw_pointer_->referenceCount); + } + EXPECT_EQ(1, raw_pointer_->referenceCount); +} + +TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromReturnedNullNPObject) { + NPObjectPointer<MockNPObject> p( + NPObjectPointer<MockNPObject>::FromReturned(NULL)); + EXPECT_TRUE(NULL == p.Get()); +} + +TEST_F(NPObjectPointerTest, PointerCanBeReturnedAsARawNPObject) { + NPObjectPointer<MockNPObject> p(raw_pointer_); + EXPECT_EQ(raw_pointer_, p.ToReturned()); + + // Check reference count is incremented before return for caller. + EXPECT_EQ(3, raw_pointer_->referenceCount); + + NPBrowser::get()->ReleaseObject(raw_pointer_); +} + +TEST_F(NPObjectPointerTest, NULLPointerCanBeReturnedAsARawNPObject) { + NPObjectPointer<MockNPObject> p; + EXPECT_TRUE(NULL == p.ToReturned()); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_plugin_object.h b/o3d/gpu_plugin/np_utils/np_plugin_object.h new file mode 100644 index 0000000..06e0136 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_plugin_object.h @@ -0,0 +1,50 @@ +// 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_PLUGIN_OBJECT_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_H_ + +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +namespace gpu_plugin { + +// Interface for a plugin instance. The NPP plugin calls forwards to an instance +// of this interface. +class PluginObject { + public: + // Initialize this object. + virtual NPError New(NPMIMEType plugin_type, + int16 argc, + char* argn[], + char* argv[], + NPSavedData* saved) = 0; + + virtual NPError SetWindow(NPWindow* new_window) = 0; + + virtual int16 HandleEvent(NPEvent* event) = 0; + + // Uninitialize but do not deallocate the object. Release will be called to + // deallocate if Destroy succeeds. + virtual NPError Destroy(NPSavedData** saved) = 0; + + // Deallocate this object. This object is invalid after this returns. + virtual void Release() = 0; + + virtual NPObject* GetScriptableNPObject() = 0; + + protected: + PluginObject() { + } + + virtual ~PluginObject() { + } + + private: + DISALLOW_COPY_AND_ASSIGN(PluginObject); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_H_ diff --git a/o3d/gpu_plugin/np_utils/np_plugin_object_factory.cc b/o3d/gpu_plugin/np_utils/np_plugin_object_factory.cc new file mode 100644 index 0000000..96cb595 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_plugin_object_factory.cc @@ -0,0 +1,30 @@ +// 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/gpu_plugin_object_factory.h" +#include "base/logging.h" + +namespace gpu_plugin { + +NPPluginObjectFactory* NPPluginObjectFactory::factory_; + +PluginObject* NPPluginObjectFactory::CreatePluginObject( + NPP npp, + NPMIMEType plugin_type) { + return NULL; +} + +NPPluginObjectFactory::NPPluginObjectFactory() { + // Make this the first factory in the linked list. + previous_factory_ = factory_; + factory_ = this; +} + +NPPluginObjectFactory::~NPPluginObjectFactory() { + // Remove this factory from the linked list. + DCHECK(factory_ == this); + factory_ = previous_factory_; +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_plugin_object_factory.h b/o3d/gpu_plugin/np_utils/np_plugin_object_factory.h new file mode 100644 index 0000000..4c8d61c --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_plugin_object_factory.h @@ -0,0 +1,37 @@ +// 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_PLUGIN_OBJECT_FACTORY_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_H_ + +#include "base/basictypes.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +namespace gpu_plugin { + +class PluginObject; + +// Mockable factory base class used to create instances of PluginObject based on +// plugin mime type. +class NPPluginObjectFactory { + public: + virtual PluginObject* CreatePluginObject(NPP npp, NPMIMEType plugin_type); + + static NPPluginObjectFactory* get() { + return factory_; + } + + protected: + NPPluginObjectFactory(); + virtual ~NPPluginObjectFactory(); + + private: + static NPPluginObjectFactory* factory_; + NPPluginObjectFactory* previous_factory_; + DISALLOW_COPY_AND_ASSIGN(NPPluginObjectFactory); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_H_ diff --git a/o3d/gpu_plugin/np_utils/np_plugin_object_factory_mock.h b/o3d/gpu_plugin/np_utils/np_plugin_object_factory_mock.h new file mode 100644 index 0000000..9a61537 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_plugin_object_factory_mock.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_NP_PLUGIN_OBJECT_FACTORY_MOCK_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_MOCK_H_ + +#include "o3d/gpu_plugin/np_utils/np_plugin_object_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu_plugin { + +// Mockable factory used to create instances of PluginObject based on plugin +// mime type. +class MockPluginObjectFactory : public NPPluginObjectFactory { + public: + MOCK_METHOD2(CreatePluginObject, PluginObject*(NPP, NPMIMEType)); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_MOCK_H_ diff --git a/o3d/gpu_plugin/np_utils/np_plugin_object_mock.h b/o3d/gpu_plugin/np_utils/np_plugin_object_mock.h new file mode 100644 index 0000000..fe1f407 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_plugin_object_mock.h @@ -0,0 +1,26 @@ +// 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_PLUGIN_OBJECT_MOCK_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_MOCK_H_ + +#include "o3d/gpu_plugin/np_utils/np_plugin_object.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu_plugin { + +class MockPluginObject : public PluginObject { + public: + MOCK_METHOD5(New, NPError(NPMIMEType, int16, char*[], char*[], NPSavedData*)); + MOCK_METHOD1(SetWindow, NPError(NPWindow*)); + MOCK_METHOD1(HandleEvent, int16(NPEvent*)); + MOCK_METHOD1(Destroy, NPError(NPSavedData**)); + MOCK_METHOD0(Release, void()); + MOCK_METHOD0(GetScriptableNPObject, NPObject*()); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_PLUGIN_OBJECT_MOCK_H_ diff --git a/o3d/gpu_plugin/np_utils/np_utils.cc b/o3d/gpu_plugin/np_utils/np_utils.cc new file mode 100644 index 0000000..d1400e6 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_utils.cc @@ -0,0 +1,170 @@ +// 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_utils.h" + +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(int32* 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; +} + +void ValueToNPVariant(bool value, NPVariant* variant) { + BOOLEAN_TO_NPVARIANT(value, *variant); +} + +void ValueToNPVariant(int32 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*>(NPBrowser::get()->MemAlloc(value.length())); + memcpy(p, value.c_str(), value.length()); + STRINGN_TO_NPVARIANT(p, value.length(), *variant); +} + +SmartNPVariant::SmartNPVariant() { + VOID_TO_NPVARIANT(*this); +} + +SmartNPVariant::SmartNPVariant(const SmartNPVariant& rhs) { + rhs.CopyTo(this); +} + +SmartNPVariant::SmartNPVariant(const NPVariant& rhs) { + static_cast<const SmartNPVariant&>(rhs).CopyTo(this); +} + +SmartNPVariant::~SmartNPVariant() { + Release(); +} + +SmartNPVariant& SmartNPVariant::operator=(const SmartNPVariant& rhs) { + Release(); + rhs.CopyTo(this); + return *this; +} + +SmartNPVariant& SmartNPVariant::operator=(const NPVariant& rhs) { + Release(); + static_cast<const SmartNPVariant&>(rhs).CopyTo(this); + return *this; +} + +bool SmartNPVariant::IsVoid() const { + return NPVARIANT_IS_VOID(*this); +} + +void SmartNPVariant::Release() { + NPBrowser::get()->ReleaseVariantValue(this); + VOID_TO_NPVARIANT(*this); +} + +void SmartNPVariant::Invalidate() { + if (NPVARIANT_IS_OBJECT(*this)) { + NULL_TO_NPVARIANT(*this); + } +} + +void SmartNPVariant::CopyTo(NPVariant* rhs) const { + if (NPVARIANT_IS_OBJECT(*this)) { + NPObject* object = NPVARIANT_TO_OBJECT(*this); + OBJECT_TO_NPVARIANT(object, *rhs); + NPBrowser::get()->RetainObject(object); + } else if (NPVARIANT_IS_STRING(*this)) { + NPUTF8* copy = static_cast<NPUTF8*>(NPBrowser::get()->MemAlloc( + value.stringValue.UTF8Length)); + memcpy(copy, + value.stringValue.UTF8Characters, + value.stringValue.UTF8Length); + STRINGN_TO_NPVARIANT(copy, value.stringValue.UTF8Length, *rhs); + } else { + memcpy(rhs, this, sizeof(*rhs)); + } +} + +bool NPHasMethod(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name) { + return NPBrowser::get()->HasMethod( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name)); +} + +bool NPHasProperty(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name) { + return NPBrowser::get()->HasProperty( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name)); +} + +bool NPRemoveProperty(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name) { + return NPBrowser::get()->RemoveProperty( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name)); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/np_utils.h b/o3d/gpu_plugin/np_utils/np_utils.h new file mode 100644 index 0000000..d5a27c5 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_utils.h @@ -0,0 +1,271 @@ +// 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_UTILS_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_NP_UTILS_H_ + +#include <string> + +#include "o3d/gpu_plugin/np_utils/np_browser.h" +#include "o3d/gpu_plugin/np_utils/np_class.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "o3d/gpu_plugin/np_utils/np_headers.h" + +namespace gpu_plugin { + +// Convert NPVariant to C++ type. Returns whether the conversion was successful. +bool NPVariantToValue(bool* value, const NPVariant& variant); +bool NPVariantToValue(int32* 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); + +template <typename T> +bool NPVariantToValue(NPObjectPointer<T>* value, + const NPVariant& variant) { + if (NPVARIANT_IS_NULL(variant)) { + *value = NPObjectPointer<T>(); + return true; + } else if (NPVARIANT_IS_OBJECT(variant)) { + NPObject* object = NPVARIANT_TO_OBJECT(variant); + if (object->_class == NPGetClass<T>()) { + *value = NPObjectPointer<T>(static_cast<T*>( + NPVARIANT_TO_OBJECT(variant))); + return true; + } + } + + return false; +} + +// Specialization for NPObject does not check for mismatched NPClass. +template <> +inline bool NPVariantToValue(NPObjectPointer<NPObject>* value, + const NPVariant& variant) { + if (NPVARIANT_IS_NULL(variant)) { + *value = NPObjectPointer<NPObject>(); + return true; + } else if (NPVARIANT_IS_OBJECT(variant)) { + *value = NPObjectPointer<NPObject>(NPVARIANT_TO_OBJECT(variant)); + return true; + } + + return false; +} + +// Convert C++ type to NPVariant. +void ValueToNPVariant(bool value, NPVariant* variant); +void ValueToNPVariant(int32 value, NPVariant* variant); +void ValueToNPVariant(float value, NPVariant* variant); +void ValueToNPVariant(double value, NPVariant* variant); +void ValueToNPVariant(const std::string& value, NPVariant* variant); + +template <typename T> +void ValueToNPVariant(const NPObjectPointer<T>& value, + NPVariant* variant) { + if (value.Get()) { + NPBrowser::get()->RetainObject(value.Get()); + OBJECT_TO_NPVARIANT(value.Get(), *variant); + } else { + NULL_TO_NPVARIANT(*variant); + } +} + +// NPVariant that automatically manages lifetime of string and object variants. +class SmartNPVariant : public NPVariant { + public: + SmartNPVariant(); + SmartNPVariant(const SmartNPVariant& rhs); + explicit SmartNPVariant(const NPVariant& rhs); + + template <typename T> + explicit SmartNPVariant(const T& v) { + ValueToNPVariant(v, this); + } + + ~SmartNPVariant(); + + SmartNPVariant& operator=(const SmartNPVariant& rhs); + SmartNPVariant& operator=(const NPVariant& rhs); + + template <typename T> + bool GetValue(T* v) const { + return NPVariantToValue(v, *this); + } + + bool IsVoid() const; + + template <typename T> + void SetValue(const T& v) { + Release(); + ValueToNPVariant(v, this); + } + + void CopyTo(NPVariant* target) const; + + // Sets the variant to void. + void Release(); + + // Called when an NPObject is invalidated to clear any references to other + // NPObjects. Does not release the object as it might no longer be valid. + void Invalidate(); +}; + +// These allow a method to be invoked with automatic conversion of C++ +// types to variants for arguments and return values. + +bool NPHasMethod(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name); + +inline bool NPInvokeVoid(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name) { + SmartNPVariant result; + return NPBrowser::get()->Invoke( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + NULL, 0, + &result); +} + +template<typename R> +bool NPInvoke(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + R* r) { + SmartNPVariant result; + if (NPBrowser::get()->Invoke( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + NULL, 0, + &result)) { + return result.GetValue(r); + } + return false; +} + +template<typename P0> +bool NPInvokeVoid(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + P0 p0) { + SmartNPVariant args[1]; + args[0].SetValue(p0); + SmartNPVariant result; + return NPBrowser::get()->Invoke( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + &args[0], 1, + &result); +} + +template<typename R, typename P0> +bool NPInvoke(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + P0 p0, + R* r) { + SmartNPVariant args[1]; + args[0].SetValue(p0); + SmartNPVariant result; + if (NPBrowser::get()->Invoke( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + &args[0], 1, + &result)) { + return result.GetValue(r); + } + return false; +} + +template<typename P0, typename P1> +bool NPInvokeVoid(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + P0 p0, P1 p1) { + SmartNPVariant args[2]; + args[0].SetValue(p0); + args[1].SetValue(p1); + SmartNPVariant result; + return NPBrowser::get()->Invoke( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + &args[0], 2, + &result); +} + +template<typename R, typename P0, typename P1> +bool NPInvoke(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + P0 p0, P1 p1, + R* r) { + SmartNPVariant args[2]; + args[0].SetValue(p0); + args[1].SetValue(p1); + SmartNPVariant result; + if (NPBrowser::get()->Invoke( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + &args[0], 2, + &result)) { + return result.GetValue(r); + } + return false; +} + +bool NPHasProperty(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name); + +template <typename T> +bool NPGetProperty(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + T* value) { + SmartNPVariant result; + if (NPBrowser::get()->GetProperty(npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + &result)) { + return result.GetValue(value); + } + return false; +} + +template <typename T> +bool NPSetProperty(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name, + const T& value) { + SmartNPVariant variant(value); + return NPBrowser::get()->SetProperty( + npp, + object.Get(), + NPBrowser::get()->GetStringIdentifier(name), + &variant); +} + +bool NPRemoveProperty(NPP npp, + const NPObjectPointer<NPObject>& object, + const NPUTF8* name); + +template <typename NPObjectType> +NPObjectPointer<NPObjectType> NPCreateObject(NPP npp) { + const NPClass* np_class = NPGetClass<NPObjectType>(); + NPObjectType* object = static_cast<NPObjectType*>( + NPBrowser::get()->CreateObject(npp, np_class)); + return NPObjectPointer<NPObjectType>::FromReturned(object); +} + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_NP_UTILS_H_ diff --git a/o3d/gpu_plugin/np_utils/np_utils_unittest.cc b/o3d/gpu_plugin/np_utils/np_utils_unittest.cc new file mode 100644 index 0000000..d281c88 --- /dev/null +++ b/o3d/gpu_plugin/np_utils/np_utils_unittest.cc @@ -0,0 +1,424 @@ +// 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_object_mock.h" +#include "o3d/gpu_plugin/np_utils/np_browser_stub.h" +#include "o3d/gpu_plugin/np_utils/np_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 gpu_plugin { + +class NPUtilsTest : public testing::Test { + protected: + StubNPBrowser stub_browser_; + NPP_t npp_; + NPVariant variant_; +}; + +TEST_F(NPUtilsTest, 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(NPUtilsTest, 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(NPUtilsTest, 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(NPUtilsTest, 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(NPUtilsTest, 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(NPUtilsTest, TestObjectNPVariantToValue) { + NPObjectPointer<NPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + NPObjectPointer<NPObject> v; + + OBJECT_TO_NPVARIANT(object.Get(), variant_); + EXPECT_TRUE(NPVariantToValue(&v, variant_)); + EXPECT_EQ(object, v); + + BOOLEAN_TO_NPVARIANT(false, variant_); + EXPECT_FALSE(NPVariantToValue(&v, variant_)); +} + +TEST_F(NPUtilsTest, TestNullNPVariantToValue) { + NPObjectPointer<NPObject> v; + + NULL_TO_NPVARIANT(variant_); + EXPECT_TRUE(NPVariantToValue(&v, variant_)); + EXPECT_TRUE(NPObjectPointer<NPObject>() == v); + + BOOLEAN_TO_NPVARIANT(false, variant_); + EXPECT_FALSE(NPVariantToValue(&v, variant_)); +} + +TEST_F(NPUtilsTest, TestDerivedObjectNPVariantToValue) { + NPObjectPointer<NPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + NPObjectPointer<StrictMock<MockNPObject> > v; + + OBJECT_TO_NPVARIANT(object.Get(), variant_); + EXPECT_TRUE(NPVariantToValue(&v, variant_)); + EXPECT_EQ(object, v); +} + +TEST_F(NPUtilsTest, + TestDerivedObjectNPVariantToValueFailsIfValueHasDifferentType) { + NPObjectPointer<NPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + NPObjectPointer<MockNPObject> v; + + OBJECT_TO_NPVARIANT(object.Get(), variant_); + EXPECT_FALSE(NPVariantToValue(&v, variant_)); +} + +TEST_F(NPUtilsTest, 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(NPUtilsTest, TestIntValueToNPVariant) { + ValueToNPVariant(7, &variant_); + EXPECT_TRUE(NPVARIANT_IS_INT32(variant_)); + EXPECT_EQ(7, NPVARIANT_TO_INT32(variant_)); +} + +TEST_F(NPUtilsTest, TestFloatValueToNPVariant) { + ValueToNPVariant(7.0f, &variant_); + EXPECT_TRUE(NPVARIANT_IS_DOUBLE(variant_)); + EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(variant_)); +} + +TEST_F(NPUtilsTest, TestDoubleValueToNPVariant) { + ValueToNPVariant(7.0, &variant_); + EXPECT_TRUE(NPVARIANT_IS_DOUBLE(variant_)); + EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(variant_)); +} + +TEST_F(NPUtilsTest, 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(NPUtilsTest, TestObjectValueToNPVariant) { + NPObjectPointer<NPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + ValueToNPVariant(object, &variant_); + EXPECT_TRUE(NPVARIANT_IS_OBJECT(variant_)); + EXPECT_EQ(object.Get(), NPVARIANT_TO_OBJECT(variant_)); + + NPBrowser::get()->ReleaseVariantValue(&variant_); +} + +TEST_F(NPUtilsTest, TestNullValueToNPVariant) { + ValueToNPVariant(NPObjectPointer<NPObject>(), &variant_); + EXPECT_TRUE(NPVARIANT_IS_NULL(variant_)); +} + +TEST_F(NPUtilsTest, CanCopyObjectSmartVariant) { + NPObjectPointer<NPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + EXPECT_EQ(1, object->referenceCount); + { + SmartNPVariant v1(object); + EXPECT_EQ(2, object->referenceCount); + { + SmartNPVariant v2(v1); + EXPECT_EQ(3, object->referenceCount); + } + EXPECT_EQ(2, object->referenceCount); + } + EXPECT_EQ(1, object->referenceCount); +} + +TEST_F(NPUtilsTest, CanCopyStringSmartVariant) { + SmartNPVariant v1(std::string("hello")); + SmartNPVariant v2(v1); + std::string r; + EXPECT_TRUE(NPVariantToValue(&r, v2)); + EXPECT_EQ(std::string("hello"), r); + EXPECT_NE(v1.value.stringValue.UTF8Characters, + v2.value.stringValue.UTF8Characters); +} + +TEST_F(NPUtilsTest, CanReleaseSmartVariant) { + SmartNPVariant variant(std::string("hello")); + EXPECT_FALSE(variant.IsVoid()); + variant.Release(); + EXPECT_TRUE(variant.IsVoid()); +} + +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(NPUtilsTest, CanDetermineIfObjectHasMethod) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + EXPECT_CALL(*object, HasMethod(name)) + .WillOnce(Return(true)); + + EXPECT_TRUE(NPHasMethod(NULL, object, "foo")); +} + +TEST_F(NPUtilsTest, CanInvokeVoidMethodWithNativeTypes) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + VOID_TO_NPVARIANT(variant_); + + EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _)) + .WillOnce(DoAll(SetArgumentPointee<3>(variant_), + Return(true))); + + EXPECT_TRUE(NPInvokeVoid(NULL, object, "foo", 7)); +} + +TEST_F(NPUtilsTest, InvokeVoidMethodCanFail) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + VOID_TO_NPVARIANT(variant_); + + EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _)) + .WillOnce(DoAll(SetArgumentPointee<3>(variant_), + Return(false))); + + EXPECT_FALSE(NPInvokeVoid(NULL, object, "foo", 7)); +} + +TEST_F(NPUtilsTest, CanInvokeNonVoidMethodWithNativeTypes) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + DOUBLE_TO_NPVARIANT(1.5, variant_); + + EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _)) + .WillOnce(DoAll(SetArgumentPointee<3>(variant_), + Return(true))); + + double r; + EXPECT_TRUE(NPInvoke(NULL, object, "foo", 7, &r)); + EXPECT_EQ(1.5, r); +} + +TEST_F(NPUtilsTest, InvokeNonVoidMethodCanFail) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + DOUBLE_TO_NPVARIANT(1.5, variant_); + + EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _)) + .WillOnce(DoAll(SetArgumentPointee<3>(variant_), + Return(false))); + + double r; + EXPECT_FALSE(NPInvoke(NULL, object, "foo", 7, &r)); +} + +TEST_F(NPUtilsTest, InvokeNonVoidMethodFailsIfResultIsIncompatible) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + DOUBLE_TO_NPVARIANT(1.5, variant_); + + EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _)) + .WillOnce(DoAll(SetArgumentPointee<3>(variant_), + Return(true))); + + int r; + EXPECT_FALSE(NPInvoke(NULL, object, "foo", 7, &r)); +} + +TEST_F(NPUtilsTest, CanDetermineIfObjectHasProperty) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + EXPECT_CALL(*object, HasProperty(name)) + .WillOnce(Return(true)); + + EXPECT_TRUE(NPHasProperty(NULL, object, "foo")); +} + +TEST_F(NPUtilsTest, CanGetPropertyValue) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + DOUBLE_TO_NPVARIANT(1.5, variant_); + + EXPECT_CALL(*object, GetProperty(name, _)) + .WillOnce(DoAll(SetArgumentPointee<1>(variant_), + Return(true))); + + double r; + EXPECT_TRUE(NPGetProperty(NULL, object, "foo", &r)); +} + +TEST_F(NPUtilsTest, NPGetPropertyReportsFailureIfResultTypeIsDifferent) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + DOUBLE_TO_NPVARIANT(1.5, variant_); + + EXPECT_CALL(*object, GetProperty(name, _)) + .WillOnce(DoAll(SetArgumentPointee<1>(variant_), + Return(true))); + + bool r; + EXPECT_FALSE(NPGetProperty(NULL, object, "foo", &r)); +} + +TEST_F(NPUtilsTest, NPGetPropertyReportsFailureFromGetProperty) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + EXPECT_CALL(*object, GetProperty(name, _)) + .WillOnce(Return(false)); + + double r; + EXPECT_FALSE(NPGetProperty(NULL, object, "foo", &r)); +} + +TEST_F(NPUtilsTest, CanSetPropertyValue) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + EXPECT_CALL(*object, SetProperty(name, Pointee(VariantMatches(1.5)))) + .WillOnce(Return(true)); + + EXPECT_TRUE(NPSetProperty(NULL, object, "foo", 1.5)); +} + +TEST_F(NPUtilsTest, NPSetPropertyReportsFailureFromSetProperty) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + EXPECT_CALL(*object, SetProperty(name, Pointee(VariantMatches(1.5)))) + .WillOnce(Return(false)); + + EXPECT_FALSE(NPSetProperty(NULL, object, "foo", 1.5)); +} + +TEST_F(NPUtilsTest, CanRemovePropertyValue) { + NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo"); + NPObjectPointer<MockNPObject> object = + NPCreateObject<StrictMock<MockNPObject> >(NULL); + + EXPECT_CALL(*object, RemoveProperty(name)) + .WillOnce(Return(true)); + + EXPECT_TRUE(NPRemoveProperty(NULL, object, "foo")); +} + +} // namespace gpu_plugin diff --git a/o3d/gpu_plugin/np_utils/webkit_browser.h b/o3d/gpu_plugin/np_utils/webkit_browser.h new file mode 100644 index 0000000..e45e65f --- /dev/null +++ b/o3d/gpu_plugin/np_utils/webkit_browser.h @@ -0,0 +1,117 @@ +// 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_WEBKIT_BROWSER_H_ +#define O3D_GPU_PLUGIN_NP_UTILS_WEBKIT_BROWSER_H_ + +// TODO(apatrick): This does not belong in np_utils. np_utils should not be +// dependent on WebKit (and it isn't - that's why the member functions are +// inline). + +#include <stdlib.h> + +#include "o3d/gpu_plugin/np_utils/np_browser.h" +#include "WebKit/api/public/WebBindings.h" + +typedef struct _NPNetscapeFuncs NPNetscapeFuncs; +typedef struct _NPChromiumFuncs NPChromiumFuncs; + +namespace gpu_plugin { + +// This class implements NPBrowser for the WebKit WebBindings. +class WebKitBrowser : public NPBrowser { + public: + WebKitBrowser(): NPBrowser(NULL) { + } + + // Standard functions from NPNetscapeFuncs. + + virtual NPIdentifier GetStringIdentifier(const NPUTF8* name) { + return WebKit::WebBindings::getStringIdentifier(name); + } + + virtual void* MemAlloc(size_t size) { + return malloc(size); + } + + virtual void MemFree(void* p) { + free(p); + } + + virtual NPObject* CreateObject(NPP npp, const NPClass* cl) { + return WebKit::WebBindings::createObject(npp, const_cast<NPClass*>(cl)); + } + + virtual NPObject* RetainObject(NPObject* object) { + return WebKit::WebBindings::retainObject(object); + } + + virtual void ReleaseObject(NPObject* object) { + WebKit::WebBindings::releaseObject(object); + } + + virtual void ReleaseVariantValue(NPVariant* variant) { + WebKit::WebBindings::releaseVariantValue(variant); + } + + virtual bool HasProperty(NPP npp, + NPObject* object, + NPIdentifier name) { + return WebKit::WebBindings::hasProperty(npp, object, name); + } + + virtual bool GetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + NPVariant* result) { + return WebKit::WebBindings::getProperty(npp, object, name, result); + } + + virtual bool SetProperty(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* result) { + return WebKit::WebBindings::setProperty(npp, object, name, result); + } + + virtual bool RemoveProperty(NPP npp, + NPObject* object, + NPIdentifier name) { + return WebKit::WebBindings::removeProperty(npp, object, name); + } + + virtual bool HasMethod(NPP npp, + NPObject* object, + NPIdentifier name) { + return WebKit::WebBindings::hasMethod(npp, object, name); + } + + virtual bool Invoke(NPP npp, + NPObject* object, + NPIdentifier name, + const NPVariant* args, + uint32_t num_args, + NPVariant* result) { + return WebKit::WebBindings::invoke(npp, object, name, args, num_args, + result); + } + + virtual NPObject* GetWindowNPObject(NPP npp) { + NPObject* window; + if (NPERR_NO_ERROR == NPN_GetValue(npp, + NPNVWindowNPObject, + &window)) { + return window; + } else { + return NULL; + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(WebKitBrowser); +}; + +} // namespace gpu_plugin + +#endif // O3D_GPU_PLUGIN_NP_UTILS_WEBKIT_BROWSER_H_ |