summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 07:06:39 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 07:06:39 +0000
commit00c0d0437c9f6f8896df580bcbeffd022d1cf878 (patch)
tree0177c166101ddd30916ee2eaf50d409d2e86ace2
parent7b64f86e2c50c086dba2d3aba2b1a0d22208f072 (diff)
downloadchromium_src-00c0d0437c9f6f8896df580bcbeffd022d1cf878.zip
chromium_src-00c0d0437c9f6f8896df580bcbeffd022d1cf878.tar.gz
chromium_src-00c0d0437c9f6f8896df580bcbeffd022d1cf878.tar.bz2
Implement the gamepad API in the IPC proxy
This does some reworking of the gamepad system to make it possible to hook in (previously it assumed that it was only talking to renderers) and I did some cleanup. Gamepad files were renamed to match the classes, and I did a bunch of test infrastructure work. IMPORTANT BEHAVIOR CHANGE: This changes the Web gamepad API to report all gamepad data as soon as any of them are interacted with. This is what we need to do for Pepper anyway (since it gets all or none of the share memory) and I think makes more sense for most consumers anyway. I separated out the user gesture detection code into a place where it can be used in the browser process as well, and exposed functionality in the gamepad provider to be notified when a user gesture happens. The existing gamepad test was disabled and had bitrotted. This fixes it. Review URL: https://chromiumcodereview.appspot.com/10912062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155676 0039d316-1c4b-4281-b951-d872f2087c98
-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(