summaryrefslogtreecommitdiffstats
path: root/o3d/gpu_plugin
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-11 18:48:49 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-11 18:48:49 +0000
commit85c5b0230b1a9a9d8e02ad6049c31bf55eb5c076 (patch)
treea4d8ddd09d0beeffa01b2ad9222698cd914b4717 /o3d/gpu_plugin
parent5222bb1495ef2e9a6294da8a8f1b9c1dae2e54e4 (diff)
downloadchromium_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')
-rw-r--r--o3d/gpu_plugin/command_buffer.cc143
-rw-r--r--o3d/gpu_plugin/command_buffer.h130
-rw-r--r--o3d/gpu_plugin/command_buffer_mock.h42
-rw-r--r--o3d/gpu_plugin/command_buffer_unittest.cc182
-rw-r--r--o3d/gpu_plugin/gpu_plugin.cc136
-rw-r--r--o3d/gpu_plugin/gpu_plugin.gyp162
-rw-r--r--o3d/gpu_plugin/gpu_plugin.h30
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object.cc117
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object.h132
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_factory.cc27
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_factory.h26
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_factory_unittest.cc39
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_unittest.cc346
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_win.cc62
-rw-r--r--o3d/gpu_plugin/gpu_plugin_unittest.cc305
-rw-r--r--o3d/gpu_plugin/gpu_processor.cc80
-rw-r--r--o3d/gpu_plugin/gpu_processor.h119
-rw-r--r--o3d/gpu_plugin/gpu_processor_mock.h41
-rw-r--r--o3d/gpu_plugin/gpu_processor_unittest.cc309
-rw-r--r--o3d/gpu_plugin/gpu_processor_win.cc85
-rw-r--r--o3d/gpu_plugin/np_utils/default_np_object.h84
-rw-r--r--o3d/gpu_plugin/np_utils/dispatched_np_object_unittest.cc403
-rw-r--r--o3d/gpu_plugin/np_utils/dynamic_np_object.cc59
-rw-r--r--o3d/gpu_plugin/np_utils/dynamic_np_object.h35
-rw-r--r--o3d/gpu_plugin/np_utils/dynamic_np_object_unittest.cc83
-rw-r--r--o3d/gpu_plugin/np_utils/np_browser.cc128
-rw-r--r--o3d/gpu_plugin/np_utils/np_browser.h95
-rw-r--r--o3d/gpu_plugin/np_utils/np_browser_mock.h50
-rw-r--r--o3d/gpu_plugin/np_utils/np_browser_stub.cc125
-rw-r--r--o3d/gpu_plugin/np_utils/np_browser_stub.h84
-rw-r--r--o3d/gpu_plugin/np_utils/np_class.h125
-rw-r--r--o3d/gpu_plugin/np_utils/np_class_unittest.cc143
-rw-r--r--o3d/gpu_plugin/np_utils/np_dispatcher.cc85
-rw-r--r--o3d/gpu_plugin/np_utils/np_dispatcher.h222
-rw-r--r--o3d/gpu_plugin/np_utils/np_dispatcher_specializations.h85
-rw-r--r--o3d/gpu_plugin/np_utils/np_headers.h16
-rw-r--r--o3d/gpu_plugin/np_utils/np_object_mock.h36
-rw-r--r--o3d/gpu_plugin/np_utils/np_object_pointer.h119
-rw-r--r--o3d/gpu_plugin/np_utils/np_object_pointer_unittest.cc220
-rw-r--r--o3d/gpu_plugin/np_utils/np_plugin_object.h50
-rw-r--r--o3d/gpu_plugin/np_utils/np_plugin_object_factory.cc30
-rw-r--r--o3d/gpu_plugin/np_utils/np_plugin_object_factory.h37
-rw-r--r--o3d/gpu_plugin/np_utils/np_plugin_object_factory_mock.h23
-rw-r--r--o3d/gpu_plugin/np_utils/np_plugin_object_mock.h26
-rw-r--r--o3d/gpu_plugin/np_utils/np_utils.cc170
-rw-r--r--o3d/gpu_plugin/np_utils/np_utils.h271
-rw-r--r--o3d/gpu_plugin/np_utils/np_utils_unittest.cc424
-rw-r--r--o3d/gpu_plugin/np_utils/webkit_browser.h117
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_