summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/browser_main_loop.cc6
-rw-r--r--content/browser/gamepad/gamepad_data_fetcher.h (renamed from content/browser/gamepad/data_fetcher.h)10
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher.cc (renamed from content/browser/gamepad/platform_data_fetcher.cc)4
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher.h (renamed from content/browser/gamepad/platform_data_fetcher.h)14
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc (renamed from content/browser/gamepad/platform_data_fetcher_linux.cc)2
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_linux.h (renamed from content/browser/gamepad/platform_data_fetcher_linux.h)8
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_mac.h (renamed from content/browser/gamepad/platform_data_fetcher_mac.h)8
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm (renamed from content/browser/gamepad/platform_data_fetcher_mac.mm)2
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_win.cc (renamed from content/browser/gamepad/platform_data_fetcher_win.cc)2
-rw-r--r--content/browser/gamepad/gamepad_platform_data_fetcher_win.h (renamed from content/browser/gamepad/platform_data_fetcher_win.h)8
-rw-r--r--content/browser/gamepad/gamepad_provider.cc101
-rw-r--r--content/browser/gamepad/gamepad_provider.h46
-rw-r--r--content/browser/gamepad/gamepad_provider_unittest.cc109
-rw-r--r--content/browser/gamepad/gamepad_service.cc82
-rw-r--r--content/browser/gamepad/gamepad_service.h72
-rw-r--r--content/browser/gamepad/gamepad_test_helpers.cc60
-rw-r--r--content/browser/gamepad/gamepad_test_helpers.h90
-rw-r--r--content/browser/ppapi_plugin_process_host.cc4
-rw-r--r--content/browser/renderer_host/gamepad_browser_message_filter.cc26
-rw-r--r--content/browser/renderer_host/gamepad_browser_message_filter.h7
-rw-r--r--content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc9
-rw-r--r--content/browser/renderer_host/pepper/browser_ppapi_host_impl.h17
-rw-r--r--content/browser/renderer_host/pepper/browser_ppapi_host_test.cc27
-rw-r--r--content/browser/renderer_host/pepper/browser_ppapi_host_test.h37
-rw-r--r--content/browser/renderer_host/pepper/pepper_gamepad_host.cc52
-rw-r--r--content/browser/renderer_host/pepper/pepper_gamepad_host.h24
-rw-r--r--content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc204
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc2
-rw-r--r--content/common/gamepad_hardware_buffer.h2
-rw-r--r--content/common/gamepad_user_gesture.cc33
-rw-r--r--content/common/gamepad_user_gesture.h20
-rw-r--r--content/content_browser.gypi16
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/content_tests.gypi9
-rw-r--r--content/ppapi_plugin/ppapi_thread.cc9
-rw-r--r--content/ppapi_plugin/ppapi_thread.h3
-rw-r--r--content/public/browser/browser_ppapi_host.h8
-rw-r--r--content/renderer/gamepad_shared_memory_reader.cc46
-rw-r--r--content/renderer/gamepad_shared_memory_reader.h2
-rw-r--r--content/renderer/pepper/pepper_file_chooser_host.cc4
-rw-r--r--ppapi/examples/gamepad/gamepad.cc2
-rw-r--r--ppapi/host/dispatch_host_message.h7
-rw-r--r--ppapi/host/host_message_context.cc24
-rw-r--r--ppapi/host/host_message_context.h10
-rw-r--r--ppapi/host/ppapi_host.cc3
-rw-r--r--ppapi/host/ppapi_host.h2
-rw-r--r--ppapi/host/resource_host.h4
-rw-r--r--ppapi/ppapi_host.gypi1
-rw-r--r--ppapi/ppapi_shared.gypi2
-rw-r--r--ppapi/proxy/dispatch_reply_message.h25
-rw-r--r--ppapi/proxy/gamepad_resource.cc87
-rw-r--r--ppapi/proxy/gamepad_resource.h10
-rw-r--r--ppapi/proxy/plugin_dispatcher.cc21
-rw-r--r--ppapi/proxy/plugin_dispatcher.h7
-rw-r--r--ppapi/proxy/ppapi_messages.h10
-rw-r--r--ppapi/proxy/resource_message_params.cc41
-rw-r--r--ppapi/proxy/resource_message_params.h35
-rw-r--r--ppapi/shared_impl/ppapi_permissions.cc8
-rw-r--r--ppapi/shared_impl/ppapi_permissions.h6
-rw-r--r--ppapi/shared_impl/ppb_gamepad_shared.cc37
-rw-r--r--ppapi/shared_impl/ppb_gamepad_shared.h78
-rw-r--r--webkit/plugins/ppapi/event_conversion.cc26
-rw-r--r--webkit/plugins/ppapi/event_conversion.h6
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.cc4
64 files changed, 1323 insertions, 320 deletions
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index faed5fc..80d34b3 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -505,8 +505,6 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
#endif
BrowserGpuChannelHostFactory::Terminate();
- GamepadService::GetInstance()->Terminate();
-
// The device monitors are using |system_monitor_| as dependency, so delete
// them before |system_monitor_| goes away.
// On Mac and windows, the monitor needs to be destroyed on the same thread
@@ -606,6 +604,10 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
// more head start for those operations to finish.
BrowserThreadImpl::ShutdownThreadPool();
+ // Must happen after the I/O thread is shutdown since this class lives on the
+ // I/O thread and isn't threadsafe.
+ GamepadService::GetInstance()->Terminate();
+
if (parts_.get())
parts_->PostDestroyThreads();
}
diff --git a/content/browser/gamepad/data_fetcher.h b/content/browser/gamepad/gamepad_data_fetcher.h
index 94bf4ae..e5e009d 100644
--- a/content/browser/gamepad/data_fetcher.h
+++ b/content/browser/gamepad/gamepad_data_fetcher.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_DATA_FETCHER_H_
-#define CONTENT_BROWSER_GAMEPAD_DATA_FETCHER_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_DATA_FETCHER_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_DATA_FETCHER_H_
namespace WebKit {
class WebGamepads;
@@ -11,6 +11,8 @@ class WebGamepads;
namespace content {
+// Abstract interface for imlementing platform- (and test-) specific behaviro
+// for getting the gamepad data.
class GamepadDataFetcher {
public:
virtual ~GamepadDataFetcher() {}
@@ -19,6 +21,6 @@ class GamepadDataFetcher {
virtual void PauseHint(bool paused) {}
};
-} // namespace content
+} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_DATA_FETCHER_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_DATA_FETCHER_H_
diff --git a/content/browser/gamepad/platform_data_fetcher.cc b/content/browser/gamepad/gamepad_platform_data_fetcher.cc
index 1e80174..d14a3ca 100644
--- a/content/browser/gamepad/platform_data_fetcher.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
@@ -16,4 +16,4 @@ void GamepadDataFetcherEmpty::GetGamepadData(WebKit::WebGamepads* pads,
pads->length = 0;
}
-} // content
+} // namespace content
diff --git a/content/browser/gamepad/platform_data_fetcher.h b/content/browser/gamepad/gamepad_platform_data_fetcher.h
index 178e478..f073a53 100644
--- a/content/browser/gamepad/platform_data_fetcher.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher.h
@@ -5,19 +5,19 @@
// Define the default data fetcher that GamepadProvider will use if none is
// supplied. (GamepadPlatformDataFetcher).
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#if defined(OS_WIN)
-#include "content/browser/gamepad/platform_data_fetcher_win.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
#elif defined(OS_MACOSX)
-#include "content/browser/gamepad/platform_data_fetcher_mac.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h"
#elif defined(OS_LINUX)
-#include "content/browser/gamepad/platform_data_fetcher_linux.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h"
#endif
namespace content {
@@ -52,4 +52,4 @@ typedef GamepadDataFetcherEmpty GamepadPlatformDataFetcher;
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_H_
diff --git a/content/browser/gamepad/platform_data_fetcher_linux.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
index e364eac..0342917 100644
--- a/content/browser/gamepad/platform_data_fetcher_linux.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher_linux.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h"
#include <fcntl.h>
#include <libudev.h>
diff --git a/content/browser/gamepad/platform_data_fetcher_linux.h b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
index 55cb74e..681946f 100644
--- a/content/browser/gamepad/platform_data_fetcher_linux.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
#include <string>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
@@ -53,4 +53,4 @@ class GamepadPlatformDataFetcherLinux : public GamepadDataFetcher {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_LINUX_H_
diff --git a/content/browser/gamepad/platform_data_fetcher_mac.h b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
index c92307d..8bcc9c2 100644
--- a/content/browser/gamepad/platform_data_fetcher_mac.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/mac/scoped_cftyperef.h"
#include "build/build_config.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "content/common/gamepad_hardware_buffer.h"
@@ -79,4 +79,4 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_MAC_H_
diff --git a/content/browser/gamepad/platform_data_fetcher_mac.mm b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
index 1d1bd72..8748730 100644
--- a/content/browser/gamepad/platform_data_fetcher_mac.mm
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher_mac.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h"
#include "base/mac/foundation_util.h"
#include "base/memory/scoped_nsobject.h"
diff --git a/content/browser/gamepad/platform_data_fetcher_win.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
index 92587a4..838a626 100644
--- a/content/browser/gamepad/platform_data_fetcher_win.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/gamepad/platform_data_fetcher_win.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
#include "base/debug/trace_event.h"
#include "content/common/gamepad_messages.h"
diff --git a/content/browser/gamepad/platform_data_fetcher_win.h b/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
index 9cae9cc..92c44ff 100644
--- a/content/browser/gamepad/platform_data_fetcher_win.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
-#define CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
#include "build/build_config.h"
@@ -16,7 +16,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/scoped_native_library.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
namespace content {
@@ -54,4 +54,4 @@ class GamepadPlatformDataFetcherWin : public GamepadDataFetcher {
} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_WIN_H_
diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
index 507c704..63a352f 100644
--- a/content/browser/gamepad/gamepad_provider.cc
+++ b/content/browser/gamepad/gamepad_provider.cc
@@ -9,42 +9,41 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
-#include "content/browser/gamepad/platform_data_fetcher.h"
+#include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_messages.h"
+#include "content/common/gamepad_user_gesture.h"
#include "content/public/browser/browser_thread.h"
namespace content {
+GamepadProvider::ClosureAndThread::ClosureAndThread(
+ const base::Closure& c,
+ const scoped_refptr<base::MessageLoopProxy>& m)
+ : closure(c),
+ message_loop(m) {
+}
+
+GamepadProvider::ClosureAndThread::~ClosureAndThread() {
+}
+
GamepadProvider::GamepadProvider()
: is_paused_(true),
have_scheduled_do_poll_(false),
devices_changed_(true) {
- size_t data_size = sizeof(GamepadHardwareBuffer);
- base::SystemMonitor* monitor = base::SystemMonitor::Get();
- if (monitor)
- monitor->AddDevicesChangedObserver(this);
- bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
- CHECK(res);
- GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
- memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
-
- polling_thread_.reset(new base::Thread("Gamepad polling thread"));
- polling_thread_->StartWithOptions(
- base::Thread::Options(MessageLoop::TYPE_IO, 0));
+ Initialize(scoped_ptr<GamepadDataFetcher>());
}
-void GamepadProvider::SetDataFetcher(GamepadDataFetcher* fetcher) {
- MessageLoop* polling_loop = polling_thread_->message_loop();
- polling_loop->PostTask(
- FROM_HERE,
- base::Bind(&GamepadProvider::DoInitializePollingThread,
- Unretained(this),
- fetcher));
+GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher)
+ : is_paused_(true),
+ have_scheduled_do_poll_(false),
+ devices_changed_(true) {
+ Initialize(fetcher.Pass());
}
GamepadProvider::~GamepadProvider() {
@@ -56,7 +55,7 @@ GamepadProvider::~GamepadProvider() {
data_fetcher_.reset();
}
-base::SharedMemoryHandle GamepadProvider::GetRendererSharedMemoryHandle(
+base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
base::ProcessHandle process) {
base::SharedMemoryHandle renderer_handle;
gamepad_shared_memory_.ShareToProcess(process, &renderer_handle);
@@ -91,24 +90,46 @@ void GamepadProvider::Resume() {
base::Bind(&GamepadProvider::ScheduleDoPoll, Unretained(this)));
}
+void GamepadProvider::RegisterForUserGesture(const base::Closure& closure) {
+ base::AutoLock lock(user_gesture_lock_);
+ user_gesture_observers_.push_back(
+ ClosureAndThread(closure, MessageLoop::current()->message_loop_proxy()));
+}
+
void GamepadProvider::OnDevicesChanged(base::SystemMonitor::DeviceType type) {
base::AutoLock lock(devices_changed_lock_);
devices_changed_ = true;
}
-void GamepadProvider::DoInitializePollingThread(GamepadDataFetcher* fetcher) {
- DCHECK(MessageLoop::current() == polling_thread_->message_loop());
+void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
+ size_t data_size = sizeof(GamepadHardwareBuffer);
+ base::SystemMonitor* monitor = base::SystemMonitor::Get();
+ if (monitor)
+ monitor->AddDevicesChangedObserver(this);
+ bool res = gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
+ CHECK(res);
+ GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
+ memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
- if (data_fetcher_ != NULL) {
- // Already initialized.
- return;
- }
+ polling_thread_.reset(new base::Thread("Gamepad polling thread"));
+ polling_thread_->StartWithOptions(
+ base::Thread::Options(MessageLoop::TYPE_IO, 0));
+
+ polling_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&GamepadProvider::DoInitializePollingThread,
+ base::Unretained(this),
+ base::Passed(&fetcher)));
+}
- if (fetcher == NULL)
- fetcher = new GamepadPlatformDataFetcher;
+void GamepadProvider::DoInitializePollingThread(
+ scoped_ptr<GamepadDataFetcher> fetcher) {
+ DCHECK(MessageLoop::current() == polling_thread_->message_loop());
+ DCHECK(!data_fetcher_.get()); // Should only initialize once.
- // Pass ownership of fetcher to provider_.
- data_fetcher_.reset(fetcher);
+ if (!fetcher.get())
+ fetcher.reset(new GamepadPlatformDataFetcher);
+ data_fetcher_ = fetcher.Pass();
}
void GamepadProvider::SendPauseHint(bool paused) {
@@ -142,6 +163,8 @@ void GamepadProvider::DoPoll() {
data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
hwbuf->sequence.WriteEnd();
+ CheckForUserGesture();
+
// Schedule our next interval of polling.
ScheduleDoPoll();
}
@@ -170,4 +193,18 @@ GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
return static_cast<GamepadHardwareBuffer*>(mem);
}
+void GamepadProvider::CheckForUserGesture() {
+ base::AutoLock lock(user_gesture_lock_);
+ if (user_gesture_observers_.empty())
+ return; // Don't need to check if nobody is listening.
+
+ if (GamepadsHaveUserGesture(SharedMemoryAsHardwareBuffer()->buffer)) {
+ for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
+ user_gesture_observers_[i].message_loop->PostTask(FROM_HERE,
+ user_gesture_observers_[i].closure);
+ }
+ user_gesture_observers_.clear();
+ }
+}
+
} // namespace content
diff --git a/content/browser/gamepad/gamepad_provider.h b/content/browser/gamepad/gamepad_provider.h
index 22c39c5..c4a7806 100644
--- a/content/browser/gamepad/gamepad_provider.h
+++ b/content/browser/gamepad/gamepad_provider.h
@@ -5,6 +5,11 @@
#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PROVIDER_H_
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PROVIDER_H_
+#include <utility>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop_proxy.h"
@@ -14,6 +19,7 @@
#include "content/common/content_export.h"
namespace base {
+class MessageLoopProxy;
class Thread;
}
@@ -25,13 +31,16 @@ struct GamepadHardwareBuffer;
class CONTENT_EXPORT GamepadProvider :
public base::SystemMonitor::DevicesChangedObserver {
public:
- explicit GamepadProvider();
- virtual ~GamepadProvider();
+ GamepadProvider();
- // Set the platform-specific data fetcher. Mostly used for testing.
- void SetDataFetcher(GamepadDataFetcher* fetcher);
+ // Manually specifies the data fetcher. Used for testing.
+ explicit GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher);
+
+ virtual ~GamepadProvider();
- base::SharedMemoryHandle GetRendererSharedMemoryHandle(
+ // Returns the shared memory handle of the gamepad data duplicated into the
+ // given process.
+ base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
base::ProcessHandle renderer_process);
// Pause and resume the background polling thread. Can be called from any
@@ -39,14 +48,19 @@ class CONTENT_EXPORT GamepadProvider :
void Pause();
void Resume();
+ // Registers the given closure for calling when the user has interacted with
+ // the device. This callback will only be issued once.
+ void RegisterForUserGesture(const base::Closure& closure);
+
// base::SystemMonitor::DevicesChangedObserver implementation.
virtual void OnDevicesChanged(base::SystemMonitor::DeviceType type) OVERRIDE;
private:
+ void Initialize(scoped_ptr<GamepadDataFetcher> fetcher);
// Method for setting up the platform-specific data fetcher. Takes ownership
// of |fetcher|.
- void DoInitializePollingThread(GamepadDataFetcher* fetcher);
+ void DoInitializePollingThread(scoped_ptr<GamepadDataFetcher> fetcher);
// Method for sending pause hints to the low-level data fetcher. Runs on
// polling_thread_.
@@ -58,6 +72,9 @@ class CONTENT_EXPORT GamepadProvider :
GamepadHardwareBuffer* SharedMemoryAsHardwareBuffer();
+ // Checks the gamepad state to see if the user has interacted with it.
+ void CheckForUserGesture();
+
enum { kDesiredSamplingIntervalMs = 16 };
// Keeps track of when the background thread is paused. Access to is_paused_
@@ -70,6 +87,23 @@ class CONTENT_EXPORT GamepadProvider :
// |is_paused_|.
bool have_scheduled_do_poll_;
+ // Lists all observers registered for user gestures, and the thread which
+ // to issue the callbacks on. Since we always issue the callback on the
+ // thread which the registration happened, and this class lives on the I/O
+ // thread, the message loop proxies will normally just be the I/O thread.
+ // However, this will be the main thread for unit testing.
+ base::Lock user_gesture_lock_;
+ struct ClosureAndThread {
+ ClosureAndThread(const base::Closure& c,
+ const scoped_refptr<base::MessageLoopProxy>& m);
+ ~ClosureAndThread();
+
+ base::Closure closure;
+ scoped_refptr<base::MessageLoopProxy> message_loop;
+ };
+ typedef std::vector<ClosureAndThread> UserGestureObserverVector;
+ UserGestureObserverVector user_gesture_observers_;
+
// Updated based on notification from SystemMonitor when the system devices
// have been updated, and this notification is passed on to the data fetcher
// to enable it to avoid redundant (and possibly expensive) is-connected
diff --git a/content/browser/gamepad/gamepad_provider_unittest.cc b/content/browser/gamepad/gamepad_provider_unittest.cc
index d81b3f5..30f5e43 100644
--- a/content/browser/gamepad/gamepad_provider_unittest.cc
+++ b/content/browser/gamepad/gamepad_provider_unittest.cc
@@ -3,15 +3,14 @@
// found in the LICENSE file.
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/process_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/system_monitor/system_monitor.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
+#include "content/browser/gamepad/gamepad_test_helpers.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "content/common/gamepad_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
namespace content {
@@ -19,35 +18,37 @@ namespace {
using WebKit::WebGamepads;
-class MockDataFetcher : public GamepadDataFetcher {
+// Helper class to generate and record user gesture callbacks.
+class UserGestureListener {
public:
- explicit MockDataFetcher(const WebGamepads& test_data)
- : test_data_(test_data),
- read_data_(false, false) {
+ UserGestureListener()
+ : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ has_user_gesture_(false) {
}
- virtual void GetGamepadData(WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE {
- *pads = test_data_;
- read_data_.Signal();
+
+ base::Closure GetClosure() {
+ return base::Bind(&UserGestureListener::GotUserGesture,
+ weak_factory_.GetWeakPtr());
}
- void WaitForDataRead() { return read_data_.Wait(); }
+ bool has_user_gesture() const { return has_user_gesture_; }
+
+ private:
+ void GotUserGesture() {
+ has_user_gesture_ = true;
+ }
- WebGamepads test_data_;
- base::WaitableEvent read_data_;
+ base::WeakPtrFactory<UserGestureListener> weak_factory_;
+ bool has_user_gesture_;
};
// Main test fixture
-class GamepadProviderTest : public testing::Test {
+class GamepadProviderTest : public testing::Test, public GamepadTestHelper {
public:
GamepadProvider* CreateProvider(const WebGamepads& test_data) {
-#if defined(OS_MACOSX)
- base::SystemMonitor::AllocateSystemIOPorts();
-#endif
- system_monitor_.reset(new base::SystemMonitor);
- mock_data_fetcher_ = new MockDataFetcher(test_data);
- provider_.reset(new GamepadProvider);
- provider_->SetDataFetcher(mock_data_fetcher_);
+ mock_data_fetcher_ = new MockGamepadDataFetcher(test_data);
+ provider_.reset(new GamepadProvider(
+ scoped_ptr<GamepadDataFetcher>(mock_data_fetcher_)));
return provider_.get();
}
@@ -55,14 +56,16 @@ class GamepadProviderTest : public testing::Test {
GamepadProviderTest() {
}
- MessageLoop main_message_loop_;
- scoped_ptr<base::SystemMonitor> system_monitor_;
- MockDataFetcher* mock_data_fetcher_;
scoped_ptr<GamepadProvider> provider_;
+
+ // Pointer owned by the provider.
+ MockGamepadDataFetcher* mock_data_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadProviderTest);
};
// Crashes. http://crbug.com/106163
-TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
+TEST_F(GamepadProviderTest, PollingAccess) {
WebGamepads test_data;
test_data.length = 1;
test_data.items[0].connected = true;
@@ -74,14 +77,15 @@ TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
test_data.items[0].axes[1] = .5f;
GamepadProvider* provider = CreateProvider(test_data);
+ provider->Resume();
- main_message_loop_.RunAllPending();
+ message_loop().RunAllPending();
mock_data_fetcher_->WaitForDataRead();
// Renderer-side, pull data out of poll buffer.
- base::SharedMemoryHandle handle =
- provider->GetRendererSharedMemoryHandle(base::GetCurrentProcessHandle());
+ base::SharedMemoryHandle handle = provider->GetSharedMemoryHandleForProcess(
+ base::GetCurrentProcessHandle());
scoped_ptr<base::SharedMemory> shared_memory(
new base::SharedMemory(handle, true));
EXPECT_TRUE(shared_memory->Map(sizeof(GamepadHardwareBuffer)));
@@ -105,6 +109,51 @@ TEST_F(GamepadProviderTest, DISABLED_PollingAccess) {
EXPECT_EQ(0.5f, output.items[0].axes[1]);
}
+// Tests that waiting for a user gesture works properly.
+TEST_F(GamepadProviderTest, UserGesture) {
+ WebGamepads no_button_data;
+ no_button_data.length = 1;
+ no_button_data.items[0].connected = true;
+ no_button_data.items[0].timestamp = 0;
+ no_button_data.items[0].buttonsLength = 1;
+ no_button_data.items[0].axesLength = 2;
+ no_button_data.items[0].buttons[0] = 0.f;
+ no_button_data.items[0].axes[0] = -1.f;
+ no_button_data.items[0].axes[1] = .5f;
+
+ WebGamepads button_down_data = no_button_data;
+ button_down_data.items[0].buttons[0] = 1.f;
+
+ UserGestureListener listener;
+ GamepadProvider* provider = CreateProvider(no_button_data);
+ provider->Resume();
+
+ // Register for a user gesture and make sure the provider reads it twice
+ // see below for why).
+ provider->RegisterForUserGesture(listener.GetClosure());
+ mock_data_fetcher_->WaitForDataRead();
+ mock_data_fetcher_->WaitForDataRead();
+
+ // It should not have issued our callback.
+ message_loop().RunAllPending();
+ EXPECT_FALSE(listener.has_user_gesture());
+
+ // Set a button down and wait for it to be read twice.
+ //
+ // We wait for two reads before calling RunAllPending because the provider
+ // will read the data on the background thread (setting the event) and *then*
+ // will issue the callback on our thread. Waiting for it to read twice
+ // ensures that it was able to issue callbacks for the first read (if it
+ // issued one) before we try to check for it.
+ mock_data_fetcher_->SetTestData(button_down_data);
+ mock_data_fetcher_->WaitForDataRead();
+ mock_data_fetcher_->WaitForDataRead();
+
+ // It should have issued our callback.
+ message_loop().RunAllPending();
+ EXPECT_TRUE(listener.has_user_gesture());
+}
+
} // namespace
} // namespace content
diff --git a/content/browser/gamepad/gamepad_service.cc b/content/browser/gamepad/gamepad_service.cc
index cb9206b..3b631ce 100644
--- a/content/browser/gamepad/gamepad_service.cc
+++ b/content/browser/gamepad/gamepad_service.cc
@@ -5,19 +5,22 @@
#include "content/browser/gamepad/gamepad_service.h"
#include "base/bind.h"
+#include "base/logging.h"
#include "base/memory/singleton.h"
-#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
namespace content {
-GamepadService::GamepadService() :
- num_readers_(0) {
+GamepadService::GamepadService() : num_readers_(0) {
+}
+
+GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher)
+ : num_readers_(0),
+ provider_(new GamepadProvider(fetcher.Pass())) {
+ thread_checker_.DetachFromThread();
}
GamepadService::~GamepadService() {
@@ -28,69 +31,40 @@ GamepadService* GamepadService::GetInstance() {
LeakySingletonTraits<GamepadService> >::get();
}
-void GamepadService::Start(
- GamepadDataFetcher* data_fetcher,
- RenderProcessHost* associated_rph) {
+void GamepadService::AddConsumer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
num_readers_++;
DCHECK(num_readers_ > 0);
- if (provider_ == NULL) {
+ if (!provider_.get())
provider_.reset(new GamepadProvider);
- provider_->SetDataFetcher(data_fetcher);
- }
provider_->Resume();
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GamepadService::RegisterForTerminationNotification,
- base::Unretained(this),
- associated_rph));
-}
-
-void GamepadService::Terminate() {
- provider_.reset();
}
-void GamepadService::RegisterForTerminationNotification(
- RenderProcessHost* rph) {
- registrar_.Add(this,
- NOTIFICATION_RENDERER_PROCESS_TERMINATED,
- Source<RenderProcessHost>(rph));
-}
+void GamepadService::RemoveConsumer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
-base::SharedMemoryHandle GamepadService::GetSharedMemoryHandle(
- base::ProcessHandle handle) {
- return provider_->GetRendererSharedMemoryHandle(handle);
-}
-
-void GamepadService::Stop(const NotificationSource& source) {
--num_readers_;
DCHECK(num_readers_ >= 0);
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GamepadService::UnregisterForTerminationNotification,
- base::Unretained(this),
- source));
-
if (num_readers_ == 0)
provider_->Pause();
}
-void GamepadService::UnregisterForTerminationNotification(
- const NotificationSource& source) {
- registrar_.Remove(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, source);
+void GamepadService::RegisterForUserGesture(const base::Closure& closure) {
+ DCHECK(num_readers_ > 0);
+ DCHECK(thread_checker_.CalledOnValidThread());
+ provider_->RegisterForUserGesture(closure);
}
-void GamepadService::Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED);
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&GamepadService::Stop, base::Unretained(this), source));
+void GamepadService::Terminate() {
+ provider_.reset();
+}
+
+base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess(
+ base::ProcessHandle handle) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return provider_->GetSharedMemoryHandleForProcess(handle);
}
-} // namespace content
+} // namespace content
diff --git a/content/browser/gamepad/gamepad_service.h b/content/browser/gamepad/gamepad_service.h
index 4e10112..cc40c5d0 100644
--- a/content/browser/gamepad/gamepad_service.h
+++ b/content/browser/gamepad/gamepad_service.h
@@ -2,72 +2,76 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Owns the GamepadProvider (the background polling thread) and keeps track of
-// the number of renderers currently using the data (and pausing the provider
-// when not in use).
-
#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/shared_memory.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "base/threading/thread_checker.h"
+#include "content/common/content_export.h"
namespace content {
class GamepadDataFetcher;
class GamepadProvider;
+class GamepadServiceTestConstructor;
class RenderProcessHost;
-class GamepadService : public NotificationObserver {
+// Owns the GamepadProvider (the background polling thread) and keeps track of
+// the number of consumers currently using the data (and pausing the provider
+// when not in use).
+class CONTENT_EXPORT GamepadService {
public:
// Returns the GamepadService singleton.
static GamepadService* GetInstance();
- // Called on IO thread from a renderer host. Increments the number of users
- // of the provider. The Provider is running when there's > 0 users, and is
- // paused when the count drops to 0. There is no stop, the gamepad service
- // registers with the RPH to be notified when the associated renderer closes
- // (or crashes).
- void Start(GamepadDataFetcher* fetcher,
- RenderProcessHost* associated_rph);
+ // Increments the number of users of the provider. The Provider is running
+ // when there's > 0 users, and is paused when the count drops to 0.
+ //
+ // Must be called on the I/O thread.
+ void AddConsumer();
+
+ // Removes a consumer. Should be matched with an AddConsumer call.
+ //
+ // Must be called on the I/O thread.
+ void RemoveConsumer();
+
+ // Registers the given closure for calling when the user has interacted with
+ // the device. This callback will only be issued once. Should only be called
+ // while a consumer is active.
+ void RegisterForUserGesture(const base::Closure& closure);
- base::SharedMemoryHandle GetSharedMemoryHandle(base::ProcessHandle handle);
+ // Returns the shared memory handle of the gamepad data duplicated into the
+ // given process.
+ base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
+ base::ProcessHandle handle);
// Stop/join with the background thread in GamepadProvider |provider_|.
void Terminate();
private:
friend struct DefaultSingletonTraits<GamepadService>;
- GamepadService();
- virtual ~GamepadService();
-
- // Called when a renderer that Start'd us is closed/crashes.
- void Stop(const NotificationSource& source);
+ friend class GamepadServiceTestConstructor;
- // Run on UI thread to receive/stop notifications of renderer closes.
- void RegisterForTerminationNotification(RenderProcessHost* rph);
- void UnregisterForTerminationNotification(const NotificationSource& source);
+ GamepadService();
- // NotificationObserver overrides:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ // Constructor for testing. This specifies the data fetcher to use for a
+ // provider, bypassing the default platform one.
+ GamepadService(scoped_ptr<GamepadDataFetcher> fetcher);
- // A registrar for listening notifications. Used to listen for when an
- // associated renderer has gone away (possibly crashed). We don't trust
- // the renderers to send a stop message because of the possibility of
- // crashing.
- NotificationRegistrar registrar_;
+ virtual ~GamepadService();
int num_readers_;
scoped_ptr<GamepadProvider> provider_;
+ base::ThreadChecker thread_checker_;
+
DISALLOW_COPY_AND_ASSIGN(GamepadService);
};
-} // namespace content
+} // namespace content
-#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
diff --git a/content/browser/gamepad/gamepad_test_helpers.cc b/content/browser/gamepad/gamepad_test_helpers.cc
new file mode 100644
index 0000000..abf4187
--- /dev/null
+++ b/content/browser/gamepad/gamepad_test_helpers.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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 "content/browser/gamepad/gamepad_test_helpers.h"
+
+#include "base/system_monitor/system_monitor.h"
+#include "content/browser/gamepad/gamepad_service.h"
+
+namespace content {
+
+MockGamepadDataFetcher::MockGamepadDataFetcher(
+ const WebKit::WebGamepads& test_data)
+ : test_data_(test_data),
+ read_data_(false, false) {
+}
+
+MockGamepadDataFetcher::~MockGamepadDataFetcher() {
+}
+
+void MockGamepadDataFetcher::GetGamepadData(WebKit::WebGamepads* pads,
+ bool devices_changed_hint) {
+ {
+ base::AutoLock lock(lock_);
+ *pads = test_data_;
+ }
+ read_data_.Signal();
+}
+
+void MockGamepadDataFetcher::WaitForDataRead() {
+ return read_data_.Wait();
+}
+
+void MockGamepadDataFetcher::SetTestData(const WebKit::WebGamepads& new_data) {
+ base::AutoLock lock(lock_);
+ test_data_ = new_data;
+}
+
+GamepadTestHelper::GamepadTestHelper() {
+#if defined(OS_MACOSX)
+ base::SystemMonitor::AllocateSystemIOPorts();
+#endif
+ system_monitor_.reset(new base::SystemMonitor);
+}
+
+GamepadTestHelper::~GamepadTestHelper() {
+}
+
+GamepadServiceTestConstructor::GamepadServiceTestConstructor(
+ const WebKit::WebGamepads& test_data) {
+ data_fetcher_ = new MockGamepadDataFetcher(test_data);
+ gamepad_service_ =
+ new GamepadService(scoped_ptr<GamepadDataFetcher>(data_fetcher_));
+}
+
+GamepadServiceTestConstructor::~GamepadServiceTestConstructor() {
+ delete gamepad_service_;
+}
+
+} // namespace content
diff --git a/content/browser/gamepad/gamepad_test_helpers.h b/content/browser/gamepad/gamepad_test_helpers.h
new file mode 100644
index 0000000..a31b147
--- /dev/null
+++ b/content/browser/gamepad/gamepad_test_helpers.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 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 CONTENT_BROWSER_GAMEPAD_GAMEPAD_TEST_HELPERS_H_
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_TEST_HELPERS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/browser/gamepad/gamepad_data_fetcher.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
+
+namespace base {
+class SystemMonitor;
+}
+
+namespace content {
+
+class GamepadService;
+
+// Data fetcher that returns canned data for the gamepad provider.
+class MockGamepadDataFetcher : public GamepadDataFetcher {
+ public:
+ // Initializes the fetcher with the given gamepad data, which will be
+ // returned when the provider queries us.
+ explicit MockGamepadDataFetcher(const WebKit::WebGamepads& test_data);
+
+ virtual ~MockGamepadDataFetcher();
+
+ // GamepadDataFetcher.
+ virtual void GetGamepadData(WebKit::WebGamepads* pads,
+ bool devices_changed_hint) OVERRIDE;
+
+ // Blocks the current thread until the GamepadProvider reads from this
+ // fetcher on the background thread.
+ void WaitForDataRead();
+
+ // Updates the test data.
+ void SetTestData(const WebKit::WebGamepads& new_data);
+
+ private:
+ base::Lock lock_;
+ WebKit::WebGamepads test_data_;
+ base::WaitableEvent read_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockGamepadDataFetcher);
+};
+
+// Base class for the other test helpers. This just sets up the system monitor.
+class GamepadTestHelper {
+ public:
+ GamepadTestHelper();
+ virtual ~GamepadTestHelper();
+
+ MessageLoop& message_loop() { return message_loop_; }
+
+ private:
+ // This must be constructed before the system monitor.
+ MessageLoop message_loop_;
+
+ scoped_ptr<base::SystemMonitor> system_monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadTestHelper);
+};
+
+// Constructs a GamepadService with a mock data source. This bypasses the
+// global singleton for the gamepad service.
+class GamepadServiceTestConstructor : public GamepadTestHelper {
+ public:
+ GamepadServiceTestConstructor(const WebKit::WebGamepads& test_data);
+ virtual ~GamepadServiceTestConstructor();
+
+ GamepadService* gamepad_service() { return gamepad_service_; }
+ MockGamepadDataFetcher* data_fetcher() { return data_fetcher_; }
+
+ private:
+ // Owning pointer (can't be a scoped_ptr due to private destructor).
+ GamepadService* gamepad_service_;
+
+ // Pointer owned by the provider (which is owned by the gamepad service).
+ MockGamepadDataFetcher* data_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadServiceTestConstructor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_TEST_HELPERS_H_
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 7da9abd..c80ceee 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -141,6 +141,9 @@ PpapiPluginProcessHost::PpapiPluginProcessHost()
: is_broker_(true) {
process_.reset(new BrowserChildProcessHostImpl(
content::PROCESS_TYPE_PPAPI_BROKER, this));
+
+ ppapi::PpapiPermissions permissions; // No permissions.
+ host_impl_ = new content::BrowserPpapiHostImpl(this, permissions);
}
bool PpapiPluginProcessHost::Init(const content::PepperPluginInfo& info) {
@@ -243,6 +246,7 @@ void PpapiPluginProcessHost::RequestPluginChannel(Client* client) {
}
void PpapiPluginProcessHost::OnProcessLaunched() {
+ host_impl_->set_plugin_process_handle(process_->GetHandle());
}
bool PpapiPluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
diff --git a/content/browser/renderer_host/gamepad_browser_message_filter.cc b/content/browser/renderer_host/gamepad_browser_message_filter.cc
index 3701c7f..c06eec2 100644
--- a/content/browser/renderer_host/gamepad_browser_message_filter.cc
+++ b/content/browser/renderer_host/gamepad_browser_message_filter.cc
@@ -11,12 +11,14 @@ using content::BrowserMessageFilter;
namespace content {
-GamepadBrowserMessageFilter::GamepadBrowserMessageFilter(
- content::RenderProcessHost* render_process_host)
- : render_process_host_(render_process_host) {
+GamepadBrowserMessageFilter::GamepadBrowserMessageFilter()
+ : is_started_(false) {
}
GamepadBrowserMessageFilter::~GamepadBrowserMessageFilter() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (is_started_)
+ GamepadService::GetInstance()->RemoveConsumer();
}
bool GamepadBrowserMessageFilter::OnMessageReceived(
@@ -36,13 +38,25 @@ bool GamepadBrowserMessageFilter::OnMessageReceived(
void GamepadBrowserMessageFilter::OnGamepadStartPolling(
base::SharedMemoryHandle* renderer_handle) {
GamepadService* service = GamepadService::GetInstance();
- service->Start(NULL, render_process_host_);
- *renderer_handle = service->GetSharedMemoryHandle(peer_handle());
+ if (!is_started_) {
+ is_started_ = true;
+ service->AddConsumer();
+ *renderer_handle = service->GetSharedMemoryHandleForProcess(peer_handle());
+ } else {
+ // Currently we only expect the renderer to tell us once to start.
+ NOTREACHED();
+ }
}
void GamepadBrowserMessageFilter::OnGamepadStopPolling() {
// TODO(scottmg): Probably get rid of this message. We can't trust it will
// arrive anyway if the renderer crashes, etc.
+ if (is_started_) {
+ is_started_ = false;
+ GamepadService::GetInstance()->RemoveConsumer();
+ } else {
+ NOTREACHED();
+ }
}
-} // namespace content
+} // namespace content
diff --git a/content/browser/renderer_host/gamepad_browser_message_filter.h b/content/browser/renderer_host/gamepad_browser_message_filter.h
index 337c444..8f09365 100644
--- a/content/browser/renderer_host/gamepad_browser_message_filter.h
+++ b/content/browser/renderer_host/gamepad_browser_message_filter.h
@@ -16,12 +16,11 @@ class RenderProcessHost;
class GamepadBrowserMessageFilter : public content::BrowserMessageFilter {
public:
- explicit GamepadBrowserMessageFilter(RenderProcessHost* rph);
+ GamepadBrowserMessageFilter();
// content::BrowserMessageFilter implementation.
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE;
- GamepadBrowserMessageFilter();
private:
virtual ~GamepadBrowserMessageFilter();
@@ -29,11 +28,11 @@ class GamepadBrowserMessageFilter : public content::BrowserMessageFilter {
void OnGamepadStartPolling(base::SharedMemoryHandle* renderer_handle);
void OnGamepadStopPolling();
- RenderProcessHost* render_process_host_;
+ bool is_started_;
DISALLOW_COPY_AND_ASSIGN(GamepadBrowserMessageFilter);
};
-} // namespace content
+} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_GAMEPAD_BROWSER_MESSAGE_FILTER_H_
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
index 8caaaf6..92e5b76 100644
--- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
@@ -12,7 +12,8 @@ BrowserPpapiHostImpl::BrowserPpapiHostImpl(
IPC::Sender* sender,
const ppapi::PpapiPermissions& permissions)
: host_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
- ppapi_host_(sender, &host_factory_, permissions) {
+ ppapi_host_(sender, &host_factory_, permissions),
+ plugin_process_handle_(base::kNullProcessHandle) {
}
BrowserPpapiHostImpl::~BrowserPpapiHostImpl() {
@@ -34,4 +35,10 @@ ppapi::host::PpapiHost* BrowserPpapiHostImpl::GetPpapiHost() {
return &ppapi_host_;
}
+base::ProcessHandle BrowserPpapiHostImpl::GetPluginProcessHandle() const {
+ // Handle should previously have been set before use.
+ DCHECK(plugin_process_handle_ != base::kNullProcessHandle);
+ return plugin_process_handle_;
+}
+
} // namespace content
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
index 062755a..98edba1 100644
--- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
+#include "content/common/content_export.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "ipc/ipc_channel_proxy.h"
#include "ppapi/host/ppapi_host.h"
@@ -18,9 +19,13 @@ class Sender;
namespace content {
-class BrowserPpapiHostImpl : public BrowserPpapiHost,
- public IPC::ChannelProxy::MessageFilter {
+class CONTENT_EXPORT BrowserPpapiHostImpl
+ : public BrowserPpapiHost,
+ public IPC::ChannelProxy::MessageFilter {
public:
+ // The creator is responsible for calling set_plugin_process_handle as soon
+ // as it is known (we start the process asynchronously so it won't be known
+ // when this object is created).
BrowserPpapiHostImpl(IPC::Sender* sender,
const ppapi::PpapiPermissions& permissions);
@@ -29,12 +34,20 @@ class BrowserPpapiHostImpl : public BrowserPpapiHost,
// BrowserPpapiHost.
virtual ppapi::host::PpapiHost* GetPpapiHost() OVERRIDE;
+ virtual base::ProcessHandle GetPluginProcessHandle() const OVERRIDE;
+
+ void set_plugin_process_handle(base::ProcessHandle handle) {
+ plugin_process_handle_ = handle;
+ }
private:
+ friend class BrowserPpapiHostTest;
+
virtual ~BrowserPpapiHostImpl();
ContentBrowserPepperHostFactory host_factory_;
ppapi::host::PpapiHost ppapi_host_;
+ base::ProcessHandle plugin_process_handle_;
DISALLOW_COPY_AND_ASSIGN(BrowserPpapiHostImpl);
};
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
new file mode 100644
index 0000000..078224a
--- /dev/null
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 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 "content/browser/renderer_host/pepper/browser_ppapi_host_test.h"
+
+#include "base/process_util.h"
+#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
+
+namespace content {
+
+BrowserPpapiHostTest::BrowserPpapiHostTest()
+ : sink_(),
+ ppapi_host_(new BrowserPpapiHostImpl(
+ &sink_,
+ ppapi::PpapiPermissions::AllPermissions())) {
+ ppapi_host_->set_plugin_process_handle(base::GetCurrentProcessHandle());
+}
+
+BrowserPpapiHostTest::~BrowserPpapiHostTest() {
+}
+
+BrowserPpapiHost* BrowserPpapiHostTest::GetPpapiHost() {
+ return ppapi_host_;
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_test.h b/content/browser/renderer_host/pepper/browser_ppapi_host_test.h
new file mode 100644
index 0000000..eb7971a
--- /dev/null
+++ b/content/browser/renderer_host/pepper/browser_ppapi_host_test.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 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 CONTENT_BROWSER_RENDERER_HOST_PEPPER_BROWSER_PPAPI_HOST_TEST_H_
+#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_BROWSER_PPAPI_HOST_TEST_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_ppapi_host.h"
+#include "ppapi/proxy/resource_message_test_sink.h"
+
+namespace content {
+
+class BrowserPpapiHostImpl;
+
+// Test harness for testing Pepper resource hosts in the browser. This will
+// construct a BrowserPpapiHost connected to a test sink for testing messages.
+class BrowserPpapiHostTest {
+ public:
+ BrowserPpapiHostTest();
+ virtual ~BrowserPpapiHostTest();
+
+ ppapi::proxy::ResourceMessageTestSink& sink() { return sink_; }
+ BrowserPpapiHost* GetPpapiHost();
+
+ private:
+ ppapi::proxy::ResourceMessageTestSink sink_;
+
+ scoped_refptr<BrowserPpapiHostImpl> ppapi_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserPpapiHostTest);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_BROWSER_PPAPI_HOST_TEST_H_
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.cc b/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
index 0fd3c44..a3cd890 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
@@ -4,10 +4,15 @@
#include "content/browser/renderer_host/pepper/pepper_gamepad_host.h"
+#include "base/bind.h"
+#include "content/browser/gamepad/gamepad_service.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
namespace content {
@@ -15,10 +20,26 @@ PepperGamepadHost::PepperGamepadHost(BrowserPpapiHost* host,
PP_Instance instance,
PP_Resource resource)
: ResourceHost(host->GetPpapiHost(), instance, resource),
- browser_ppapi_host_(host) {
+ browser_ppapi_host_(host),
+ gamepad_service_(GamepadService::GetInstance()),
+ is_started_(false),
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+}
+
+PepperGamepadHost::PepperGamepadHost(GamepadService* gamepad_service,
+ BrowserPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ browser_ppapi_host_(host),
+ gamepad_service_(gamepad_service),
+ is_started_(false),
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}
PepperGamepadHost::~PepperGamepadHost() {
+ if (is_started_)
+ gamepad_service_->RemoveConsumer();
}
int32_t PepperGamepadHost::OnResourceMessageReceived(
@@ -33,7 +54,34 @@ int32_t PepperGamepadHost::OnResourceMessageReceived(
int32_t PepperGamepadHost::OnMsgRequestMemory(
ppapi::host::HostMessageContext* context) {
- return PP_ERROR_FAILED;
+ if (is_started_)
+ return PP_ERROR_FAILED;
+
+ gamepad_service_->AddConsumer();
+ is_started_ = true;
+
+ // Don't send the shared memory back until the user has interacted with the
+ // gamepad. This is to prevent fingerprinting and matches what the web
+ // platform does.
+ gamepad_service_->RegisterForUserGesture(
+ base::Bind(&PepperGamepadHost::GotUserGesture,
+ weak_factory_.GetWeakPtr(),
+ context->MakeReplyParams()));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PepperGamepadHost::GotUserGesture(
+ const ppapi::proxy::ResourceMessageReplyParams& in_params) {
+ base::SharedMemoryHandle handle =
+ gamepad_service_->GetSharedMemoryHandleForProcess(
+ browser_ppapi_host_->GetPluginProcessHandle());
+
+ // The shared memory handle is sent in the params struct, so we have to make
+ // a copy to mutate it.
+ ppapi::proxy::ResourceMessageReplyParams params = in_params;
+ params.AppendHandle(ppapi::proxy::SerializedHandle(
+ handle, sizeof(ppapi::ContentGamepadHardwareBuffer)));
+ host()->SendReply(params, PpapiPluginMsg_Gamepad_SendMemory());
}
} // namespace content
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.h b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
index a47d053..50181c7 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.h
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
@@ -6,18 +6,34 @@
#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_GAMEPAD_HOST_H_
#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "ppapi/host/resource_host.h"
+namespace ppapi {
+namespace proxy {
+class ResourceMessageReplyParams;
+}
+}
+
namespace content {
class BrowserPpapiHost;
+class GamepadService;
class CONTENT_EXPORT PepperGamepadHost : public ppapi::host::ResourceHost {
public:
PepperGamepadHost(BrowserPpapiHost* host,
PP_Instance instance,
PP_Resource resource);
+
+ // Allows tests to specify a gamepad service to use rather than the global
+ // singleton. The caller owns the gamepad_service pointer.
+ PepperGamepadHost(GamepadService* gamepad_service,
+ BrowserPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource);
+
virtual ~PepperGamepadHost();
virtual int32_t OnResourceMessageReceived(
@@ -27,8 +43,16 @@ class CONTENT_EXPORT PepperGamepadHost : public ppapi::host::ResourceHost {
private:
int32_t OnMsgRequestMemory(ppapi::host::HostMessageContext* context);
+ void GotUserGesture(const ppapi::proxy::ResourceMessageReplyParams& params);
+
BrowserPpapiHost* browser_ppapi_host_;
+ GamepadService* gamepad_service_;
+
+ bool is_started_;
+
+ base::WeakPtrFactory<PepperGamepadHost> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(PepperGamepadHost);
};
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc b/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
new file mode 100644
index 0000000..c5a09f7
--- /dev/null
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 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.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/gamepad/gamepad_test_helpers.h"
+#include "content/browser/renderer_host/pepper/browser_ppapi_host_test.h"
+#include "content/browser/renderer_host/pepper/pepper_gamepad_host.h"
+#include "content/common/gamepad_hardware_buffer.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/proxy/gamepad_resource.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/resource_message_params.h"
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+class PepperGamepadHostTest
+ : public testing::Test,
+ public BrowserPpapiHostTest {
+ public:
+ PepperGamepadHostTest() {
+ }
+ ~PepperGamepadHostTest() {
+ }
+
+ void ConstructService(const WebKit::WebGamepads& test_data) {
+ service_.reset(new GamepadServiceTestConstructor(test_data));
+ }
+
+ GamepadService* gamepad_service() { return service_->gamepad_service(); }
+
+ protected:
+ scoped_ptr<GamepadServiceTestConstructor> service_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperGamepadHostTest);
+};
+
+inline ptrdiff_t AddressDiff(const void* a, const void* b) {
+ return static_cast<const char*>(a) - static_cast<const char*>(b);
+}
+
+} // namespace
+
+// Validate the memory layout of the Pepper proxy struct matches the content
+// one. The proxy can't depend on content so has a duplicate definition. This
+// code can see both definitions so we do the validation here.
+TEST_F(PepperGamepadHostTest, ValidateHardwareBuffersMatch) {
+ // Hardware buffer.
+ COMPILE_ASSERT(sizeof(ppapi::ContentGamepadHardwareBuffer) ==
+ sizeof(content::GamepadHardwareBuffer),
+ gamepad_hardware_buffers_must_match);
+ ppapi::ContentGamepadHardwareBuffer ppapi_buf;
+ GamepadHardwareBuffer content_buf;
+ EXPECT_EQ(AddressDiff(&content_buf.sequence, &content_buf),
+ AddressDiff(&ppapi_buf.sequence, &ppapi_buf));
+ EXPECT_EQ(AddressDiff(&content_buf.buffer, &content_buf),
+ AddressDiff(&ppapi_buf.buffer, &ppapi_buf));
+}
+
+TEST_F(PepperGamepadHostTest, ValidateGamepadsMatch) {
+ // Gamepads.
+ COMPILE_ASSERT(sizeof(ppapi::WebKitGamepads) ==
+ sizeof(WebKit::WebGamepads),
+ gamepads_data_must_match);
+ ppapi::WebKitGamepads ppapi_gamepads;
+ WebKit::WebGamepads web_gamepads;
+ EXPECT_EQ(AddressDiff(&web_gamepads.length, &web_gamepads),
+ AddressDiff(&ppapi_gamepads.length, &ppapi_gamepads));
+
+ // See comment below on storage & the EXPECT macro.
+ size_t webkit_items_length_cap = WebKit::WebGamepads::itemsLengthCap;
+ size_t ppapi_items_length_cap = ppapi::WebKitGamepads::kItemsLengthCap;
+ EXPECT_EQ(webkit_items_length_cap, ppapi_items_length_cap);
+
+ for (size_t i = 0; i < web_gamepads.itemsLengthCap; i++) {
+ EXPECT_EQ(AddressDiff(&web_gamepads.items[0], &web_gamepads),
+ AddressDiff(&ppapi_gamepads.items[0], &ppapi_gamepads));
+ }
+}
+
+TEST_F(PepperGamepadHostTest, ValidateGamepadMatch) {
+ // Gamepad.
+ COMPILE_ASSERT(sizeof(ppapi::WebKitGamepad) ==
+ sizeof(WebKit::WebGamepad),
+ gamepad_data_must_match);
+ ppapi::WebKitGamepad ppapi_gamepad;
+ WebKit::WebGamepad web_gamepad;
+
+ // Using EXPECT seems to force storage for the parameter, which the constants
+ // in the WebKit/PPAPI headers don't have. So we have to use temporaries
+ // before comparing them.
+ size_t webkit_id_length_cap = WebKit::WebGamepad::idLengthCap;
+ size_t ppapi_id_length_cap = ppapi::WebKitGamepad::kIdLengthCap;
+ EXPECT_EQ(webkit_id_length_cap, ppapi_id_length_cap);
+
+ size_t webkit_axes_length_cap = WebKit::WebGamepad::axesLengthCap;
+ size_t ppapi_axes_length_cap = ppapi::WebKitGamepad::kAxesLengthCap;
+ EXPECT_EQ(webkit_axes_length_cap, ppapi_axes_length_cap);
+
+ size_t webkit_buttons_length_cap = WebKit::WebGamepad::buttonsLengthCap;
+ size_t ppapi_buttons_length_cap = ppapi::WebKitGamepad::kButtonsLengthCap;
+ EXPECT_EQ(webkit_buttons_length_cap, ppapi_buttons_length_cap);
+
+ EXPECT_EQ(AddressDiff(&web_gamepad.connected, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.connected, &ppapi_gamepad));
+ EXPECT_EQ(AddressDiff(&web_gamepad.id, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.id, &ppapi_gamepad));
+ EXPECT_EQ(AddressDiff(&web_gamepad.timestamp, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.timestamp, &ppapi_gamepad));
+ EXPECT_EQ(AddressDiff(&web_gamepad.axesLength, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.axes_length, &ppapi_gamepad));
+ EXPECT_EQ(AddressDiff(&web_gamepad.axes, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.axes, &ppapi_gamepad));
+ EXPECT_EQ(AddressDiff(&web_gamepad.buttonsLength, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.buttons_length, &ppapi_gamepad));
+ EXPECT_EQ(AddressDiff(&web_gamepad.buttons, &web_gamepad),
+ AddressDiff(&ppapi_gamepad.buttons, &ppapi_gamepad));
+}
+
+TEST_F(PepperGamepadHostTest, WaitForReply) {
+ WebKit::WebGamepads default_data;
+ memset(&default_data, 0, sizeof(WebKit::WebGamepads));
+ default_data.length = 1;
+ default_data.items[0].connected = true;
+ default_data.items[0].buttonsLength = 1;
+ ConstructService(default_data);
+
+ PP_Instance pp_instance = 12345;
+ PP_Resource pp_resource = 67890;
+ PepperGamepadHost gamepad_host(gamepad_service(), GetPpapiHost(),
+ pp_instance, pp_resource);
+
+ // Synthesize a request for gamepad data.
+ ppapi::host::HostMessageContext context(
+ ppapi::proxy::ResourceMessageCallParams(pp_resource, 1));
+ EXPECT_EQ(PP_OK_COMPLETIONPENDING,
+ gamepad_host.OnResourceMessageReceived(
+ PpapiHostMsg_Gamepad_RequestMemory(),
+ &context));
+
+ // Wait for the gamepad background thread to read twice to make sure we
+ // don't get a message yet (see below for why).
+ MockGamepadDataFetcher* fetcher = service_->data_fetcher();
+ fetcher->WaitForDataRead();
+ fetcher->WaitForDataRead();
+
+ // It should not have sent the callback message.
+ service_->message_loop().RunAllPending();
+ EXPECT_EQ(0u, sink().message_count());
+
+ // Set a button down and wait for it to be read twice.
+ //
+ // We wait for two reads before calling RunAllPending because the provider
+ // will read the data on the background thread (setting the event) and *then*
+ // will issue the callback on our thread. Waiting for it to read twice
+ // ensures that it was able to issue callbacks for the first read (if it
+ // issued one) before we try to check for it.
+ WebKit::WebGamepads button_down_data = default_data;
+ button_down_data.items[0].buttons[0] = 1.f;
+ fetcher->SetTestData(button_down_data);
+ fetcher->WaitForDataRead();
+ fetcher->WaitForDataRead();
+
+ // It should have sent a callback.
+ service_->message_loop().RunAllPending();
+ ppapi::proxy::ResourceMessageReplyParams reply_params;
+ IPC::Message reply_msg;
+ ASSERT_TRUE(sink().GetFirstResourceReplyMatching(
+ PpapiPluginMsg_Gamepad_SendMemory::ID, &reply_params, &reply_msg));
+
+ // Extract the shared memory handle.
+ base::SharedMemoryHandle reply_handle;
+ EXPECT_TRUE(reply_params.GetSharedMemoryHandleAtIndex(0, &reply_handle));
+
+ // Validate the shared memory.
+ base::SharedMemory shared_memory(reply_handle, true);
+ EXPECT_TRUE(shared_memory.Map(sizeof(ppapi::ContentGamepadHardwareBuffer)));
+ const ppapi::ContentGamepadHardwareBuffer* buffer =
+ static_cast<const ppapi::ContentGamepadHardwareBuffer*>(
+ shared_memory.memory());
+ EXPECT_EQ(button_down_data.length, buffer->buffer.length);
+ EXPECT_EQ(button_down_data.items[0].buttonsLength,
+ buffer->buffer.items[0].buttons_length);
+ for (size_t i = 0; i < ppapi::WebKitGamepad::kButtonsLengthCap; i++) {
+ EXPECT_EQ(button_down_data.items[0].buttons[i],
+ buffer->buffer.items[0].buttons[i]);
+ }
+
+ // Duplicate requests should be denied.
+ EXPECT_EQ(PP_ERROR_FAILED,
+ gamepad_host.OnResourceMessageReceived(
+ PpapiHostMsg_Gamepad_RequestMemory(),
+ &context));
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 4f7c624..648aabf 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -607,7 +607,7 @@ void RenderProcessHostImpl::CreateMessageFilters() {
GetID(),
storage_partition_impl_->GetQuotaManager(),
GetContentClient()->browser()->CreateQuotaPermissionContext()));
- channel_->AddFilter(new GamepadBrowserMessageFilter(this));
+ channel_->AddFilter(new GamepadBrowserMessageFilter());
channel_->AddFilter(new ProfilerMessageFilter(PROCESS_TYPE_RENDERER));
channel_->AddFilter(new HistogramMessageFilter());
channel_->AddFilter(new HyphenatorMessageFilter(this));
diff --git a/content/common/gamepad_hardware_buffer.h b/content/common/gamepad_hardware_buffer.h
index 077c782..133b751 100644
--- a/content/common/gamepad_hardware_buffer.h
+++ b/content/common/gamepad_hardware_buffer.h
@@ -28,6 +28,6 @@ struct GamepadHardwareBuffer {
WebKit::WebGamepads buffer;
};
-}
+} // namespace content
#endif // CONTENT_COMMON_GAMEPAD_HARDWARE_BUFFER_H_
diff --git a/content/common/gamepad_user_gesture.cc b/content/common/gamepad_user_gesture.cc
new file mode 100644
index 0000000..8fa42b5
--- /dev/null
+++ b/content/common/gamepad_user_gesture.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 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 "content/common/gamepad_user_gesture.h"
+
+#include <algorithm>
+
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGamepads.h"
+
+namespace content {
+
+bool GamepadsHaveUserGesture(const WebKit::WebGamepads& gamepads) {
+ for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; i++) {
+ const WebKit::WebGamepad& pad = gamepads.items[i];
+
+ // If the device is physically connected, then check the primary 4 buttons
+ // to see if there is currently an intentional user action.
+ if (pad.connected) {
+ const unsigned kPrimaryInteractionButtons = 4;
+ unsigned buttons_to_check = std::min(pad.buttonsLength,
+ kPrimaryInteractionButtons);
+ for (unsigned button_index = 0; button_index < buttons_to_check;
+ button_index++) {
+ if (pad.buttons[button_index] > 0.5f)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace content
diff --git a/content/common/gamepad_user_gesture.h b/content/common/gamepad_user_gesture.h
new file mode 100644
index 0000000..d17c69c
--- /dev/null
+++ b/content/common/gamepad_user_gesture.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 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 CONTENT_COMMON_GAMEPAD_USER_GESTURE_H_
+#define CONTENT_COMMON_GAMEPAD_USER_GESTURE_H_
+
+namespace WebKit {
+class WebGamepads;
+}
+
+namespace content {
+
+// Returns true if any of the gamepads have a button pressed that would be
+// considerd a user gesture for interaction.
+bool GamepadsHaveUserGesture(const WebKit::WebGamepads& gamepads);
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GAMEPAD_USER_GESTURE_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index a735037..33bc250 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -357,7 +357,14 @@
'browser/fileapi/fileapi_message_filter.cc',
'browser/fileapi/fileapi_message_filter.h',
'browser/font_list_async.cc',
- 'browser/gamepad/data_fetcher.h',
+ 'browser/gamepad/gamepad_data_fetcher.h',
+ 'browser/gamepad/gamepad_platform_data_fetcher.h',
+ 'browser/gamepad/gamepad_platform_data_fetcher_linux.cc',
+ 'browser/gamepad/gamepad_platform_data_fetcher_linux.h',
+ 'browser/gamepad/gamepad_platform_data_fetcher_mac.h',
+ 'browser/gamepad/gamepad_platform_data_fetcher_mac.mm',
+ 'browser/gamepad/gamepad_platform_data_fetcher_win.cc',
+ 'browser/gamepad/gamepad_platform_data_fetcher_win.h',
'browser/gamepad/gamepad_provider.cc',
'browser/gamepad/gamepad_provider.h',
'browser/gamepad/gamepad_service.cc',
@@ -365,13 +372,6 @@
'browser/gamepad/gamepad_standard_mappings.h',
'browser/gamepad/gamepad_standard_mappings_linux.cc',
'browser/gamepad/gamepad_standard_mappings_mac.mm',
- 'browser/gamepad/platform_data_fetcher.h',
- 'browser/gamepad/platform_data_fetcher_linux.cc',
- 'browser/gamepad/platform_data_fetcher_linux.h',
- 'browser/gamepad/platform_data_fetcher_mac.h',
- 'browser/gamepad/platform_data_fetcher_mac.mm',
- 'browser/gamepad/platform_data_fetcher_win.cc',
- 'browser/gamepad/platform_data_fetcher_win.h',
'browser/geolocation/arbitrator_dependency_factory.cc',
'browser/geolocation/arbitrator_dependency_factory.h',
'browser/geolocation/core_location_data_provider_mac.h',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 62c240b..25c561c 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -198,6 +198,8 @@
'common/gamepad_messages.h',
'common/gamepad_seqlock.cc',
'common/gamepad_seqlock.h',
+ 'common/gamepad_user_gesture.cc',
+ 'common/gamepad_user_gesture.h',
'common/geolocation_messages.h',
'common/gpu/client/command_buffer_proxy_impl.cc',
'common/gpu/client/command_buffer_proxy_impl.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 215fa23a..446fb47 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -14,6 +14,10 @@
'content_browser',
'content_common',
'../net/net.gyp:net_test_support',
+ '../ppapi/ppapi_internal.gyp:ppapi_host',
+ '../ppapi/ppapi_internal.gyp:ppapi_proxy',
+ '../ppapi/ppapi_internal.gyp:ppapi_shared',
+ '../ppapi/ppapi_internal.gyp:ppapi_unittest_shared',
'../skia/skia.gyp:skia',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
@@ -262,6 +266,8 @@
'browser/download/file_metadata_unittest_linux.cc',
'browser/download/save_package_unittest.cc',
'browser/gamepad/gamepad_provider_unittest.cc',
+ 'browser/gamepad/gamepad_test_helpers.cc',
+ 'browser/gamepad/gamepad_test_helpers.h',
'browser/geolocation/device_data_provider_unittest.cc',
'browser/geolocation/geolocation_provider_unittest.cc',
'browser/geolocation/gps_location_provider_unittest_linux.cc',
@@ -291,6 +297,9 @@
'browser/renderer_host/media/video_capture_controller_unittest.cc',
'browser/renderer_host/media/video_capture_host_unittest.cc',
'browser/renderer_host/media/video_capture_manager_unittest.cc',
+ 'browser/renderer_host/pepper/browser_ppapi_host_test.cc',
+ 'browser/renderer_host/pepper/browser_ppapi_host_test.h',
+ 'browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc',
'browser/renderer_host/render_view_host_unittest.cc',
'browser/renderer_host/render_widget_host_unittest.cc',
'browser/renderer_host/render_widget_host_view_aura_unittest.cc',
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 970468d..7e1c3bc 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -94,6 +94,8 @@ bool PpapiThread::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnMsgLoadPlugin)
IPC_MESSAGE_HANDLER(PpapiMsg_CreateChannel, OnMsgCreateChannel)
+ IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply, OnMsgResourceReply)
+
IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPServerSocket_ListenACK,
OnPluginDispatcherMessageReceived(msg))
IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPServerSocket_AcceptACK,
@@ -306,6 +308,13 @@ void PpapiThread::OnMsgCreateChannel(int renderer_id,
Send(new PpapiHostMsg_ChannelCreated(channel_handle));
}
+void PpapiThread::OnMsgResourceReply(
+ const ppapi::proxy::ResourceMessageReplyParams& reply_params,
+ const IPC::Message& nested_msg) {
+ ppapi::proxy::PluginDispatcher::DispatchResourceReply(reply_params,
+ nested_msg);
+}
+
void PpapiThread::OnMsgSetNetworkState(bool online) {
if (!get_plugin_interface_)
return;
diff --git a/content/ppapi_plugin/ppapi_thread.h b/content/ppapi_plugin/ppapi_thread.h
index 06ed0e3..0329809 100644
--- a/content/ppapi_plugin/ppapi_thread.h
+++ b/content/ppapi_plugin/ppapi_thread.h
@@ -70,6 +70,9 @@ class PpapiThread : public ChildThread,
void OnMsgLoadPlugin(const FilePath& path);
void OnMsgCreateChannel(int renderer_id,
bool incognito);
+ void OnMsgResourceReply(
+ const ppapi::proxy::ResourceMessageReplyParams& reply_params,
+ const IPC::Message& nested_msg);
void OnMsgSetNetworkState(bool online);
void OnPluginDispatcherMessageReceived(const IPC::Message& msg);
diff --git a/content/public/browser/browser_ppapi_host.h b/content/public/browser/browser_ppapi_host.h
index a25a6d0..aa97990 100644
--- a/content/public/browser/browser_ppapi_host.h
+++ b/content/public/browser/browser_ppapi_host.h
@@ -5,6 +5,9 @@
#ifndef CONTENT_PUBLIC_BROWSER_BROWSER_PPAPI_HOST_H_
#define CONTENT_PUBLIC_BROWSER_BROWSER_PPAPI_HOST_H_
+#include "base/process.h"
+#include "content/common/content_export.h"
+
namespace ppapi {
namespace host {
class PpapiHost;
@@ -18,11 +21,14 @@ namespace content {
//
// There will be one of these objects in the browser per plugin process. It
// lives entirely on the I/O thread.
-class BrowserPpapiHost {
+class CONTENT_EXPORT BrowserPpapiHost {
public:
// Returns the PpapiHost object.
virtual ppapi::host::PpapiHost* GetPpapiHost() = 0;
+ // Returns the handle to the plugin process.
+ virtual base::ProcessHandle GetPluginProcessHandle() const = 0;
+
protected:
virtual ~BrowserPpapiHost() {}
};
diff --git a/content/renderer/gamepad_shared_memory_reader.cc b/content/renderer/gamepad_shared_memory_reader.cc
index 55c6f62..f4e8194 100644
--- a/content/renderer/gamepad_shared_memory_reader.cc
+++ b/content/renderer/gamepad_shared_memory_reader.cc
@@ -7,6 +7,7 @@
#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
#include "content/common/gamepad_messages.h"
+#include "content/common/gamepad_user_gesture.h"
#include "content/public/renderer/render_thread.h"
#include "content/common/gamepad_hardware_buffer.h"
#include "ipc/ipc_sync_message_filter.h"
@@ -14,8 +15,8 @@
namespace content {
GamepadSharedMemoryReader::GamepadSharedMemoryReader()
- : gamepad_hardware_buffer_(NULL) {
- memset(ever_interacted_with_, 0, sizeof(ever_interacted_with_));
+ : gamepad_hardware_buffer_(NULL),
+ ever_interacted_with_(false) {
CHECK(RenderThread::Get()->Send(new GamepadHostMsg_StartPolling(
&renderer_shared_memory_handle_)));
// If we don't get a valid handle from the browser, don't try to Map (we're
@@ -35,6 +36,12 @@ GamepadSharedMemoryReader::GamepadSharedMemoryReader()
}
void GamepadSharedMemoryReader::SampleGamepads(WebKit::WebGamepads& gamepads) {
+ // ==========
+ // DANGER
+ // ==========
+ //
+ // This logic is duplicated in Pepper as well. If you change it, that also
+ // needs to be in sync. See ppapi/proxy/gamepad_resource.cc.
WebKit::WebGamepads read_into;
TRACE_EVENT0("GAMEPAD", "SampleGamepads");
@@ -58,32 +65,25 @@ void GamepadSharedMemoryReader::SampleGamepads(WebKit::WebGamepads& gamepads) {
UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count);
if (contention_count >= kMaximumContentionCount) {
- // We failed to successfully read, presumably because the hardware
- // thread was taking unusually long. Don't copy the data to the output
- // buffer, and simply leave what was there before.
- return;
+ // We failed to successfully read, presumably because the hardware
+ // thread was taking unusually long. Don't copy the data to the output
+ // buffer, and simply leave what was there before.
+ return;
}
// New data was read successfully, copy it into the output buffer.
memcpy(&gamepads, &read_into, sizeof(gamepads));
- // Override the "connected" with false until the user has interacted
- // with the gamepad. This is to prevent fingerprinting on drive-by pages.
- for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i) {
- WebKit::WebGamepad& pad = gamepads.items[i];
- // If the device is physically connected, then check if we should
- // keep it disabled. We track if any of the primary 4 buttons have been
- // pressed to determine a reasonable intentional interaction from the user.
- if (pad.connected) {
- if (ever_interacted_with_[i])
- continue;
- const unsigned kPrimaryInteractionButtons = 4;
- for (unsigned j = 0; j < kPrimaryInteractionButtons; ++j)
- ever_interacted_with_[i] |= pad.buttons[j] > 0.5f;
- // If we've not previously set, and the user still hasn't touched
- // these buttons, then don't pass the data on to the Chromium port.
- if (!ever_interacted_with_[i])
- pad.connected = false;
+ if (!ever_interacted_with_) {
+ if (GamepadsHaveUserGesture(gamepads)) {
+ ever_interacted_with_ = true;
+ } else {
+ // Clear the connected flag if the user hasn't interacted with any of the
+ // gamepads to prevent fingerprinting. The actual data is not cleared.
+ // WebKit will only copy out data into the JS buffers for connected
+ // gamepads so this is sufficient.
+ for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; i++)
+ gamepads.items[i].connected = false;
}
}
}
diff --git a/content/renderer/gamepad_shared_memory_reader.h b/content/renderer/gamepad_shared_memory_reader.h
index 9a85025..a217c16 100644
--- a/content/renderer/gamepad_shared_memory_reader.h
+++ b/content/renderer/gamepad_shared_memory_reader.h
@@ -24,7 +24,7 @@ class GamepadSharedMemoryReader {
scoped_ptr<base::SharedMemory> renderer_shared_memory_;
GamepadHardwareBuffer* gamepad_hardware_buffer_;
- bool ever_interacted_with_[WebKit::WebGamepads::itemsLengthCap];
+ bool ever_interacted_with_;
};
} // namespace content
diff --git a/content/renderer/pepper/pepper_file_chooser_host.cc b/content/renderer/pepper/pepper_file_chooser_host.cc
index 4d15151..f4faa9f 100644
--- a/content/renderer/pepper/pepper_file_chooser_host.cc
+++ b/content/renderer/pepper/pepper_file_chooser_host.cc
@@ -166,9 +166,7 @@ int32_t PepperFileChooserHost::OnMsgShow(
return PP_ERROR_NOACCESS;
}
- reply_params_ = ppapi::proxy::ResourceMessageReplyParams(
- context->params.pp_resource(),
- context->params.sequence());
+ reply_params_ = context->MakeReplyParams();
return PP_OK_COMPLETIONPENDING;
}
diff --git a/ppapi/examples/gamepad/gamepad.cc b/ppapi/examples/gamepad/gamepad.cc
index 96a127c..4fedc0b 100644
--- a/ppapi/examples/gamepad/gamepad.cc
+++ b/ppapi/examples/gamepad/gamepad.cc
@@ -85,7 +85,7 @@ class MyInstance : public pp::Instance {
}
pp::ImageData PaintImage(const pp::Size& size) {
- pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
+ pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, true);
if (image.is_null())
return image;
diff --git a/ppapi/host/dispatch_host_message.h b/ppapi/host/dispatch_host_message.h
index 9a3fae5..b01a0ed 100644
--- a/ppapi/host/dispatch_host_message.h
+++ b/ppapi/host/dispatch_host_message.h
@@ -79,10 +79,9 @@ inline int32_t DispatchResourceCall(ObjT* obj, Method method,
#define PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(msg_class, member_func) \
case msg_class::ID: { \
- TRACK_RUN_IN_IPC_HANDLER(member_func); \
- return member_func(context); \
- }
-
+ TRACK_RUN_IN_IPC_HANDLER(member_func); \
+ return member_func(context); \
+ }
} // namespace host
} // namespace ppapi
diff --git a/ppapi/host/host_message_context.cc b/ppapi/host/host_message_context.cc
new file mode 100644
index 0000000..5c1c0d1
--- /dev/null
+++ b/ppapi/host/host_message_context.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/host/host_message_context.h"
+
+namespace ppapi {
+namespace host {
+
+HostMessageContext::HostMessageContext(
+ const ppapi::proxy::ResourceMessageCallParams& cp)
+ : params(cp) {
+}
+
+HostMessageContext::~HostMessageContext() {
+}
+
+ppapi::proxy::ResourceMessageReplyParams HostMessageContext::MakeReplyParams() {
+ return ppapi::proxy::ResourceMessageReplyParams(params.pp_resource(),
+ params.sequence());
+}
+
+} // namespace host
+} // namespace ppapi
diff --git a/ppapi/host/host_message_context.h b/ppapi/host/host_message_context.h
index a8ac526..6708261 100644
--- a/ppapi/host/host_message_context.h
+++ b/ppapi/host/host_message_context.h
@@ -15,9 +15,13 @@ namespace host {
// This context structure provides information about incoming resource message
// call requests when passed to resources.
struct PPAPI_HOST_EXPORT HostMessageContext {
- explicit HostMessageContext(const ppapi::proxy::ResourceMessageCallParams& cp)
- : params(cp) {
- }
+ explicit HostMessageContext(
+ const ppapi::proxy::ResourceMessageCallParams& cp);
+ ~HostMessageContext();
+
+ // Returns a "reply params" struct with the same resource and sequence number
+ // as this request.
+ ppapi::proxy::ResourceMessageReplyParams MakeReplyParams();
// The original call parameters passed to the resource message call.
const ppapi::proxy::ResourceMessageCallParams& params;
diff --git a/ppapi/host/ppapi_host.cc b/ppapi/host/ppapi_host.cc
index 14a3a4f..247c781 100644
--- a/ppapi/host/ppapi_host.cc
+++ b/ppapi/host/ppapi_host.cc
@@ -91,7 +91,8 @@ void PpapiHost::OnHostMsgResourceCall(
reply_params.set_result(resource_host->OnResourceMessageReceived(
nested_msg, &context));
- // Sanity check the resource handler.
+ // Sanity check the resource handler. Note if the result was
+ // "completion pending" the resource host may have already sent the reply.
if (reply_params.result() == PP_OK_COMPLETIONPENDING) {
// Message handler should have only returned a pending result if a
// response will be sent to the plugin.
diff --git a/ppapi/host/ppapi_host.h b/ppapi/host/ppapi_host.h
index 5bc284c..3f3605c5 100644
--- a/ppapi/host/ppapi_host.h
+++ b/ppapi/host/ppapi_host.h
@@ -10,8 +10,8 @@
#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "ppapi/c/pp_instance.h"
diff --git a/ppapi/host/resource_host.h b/ppapi/host/resource_host.h
index c1e4b74..27d87b3 100644
--- a/ppapi/host/resource_host.h
+++ b/ppapi/host/resource_host.h
@@ -39,7 +39,9 @@ class PPAPI_HOST_EXPORT ResourceHost {
//
// You can do a response asynchronously by returning PP_OK_COMPLETIONPENDING.
// This will cause the reply to be skipped, and the class implementing this
- // function will take responsibility for issuing the callback later.
+ // function will take responsibility for issuing the callback. The callback
+ // can be issued inside OnResourceMessageReceived before it returns, or at
+ // a future time.
//
// If you don't have a particular reply message, you can just ignore
// the reply in the message context. However, if you have a reply more than
diff --git a/ppapi/ppapi_host.gypi b/ppapi/ppapi_host.gypi
index 079125e..8967e45 100644
--- a/ppapi/ppapi_host.gypi
+++ b/ppapi/ppapi_host.gypi
@@ -23,6 +23,7 @@
'sources': [
'host/dispatch_host_message.h',
'host/host_factory.h',
+ 'host/host_message_context.cc',
'host/host_message_context.h',
'host/instance_message_filter.cc',
'host/instance_message_filter.h',
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index 22d2ceb..2e8ca9f 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -55,6 +55,8 @@
'shared_impl/ppb_file_ref_shared.h',
'shared_impl/ppb_flash_shared.cc',
'shared_impl/ppb_flash_shared.h',
+ 'shared_impl/ppb_gamepad_shared.cc',
+ 'shared_impl/ppb_gamepad_shared.h',
'shared_impl/ppb_graphics_3d_shared.cc',
'shared_impl/ppb_graphics_3d_shared.h',
'shared_impl/ppb_image_data_shared.cc',
diff --git a/ppapi/proxy/dispatch_reply_message.h b/ppapi/proxy/dispatch_reply_message.h
index 443c523..0dc3739 100644
--- a/ppapi/proxy/dispatch_reply_message.h
+++ b/ppapi/proxy/dispatch_reply_message.h
@@ -63,16 +63,23 @@ inline void DispatchResourceReply(ObjT* obj, Method method,
#define PPAPI_DISPATCH_RESOURCE_REPLY(msg_class, member_func) \
case msg_class::ID: { \
- TRACK_RUN_IN_IPC_HANDLER(member_func); \
- msg_class::Schema::Param p; \
- if (msg_class::Read(&ipc_message__, &p)) { \
- ppapi::proxy::DispatchResourceReply( \
- this, \
- &_IpcMessageHandlerClass::member_func, \
- params, p); \
- } \
+ TRACK_RUN_IN_IPC_HANDLER(member_func); \
+ msg_class::Schema::Param p; \
+ if (msg_class::Read(&ipc_message__, &p)) { \
+ ppapi::proxy::DispatchResourceReply( \
+ this, \
+ &_IpcMessageHandlerClass::member_func, \
+ params, p); \
} \
- break;
+ break; \
+ }
+
+#define PPAPI_DISPATCH_RESOURCE_REPLY_0(msg_class, member_func) \
+ case msg_class::ID: { \
+ TRACK_RUN_IN_IPC_HANDLER(member_func); \
+ member_func(params); \
+ break; \
+ }
} // namespace proxy
} // namespace ppapi
diff --git a/ppapi/proxy/gamepad_resource.cc b/ppapi/proxy/gamepad_resource.cc
index 21ee02d..446c11c 100644
--- a/ppapi/proxy/gamepad_resource.cc
+++ b/ppapi/proxy/gamepad_resource.cc
@@ -6,16 +6,47 @@
#include <string.h>
-#include "ppapi/c/ppb_gamepad.h"
+#include "base/threading/platform_thread.h"
#include "ppapi/proxy/dispatch_reply_message.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
namespace ppapi {
namespace proxy {
+namespace {
+
+// This is the read logic from content/common/gamepad_seqlock.h
+base::subtle::Atomic32 ReadBegin(const base::subtle::Atomic32* sequence) {
+ base::subtle::Atomic32 version;
+ for (;;) {
+ version = base::subtle::NoBarrier_Load(sequence);
+
+ // If the counter is even, then the associated data might be in a
+ // consistent state, so we can try to read.
+ if ((version & 1) == 0)
+ break;
+
+ // Otherwise, the writer is in the middle of an update. Retry the read.
+ base::PlatformThread::YieldCurrentThread();
+ }
+ return version;
+}
+
+bool ReadRetry(const base::subtle::Atomic32* sequence,
+ base::subtle::Atomic32 version) {
+ // If the sequence number was updated then a read should be re-attempted.
+ // -- Load fence, read membarrier
+ return base::subtle::Release_Load(sequence) != version;
+}
+
+} // namespace
+
GamepadResource::GamepadResource(Connection connection, PP_Instance instance)
: PluginResource(connection, instance),
buffer_(NULL) {
+ memset(&last_read_, 0, sizeof(last_read_));
+
SendCreateToBrowser(PpapiHostMsg_Gamepad_Create());
CallBrowser(PpapiHostMsg_Gamepad_RequestMemory());
}
@@ -28,30 +59,56 @@ void GamepadResource::Sample(PP_GamepadsSampleData* data) {
// Browser hasn't sent back our shared memory, give the plugin gamepad
// data corresponding to "not connected".
memset(data, 0, sizeof(PP_GamepadsSampleData));
- } else {
- memcpy(data, buffer_, sizeof(PP_GamepadsSampleData));
+ return;
}
+
+ // ==========
+ // DANGER
+ // ==========
+ //
+ // This logic is duplicated in the renderer as well. If you change it, that
+ // also needs to be in sync. See gamepad_shared_memory_reader.cc.
+
+ // Only try to read this many times before failing to avoid waiting here
+ // very long in case of contention with the writer.
+ const int kMaximumContentionCount = 10;
+ int contention_count = -1;
+ base::subtle::Atomic32 version;
+ WebKitGamepads read_into;
+ do {
+ version = ReadBegin(&buffer_->sequence);
+ memcpy(&read_into, &buffer_->buffer, sizeof(read_into));
+ ++contention_count;
+ if (contention_count == kMaximumContentionCount)
+ break;
+ } while (ReadRetry(&buffer_->sequence, version));
+
+ // In the event of a read failure, just leave the last read data as-is (the
+ // hardware thread is taking unusally long).
+ if (contention_count < kMaximumContentionCount)
+ ConvertWebKitGamepadData(read_into, &last_read_);
+
+ memcpy(data, &last_read_, sizeof(PP_GamepadsSampleData));
}
void GamepadResource::OnReplyReceived(const ResourceMessageReplyParams& params,
const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(GamepadResource, msg)
- PPAPI_DISPATCH_RESOURCE_REPLY(PpapiPluginMsg_Gamepad_SendMemory,
- OnPluginMsgSendMemory)
+ PPAPI_DISPATCH_RESOURCE_REPLY_0(PpapiPluginMsg_Gamepad_SendMemory,
+ OnPluginMsgSendMemory)
IPC_END_MESSAGE_MAP()
}
void GamepadResource::OnPluginMsgSendMemory(
- const ResourceMessageReplyParams& params,
- base::SharedMemoryHandle shared_memory_handle) {
- /* TODO(brettw) implement this when we have shared gamepad code. It would be
- something like this:
- shared_memory_.reset(
- new base::SharedMemory(shared_memory_handle, true));
- CHECK(shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
- void *memory = shared_memory_->memory();
- // Use the memory...
- */
+ const ResourceMessageReplyParams& params) {
+ // On failure, the handle will be null and the CHECK below will be tripped.
+ base::SharedMemoryHandle handle;
+ params.GetSharedMemoryHandleAtIndex(0, &handle);
+
+ shared_memory_.reset(new base::SharedMemory(handle, true));
+ CHECK(shared_memory_->Map(sizeof(ContentGamepadHardwareBuffer)));
+ buffer_ = static_cast<const ContentGamepadHardwareBuffer*>(
+ shared_memory_->memory());
}
} // namespace proxy
diff --git a/ppapi/proxy/gamepad_resource.h b/ppapi/proxy/gamepad_resource.h
index 61d66b0..f2398ff 100644
--- a/ppapi/proxy/gamepad_resource.h
+++ b/ppapi/proxy/gamepad_resource.h
@@ -9,8 +9,10 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/shared_memory.h"
+#include "ppapi/c/ppb_gamepad.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
#include "ppapi/thunk/ppb_gamepad_api.h"
struct PP_GamepadsSampleData;
@@ -41,11 +43,13 @@ class PPAPI_PROXY_EXPORT GamepadResource
virtual void OnReplyReceived(const ResourceMessageReplyParams& params,
const IPC::Message& msg) OVERRIDE;
- void OnPluginMsgSendMemory(const ResourceMessageReplyParams& params,
- base::SharedMemoryHandle shared_memory_handle);
+ void OnPluginMsgSendMemory(const ResourceMessageReplyParams& params);
scoped_ptr<base::SharedMemory> shared_memory_;
- void* buffer_;
+ const ContentGamepadHardwareBuffer* buffer_;
+
+ // Last data returned so we can use this in the event of a read failure.
+ PP_GamepadsSampleData last_read_;
DISALLOW_COPY_AND_ASSIGN(GamepadResource);
};
diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc
index 0e406db..d48dbfb 100644
--- a/ppapi/proxy/plugin_dispatcher.cc
+++ b/ppapi/proxy/plugin_dispatcher.cc
@@ -260,6 +260,19 @@ thunk::ResourceCreationAPI* PluginDispatcher::GetResourceCreationAPI() {
GetInterfaceProxy(API_ID_RESOURCE_CREATION));
}
+// static
+void PluginDispatcher::DispatchResourceReply(
+ const ppapi::proxy::ResourceMessageReplyParams& reply_params,
+ const IPC::Message& nested_msg) {
+ Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource(
+ reply_params.pp_resource());
+ if (!resource) {
+ NOTREACHED();
+ return;
+ }
+ resource->OnReplyReceived(reply_params, nested_msg);
+}
+
void PluginDispatcher::ForceFreeAllInstances() {
if (!g_instance_to_dispatcher)
return;
@@ -281,13 +294,7 @@ void PluginDispatcher::ForceFreeAllInstances() {
void PluginDispatcher::OnMsgResourceReply(
const ppapi::proxy::ResourceMessageReplyParams& reply_params,
const IPC::Message& nested_msg) {
- Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource(
- reply_params.pp_resource());
- if (!resource) {
- NOTREACHED();
- return;
- }
- resource->OnReplyReceived(reply_params, nested_msg);
+ DispatchResourceReply(reply_params, nested_msg);
}
void PluginDispatcher::OnMsgSupportsInterface(
diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h
index ba46464..66b5e2d 100644
--- a/ppapi/proxy/plugin_dispatcher.h
+++ b/ppapi/proxy/plugin_dispatcher.h
@@ -147,6 +147,13 @@ class PPAPI_PROXY_EXPORT PluginDispatcher
uint32 plugin_dispatcher_id() const { return plugin_dispatcher_id_; }
bool incognito() const { return incognito_; }
+ // Dispatches the given resource message to the appropriate resource in the
+ // plugin process. This should be wired to the various channels that messages
+ // come in from various other processes.
+ static void DispatchResourceReply(
+ const ppapi::proxy::ResourceMessageReplyParams& reply_params,
+ const IPC::Message& nested_msg);
+
private:
friend class PluginDispatcherTest;
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index a532aff..8528a2d 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1551,9 +1551,15 @@ IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FileChooser_ShowReply,
// Gamepad.
IPC_MESSAGE_CONTROL0(PpapiHostMsg_Gamepad_Create)
+
+// Requests that the gamepad host send the shared memory handle to the plugin
+// process.
IPC_MESSAGE_CONTROL0(PpapiHostMsg_Gamepad_RequestMemory)
-IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Gamepad_SendMemory,
- base::SharedMemoryHandle /* handle */)
+
+// Reply to a RequestMemory call. This supplies the shared memory handle. The
+// actual handle is passed in the ReplyParams struct.
+IPC_MESSAGE_CONTROL0(PpapiPluginMsg_Gamepad_SendMemory)
+
// Printing.
IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_Create)
IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_GetDefaultPrintSettings)
diff --git a/ppapi/proxy/resource_message_params.cc b/ppapi/proxy/resource_message_params.cc
index 5c70e49..6d3fa02 100644
--- a/ppapi/proxy/resource_message_params.cc
+++ b/ppapi/proxy/resource_message_params.cc
@@ -27,12 +27,51 @@ ResourceMessageParams::~ResourceMessageParams() {
void ResourceMessageParams::Serialize(IPC::Message* msg) const {
IPC::ParamTraits<PP_Resource>::Write(msg, pp_resource_);
IPC::ParamTraits<int32_t>::Write(msg, sequence_);
+ IPC::ParamTraits<std::vector<SerializedHandle> >::Write(msg, handles_);
}
bool ResourceMessageParams::Deserialize(const IPC::Message* msg,
PickleIterator* iter) {
return IPC::ParamTraits<PP_Resource>::Read(msg, iter, &pp_resource_) &&
- IPC::ParamTraits<int32_t>::Read(msg, iter, &sequence_);
+ IPC::ParamTraits<int32_t>::Read(msg, iter, &sequence_) &&
+ IPC::ParamTraits<std::vector<SerializedHandle> >::Read(
+ msg, iter, &handles_);
+}
+
+const SerializedHandle* ResourceMessageParams::GetHandleOfTypeAtIndex(
+ size_t index,
+ SerializedHandle::Type type) const {
+ if (handles_.size() <= index)
+ return NULL;
+ if (handles_[index].type() != type)
+ return NULL;
+ return &handles_[index];
+}
+
+bool ResourceMessageParams::GetSharedMemoryHandleAtIndex(
+ size_t index,
+ base::SharedMemoryHandle* handle) const {
+ const SerializedHandle* serialized = GetHandleOfTypeAtIndex(
+ index, SerializedHandle::SHARED_MEMORY);
+ if (!serialized)
+ return false;
+ *handle = serialized->shmem();
+ return true;
+}
+
+bool ResourceMessageParams::GetSocketHandleAtIndex(
+ size_t index,
+ IPC::PlatformFileForTransit* handle) const {
+ const SerializedHandle* serialized = GetHandleOfTypeAtIndex(
+ index, SerializedHandle::SOCKET);
+ if (!serialized)
+ return false;
+ *handle = serialized->descriptor();
+ return true;
+}
+
+void ResourceMessageParams::AppendHandle(const SerializedHandle& handle) {
+ handles_.push_back(handle);
}
ResourceMessageCallParams::ResourceMessageCallParams()
diff --git a/ppapi/proxy/resource_message_params.h b/ppapi/proxy/resource_message_params.h
index ad1c96a..bc52234 100644
--- a/ppapi/proxy/resource_message_params.h
+++ b/ppapi/proxy/resource_message_params.h
@@ -5,9 +5,12 @@
#ifndef PPAPI_PROXY_RESOURCE_MESSAGE_PARAMS_H_
#define PPAPI_PROXY_RESOURCE_MESSAGE_PARAMS_H_
+#include <vector>
+
#include "ipc/ipc_message_utils.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/proxy/serialized_structs.h"
namespace ppapi {
namespace proxy {
@@ -20,6 +23,33 @@ class PPAPI_PROXY_EXPORT ResourceMessageParams {
PP_Resource pp_resource() const { return pp_resource_; }
int32_t sequence() const { return sequence_; }
+ const std::vector<SerializedHandle> handles() const { return handles_; }
+
+ // Returns a pointer to the handle at the given index if it exists and is of
+ // the given type. If the index doesn't exist or the handle isn't of the
+ // given type, returns NULL. Note that the pointer will be into an internal
+ // vector so will be invalidated if the params are mutated.
+ const SerializedHandle* GetHandleOfTypeAtIndex(
+ size_t index,
+ SerializedHandle::Type type) const;
+
+ // Helper functions to return shared memory handles passed in the params
+ // struct. If the index has a valid handle of the given type, it will be
+ // placed in the output parameter and the function will return true. If the
+ // handle doesn't exist or is a different type, the functions will return
+ // false and the output parameter will be untouched.
+ //
+ // Note that the handle could still be a "null" or invalid handle of
+ // the right type and the functions will succeed.
+ bool GetSharedMemoryHandleAtIndex(size_t index,
+ base::SharedMemoryHandle* handle) const;
+ bool GetSocketHandleAtIndex(size_t index,
+ IPC::PlatformFileForTransit* handle) const;
+
+ // Appends the given handle to the list of handles sent with the call or
+ // reply.
+ void AppendHandle(const SerializedHandle& handle);
+
protected:
ResourceMessageParams();
ResourceMessageParams(PP_Resource resource, int32_t sequence);
@@ -44,6 +74,11 @@ class PPAPI_PROXY_EXPORT ResourceMessageParams {
// confusion within the plugin and within callbacks on the same resource,
// there shouldn't be a security problem.
int32_t sequence_;
+
+ // A list of all handles transferred in the message. Handles go here so that
+ // the NaCl adapter can extract them generally when it rewrites them to
+ // go between Windows and NaCl (Posix) apps.
+ std::vector<SerializedHandle> handles_;
};
// Parameters common to all ResourceMessage "Call" requests.
diff --git a/ppapi/shared_impl/ppapi_permissions.cc b/ppapi/shared_impl/ppapi_permissions.cc
index 987fd89..d92f6ba 100644
--- a/ppapi/shared_impl/ppapi_permissions.cc
+++ b/ppapi/shared_impl/ppapi_permissions.cc
@@ -17,6 +17,14 @@ PpapiPermissions::PpapiPermissions(uint32 perms) : permissions_(perms) {
PpapiPermissions::~PpapiPermissions() {
}
+// static
+PpapiPermissions PpapiPermissions::AllPermissions() {
+ return PpapiPermissions(
+ PERMISSION_DEV |
+ PERMISSION_PRIVATE |
+ PERMISSION_BYPASS_USER_GESTURE);
+}
+
bool PpapiPermissions::HasPermission(Permission perm) const {
// Check that "perm" is a power of two to make sure the caller didn't set
// more than one permission bit. We may want to change how permissions are
diff --git a/ppapi/shared_impl/ppapi_permissions.h b/ppapi/shared_impl/ppapi_permissions.h
index 94db0e6..4b1c6a6 100644
--- a/ppapi/shared_impl/ppapi_permissions.h
+++ b/ppapi/shared_impl/ppapi_permissions.h
@@ -20,6 +20,8 @@ enum Permission {
// Allows ability to bypass user-gesture checks for showing things like
// file select dialogs.
PERMISSION_BYPASS_USER_GESTURE = 1 << 3
+
+ // NOTE: If you add stuff be sure to update AllPermissions().
};
class PPAPI_SHARED_EXPORT PpapiPermissions {
@@ -32,6 +34,10 @@ class PPAPI_SHARED_EXPORT PpapiPermissions {
~PpapiPermissions();
+ // Returns a permissions class with all features enabled. This is for testing
+ // and manually registered plugins.
+ static PpapiPermissions AllPermissions();
+
bool HasPermission(Permission perm) const;
private:
diff --git a/ppapi/shared_impl/ppb_gamepad_shared.cc b/ppapi/shared_impl/ppb_gamepad_shared.cc
new file mode 100644
index 0000000..41c7668
--- /dev/null
+++ b/ppapi/shared_impl/ppb_gamepad_shared.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
+
+#include "base/basictypes.h"
+
+namespace ppapi {
+
+void ConvertWebKitGamepadData(const WebKitGamepads& webkit_data,
+ PP_GamepadsSampleData* output_data) {
+ output_data->length = webkit_data.length;
+ for (unsigned i = 0; i < webkit_data.length; ++i) {
+ PP_GamepadSampleData& output_pad = output_data->items[i];
+ const WebKitGamepad& webkit_pad = webkit_data.items[i];
+ output_pad.connected = webkit_pad.connected ? PP_TRUE : PP_FALSE;
+ if (webkit_pad.connected) {
+ COMPILE_ASSERT(sizeof(output_pad.id) == sizeof(webkit_pad.id),
+ id_size_does_not_match);
+ COMPILE_ASSERT(sizeof(output_pad.axes) == sizeof(webkit_pad.axes),
+ axes_size_does_not_match);
+ COMPILE_ASSERT(sizeof(output_pad.buttons) == sizeof(webkit_pad.buttons),
+ buttons_size_does_not_match);
+ memcpy(output_pad.id, webkit_pad.id, sizeof(output_pad.id));
+ output_pad.timestamp = webkit_pad.timestamp;
+ output_pad.axes_length = webkit_pad.axes_length;
+ memcpy(output_pad.axes, webkit_pad.axes, sizeof(output_pad.axes));
+ output_pad.buttons_length = webkit_pad.buttons_length;
+ memcpy(output_pad.buttons,
+ webkit_pad.buttons,
+ sizeof(output_pad.buttons));
+ }
+ }
+}
+
+} // namespace ppapi
diff --git a/ppapi/shared_impl/ppb_gamepad_shared.h b/ppapi/shared_impl/ppb_gamepad_shared.h
new file mode 100644
index 0000000..b3ab882
--- /dev/null
+++ b/ppapi/shared_impl/ppb_gamepad_shared.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_SHARED_IMPL_PPB_GAMEPAD_SHARED_H_
+#define PPAPI_SHARED_IMPL_PPB_GAMEPAD_SHARED_H_
+
+#include "base/atomicops.h"
+#include "base/string16.h"
+#include "ppapi/c/ppb_gamepad.h"
+#include "ppapi/shared_impl/ppapi_shared_export.h"
+
+namespace ppapi {
+
+// TODO(brettw) when we remove the non-IPC-based gamepad implementation, this
+// code should all move into the GamepadResource.
+
+#pragma pack(push, 1)
+
+// This must match the definition of WebKit::Gamepad. The GamepadHost unit test
+// has some compile asserts to validate this.
+struct WebKitGamepad {
+ static const size_t kIdLengthCap = 128;
+ static const size_t kAxesLengthCap = 16;
+ static const size_t kButtonsLengthCap = 32;
+
+ // Is there a gamepad connected at this index?
+ bool connected;
+
+ // Device identifier (based on manufacturer, model, etc.).
+ char16 id[kIdLengthCap];
+
+ // Monotonically increasing value referring to when the data were last
+ // updated.
+ unsigned long long timestamp;
+
+ // Number of valid entries in the axes array.
+ unsigned axes_length;
+
+ // Normalized values representing axes, in the range [-1..1].
+ float axes[kAxesLengthCap];
+
+ // Number of valid entries in the buttons array.
+ unsigned buttons_length;
+
+ // Normalized values representing buttons, in the range [0..1].
+ float buttons[kButtonsLengthCap];
+};
+
+// This must match the definition of WebKit::Gamepads. The GamepadHost unit
+// test has some compile asserts to validate this.
+struct WebKitGamepads {
+ static const size_t kItemsLengthCap = 4;
+
+ // Number of valid entries in the items array.
+ unsigned length;
+
+ // Gamepad data for N separate gamepad devices.
+ WebKitGamepad items[kItemsLengthCap];
+};
+
+// This is the structure store in shared memory. It must match
+// content/common/gamepad_hardware_buffer.h. The GamepadHost unit test has
+// some compile asserts to validate this.
+struct ContentGamepadHardwareBuffer {
+ base::subtle::Atomic32 sequence;
+ WebKitGamepads buffer;
+};
+
+#pragma pack(pop)
+
+PPAPI_SHARED_EXPORT void ConvertWebKitGamepadData(
+ const WebKitGamepads& webkit_data,
+ PP_GamepadsSampleData* output_data);
+
+} // namespace ppapi
+
+#endif // PPAPI_SHARED_IMPL_PPB_GAMEPAD_SHARED_H_
diff --git a/webkit/plugins/ppapi/event_conversion.cc b/webkit/plugins/ppapi/event_conversion.cc
index e88b25a..3329ccf 100644
--- a/webkit/plugins/ppapi/event_conversion.cc
+++ b/webkit/plugins/ppapi/event_conversion.cc
@@ -724,31 +724,5 @@ PP_InputEvent_Class ClassifyInputEvent(WebInputEvent::Type type) {
}
}
-void ConvertWebKitGamepadData(WebKit::WebGamepads& webkit_data,
- PP_GamepadsSampleData* output_data) {
- output_data->length = webkit_data.length;
- for (unsigned i = 0; i < webkit_data.length; ++i) {
- PP_GamepadSampleData& output_pad = output_data->items[i];
- const WebKit::WebGamepad& webkit_pad = webkit_data.items[i];
- output_pad.connected = webkit_pad.connected ? PP_TRUE : PP_FALSE;
- if (webkit_pad.connected) {
- COMPILE_ASSERT(sizeof(output_pad.id) == sizeof(webkit_pad.id),
- id_size_does_not_match);
- COMPILE_ASSERT(sizeof(output_pad.axes) == sizeof(webkit_pad.axes),
- axes_size_does_not_match);
- COMPILE_ASSERT(sizeof(output_pad.buttons) == sizeof(webkit_pad.buttons),
- buttons_size_does_not_match);
- memcpy(output_pad.id, webkit_pad.id, sizeof(output_pad.id));
- output_pad.timestamp = webkit_pad.timestamp;
- output_pad.axes_length = webkit_pad.axesLength;
- memcpy(output_pad.axes, webkit_pad.axes, sizeof(output_pad.axes));
- output_pad.buttons_length = webkit_pad.buttonsLength;
- memcpy(output_pad.buttons,
- webkit_pad.buttons,
- sizeof(output_pad.buttons));
- }
- }
-}
-
} // namespace ppapi
} // namespace webkit
diff --git a/webkit/plugins/ppapi/event_conversion.h b/webkit/plugins/ppapi/event_conversion.h
index 1474fee..f289012 100644
--- a/webkit/plugins/ppapi/event_conversion.h
+++ b/webkit/plugins/ppapi/event_conversion.h
@@ -8,7 +8,6 @@
#include <vector>
#include "base/memory/linked_ptr.h"
-#include "ppapi/c/ppb_gamepad.h"
#include "ppapi/c/ppb_input_event.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "webkit/plugins/webkit_plugins_export.h"
@@ -50,11 +49,6 @@ std::vector<linked_ptr<WebKit::WebInputEvent> > CreateSimulatedWebInputEvents(
// type should not be "Undefined" since there's no corresponding PPAPI class.
PP_InputEvent_Class ClassifyInputEvent(WebKit::WebInputEvent::Type type);
-// Translate from WebGamepads to the Gamepad API format
-// PP_GamepadsSampleData.
-void ConvertWebKitGamepadData(WebKit::WebGamepads& webkit_data,
- PP_GamepadsSampleData* output_data);
-
} // namespace ppapi
} // namespace webkit
diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
index 4070262..6a2a3fe 100644
--- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc
+++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
@@ -33,6 +33,7 @@
#include "ppapi/c/private/pp_content_decryptor.h"
#include "ppapi/c/private/ppp_instance_private.h"
#include "ppapi/shared_impl/ppapi_preferences.h"
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
#include "ppapi/shared_impl/ppb_input_event_shared.h"
#include "ppapi/shared_impl/ppb_url_util_shared.h"
#include "ppapi/shared_impl/ppb_view_shared.h"
@@ -401,7 +402,8 @@ PluginInstance::GamepadImpl::GamepadImpl(PluginDelegate* delegate)
void PluginInstance::GamepadImpl::Sample(PP_GamepadsSampleData* data) {
WebKit::WebGamepads webkit_data;
delegate_->SampleGamepads(&webkit_data);
- ConvertWebKitGamepadData(webkit_data, data);
+ ConvertWebKitGamepadData(
+ *reinterpret_cast<const ::ppapi::WebKitGamepads*>(&webkit_data), data);
}
PluginInstance::PluginInstance(