summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/DEPS1
-rw-r--r--content/browser/gamepad/gamepad_consumer.h29
-rw-r--r--content/browser/gamepad/gamepad_provider.cc117
-rw-r--r--content/browser/gamepad/gamepad_provider.h41
-rw-r--r--content/browser/gamepad/gamepad_service.cc100
-rw-r--r--content/browser/gamepad/gamepad_service.h58
-rw-r--r--content/browser/renderer_host/gamepad_browser_message_filter.cc37
-rw-r--r--content/browser/renderer_host/gamepad_browser_message_filter.h13
-rw-r--r--content/browser/renderer_host/pepper/pepper_gamepad_host.cc4
-rw-r--r--content/browser/renderer_host/pepper/pepper_gamepad_host.h13
-rw-r--r--content/common/DEPS1
-rw-r--r--content/common/gamepad_messages.h12
-rw-r--r--content/common/gamepad_param_traits.cc79
-rw-r--r--content/common/gamepad_param_traits.h32
-rw-r--r--content/content_browser.gypi1
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/renderer/gamepad_shared_memory_reader.cc67
-rw-r--r--content/renderer/gamepad_shared_memory_reader.h21
-rw-r--r--content/renderer/render_thread_impl.cc9
-rw-r--r--content/renderer/render_thread_impl.h9
-rw-r--r--content/renderer/renderer_webkitplatformsupport_impl.cc5
21 files changed, 593 insertions, 58 deletions
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 41e19ab..bd7a602 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -32,6 +32,7 @@ include_rules = [
# header-only types, and some selected common code.
"-third_party/WebKit",
"+third_party/WebKit/public/platform/WebCursorInfo.h",
+ "+third_party/WebKit/public/platform/WebGamepad.h",
"+third_party/WebKit/public/platform/WebGamepads.h",
"+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
"+third_party/WebKit/public/platform/WebIDBDatabaseException.h",
diff --git a/content/browser/gamepad/gamepad_consumer.h b/content/browser/gamepad/gamepad_consumer.h
new file mode 100644
index 0000000..3d07452
--- /dev/null
+++ b/content/browser/gamepad/gamepad_consumer.h
@@ -0,0 +1,29 @@
+// Copyright 2014 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_CONSUMER_H
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H
+
+#include "base/basictypes.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebGamepad.h"
+
+namespace content {
+
+class CONTENT_EXPORT GamepadConsumer {
+ public:
+ virtual void OnGamepadConnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) = 0;
+ virtual void OnGamepadDisconnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) = 0;
+
+ protected:
+ virtual ~GamepadConsumer() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_CONSUMER_H
diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
index 1cc7aab..8e7644e 100644
--- a/content/browser/gamepad/gamepad_provider.cc
+++ b/content/browser/gamepad/gamepad_provider.cc
@@ -15,9 +15,14 @@
#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
+#include "content/browser/gamepad/gamepad_service.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"
+
+using blink::WebGamepad;
+using blink::WebGamepads;
namespace content {
@@ -34,14 +39,16 @@ GamepadProvider::ClosureAndThread::~ClosureAndThread() {
GamepadProvider::GamepadProvider()
: is_paused_(true),
have_scheduled_do_poll_(false),
- devices_changed_(true) {
+ devices_changed_(true),
+ ever_had_user_gesture_(false) {
Initialize(scoped_ptr<GamepadDataFetcher>());
}
GamepadProvider::GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher)
: is_paused_(true),
have_scheduled_do_poll_(false),
- devices_changed_(true) {
+ devices_changed_(true),
+ ever_had_user_gesture_(false) {
Initialize(fetcher.Pass());
}
@@ -63,6 +70,12 @@ base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
return renderer_handle;
}
+void GamepadProvider::GetCurrentGamepadData(WebGamepads* data) {
+ const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
+ base::AutoLock lock(shared_memory_lock_);
+ *data = pads;
+}
+
void GamepadProvider::Pause() {
{
base::AutoLock lock(is_paused_lock_);
@@ -111,6 +124,7 @@ void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
CHECK(res);
GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
+ pad_states_.reset(new PadState[WebGamepads::itemsLengthCap]);
polling_thread_.reset(new base::Thread("Gamepad polling thread"));
#if defined(OS_LINUX)
@@ -148,6 +162,41 @@ void GamepadProvider::SendPauseHint(bool paused) {
data_fetcher_->PauseHint(paused);
}
+bool GamepadProvider::PadState::Match(const WebGamepad& pad) const {
+ return connected_ == pad.connected &&
+ axes_length_ == pad.axesLength &&
+ buttons_length_ == pad.buttonsLength &&
+ memcmp(id_, pad.id, arraysize(id_)) == 0 &&
+ memcmp(mapping_, pad.mapping, arraysize(mapping_)) == 0;
+}
+
+void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
+ DCHECK(pad.connected);
+ connected_ = true;
+ axes_length_ = pad.axesLength;
+ buttons_length_ = pad.buttonsLength;
+ memcpy(id_, pad.id, arraysize(id_));
+ memcpy(mapping_, pad.mapping, arraysize(mapping_));
+}
+
+void GamepadProvider::PadState::SetDisconnected() {
+ connected_ = false;
+ axes_length_ = 0;
+ buttons_length_ = 0;
+ memset(id_, 0, arraysize(id_));
+ memset(mapping_, 0, arraysize(mapping_));
+}
+
+void GamepadProvider::PadState::AsWebGamepad(WebGamepad* pad) {
+ pad->connected = connected_;
+ pad->axesLength = axes_length_;
+ pad->buttonsLength = buttons_length_;
+ memcpy(pad->id, id_, arraysize(id_));
+ memcpy(pad->mapping, mapping_, arraysize(mapping_));
+ memset(pad->axes, 0, arraysize(pad->axes));
+ memset(pad->buttons, 0, arraysize(pad->buttons));
+}
+
void GamepadProvider::DoPoll() {
DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
DCHECK(have_scheduled_do_poll_);
@@ -158,7 +207,7 @@ void GamepadProvider::DoPoll() {
ANNOTATE_BENIGN_RACE_SIZED(
&hwbuf->buffer,
- sizeof(blink::WebGamepads),
+ sizeof(WebGamepads),
"Racey reads are discarded");
{
@@ -167,14 +216,35 @@ void GamepadProvider::DoPoll() {
devices_changed_ = false;
}
- // Acquire the SeqLock. There is only ever one writer to this data.
- // See gamepad_hardware_buffer.h.
- hwbuf->sequence.WriteBegin();
- data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
- hwbuf->sequence.WriteEnd();
+ {
+ base::AutoLock lock(shared_memory_lock_);
+
+ // Acquire the SeqLock. There is only ever one writer to this data.
+ // See gamepad_hardware_buffer.h.
+ hwbuf->sequence.WriteBegin();
+ data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
+ hwbuf->sequence.WriteEnd();
+ }
CheckForUserGesture();
+ if (ever_had_user_gesture_) {
+ for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
+ WebGamepad& pad = hwbuf->buffer.items[i];
+ PadState& state = pad_states_.get()[i];
+ if (pad.connected && !state.connected()) {
+ OnGamepadConnectionChange(true, i, pad);
+ } else if (!pad.connected && state.connected()) {
+ OnGamepadConnectionChange(false, i, pad);
+ } else if (pad.connected && state.connected() && !state.Match(pad)) {
+ WebGamepad old_pad;
+ state.AsWebGamepad(&old_pad);
+ OnGamepadConnectionChange(false, i, old_pad);
+ OnGamepadConnectionChange(true, i, pad);
+ }
+ }
+ }
+
// Schedule our next interval of polling.
ScheduleDoPoll();
}
@@ -197,6 +267,32 @@ void GamepadProvider::ScheduleDoPoll() {
have_scheduled_do_poll_ = true;
}
+void GamepadProvider::OnGamepadConnectionChange(
+ bool connected, int index, const WebGamepad& pad) {
+ PadState& state = pad_states_.get()[index];
+ if (connected)
+ state.SetPad(pad);
+ else
+ state.SetDisconnected();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GamepadProvider::DispatchGamepadConnectionChange,
+ base::Unretained(this),
+ connected,
+ index,
+ pad));
+}
+
+void GamepadProvider::DispatchGamepadConnectionChange(
+ bool connected, int index, const WebGamepad& pad) {
+ if (connected)
+ GamepadService::GetInstance()->OnGamepadConnected(index, pad);
+ else
+ GamepadService::GetInstance()->OnGamepadDisconnected(index, pad);
+}
+
GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
void* mem = gamepad_shared_memory_.memory();
CHECK(mem);
@@ -205,10 +301,11 @@ GamepadHardwareBuffer* GamepadProvider::SharedMemoryAsHardwareBuffer() {
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 (user_gesture_observers_.empty() && ever_had_user_gesture_)
+ return;
if (GamepadsHaveUserGesture(SharedMemoryAsHardwareBuffer()->buffer)) {
+ ever_had_user_gesture_ = true;
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);
diff --git a/content/browser/gamepad/gamepad_provider.h b/content/browser/gamepad/gamepad_provider.h
index 5f10f13..86a4b17 100644
--- a/content/browser/gamepad/gamepad_provider.h
+++ b/content/browser/gamepad/gamepad_provider.h
@@ -17,6 +17,7 @@
#include "base/synchronization/lock.h"
#include "base/system_monitor/system_monitor.h"
#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebGamepads.h"
namespace base {
class MessageLoopProxy;
@@ -43,6 +44,8 @@ class CONTENT_EXPORT GamepadProvider :
base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
base::ProcessHandle renderer_process);
+ void GetCurrentGamepadData(blink::WebGamepads* data);
+
// Pause and resume the background polling thread. Can be called from any
// thread.
void Pause();
@@ -70,6 +73,13 @@ class CONTENT_EXPORT GamepadProvider :
void DoPoll();
void ScheduleDoPoll();
+ void OnGamepadConnectionChange(bool connected,
+ int index,
+ const blink::WebGamepad& pad);
+ void DispatchGamepadConnectionChange(bool connected,
+ int index,
+ const blink::WebGamepad& pad);
+
GamepadHardwareBuffer* SharedMemoryAsHardwareBuffer();
// Checks the gamepad state to see if the user has interacted with it.
@@ -112,9 +122,36 @@ class CONTENT_EXPORT GamepadProvider :
base::Lock devices_changed_lock_;
bool devices_changed_;
- // When polling_thread_ is running, members below are only to be used
- // from that thread.
+ bool ever_had_user_gesture_;
+
+ class PadState {
+ public:
+ PadState() {
+ SetDisconnected();
+ }
+
+ bool Match(const blink::WebGamepad& pad) const;
+ void SetPad(const blink::WebGamepad& pad);
+ void SetDisconnected();
+ void AsWebGamepad(blink::WebGamepad* pad);
+
+ bool connected() const { return connected_; }
+
+ private:
+ bool connected_;
+ unsigned axes_length_;
+ unsigned buttons_length_;
+ blink::WebUChar id_[blink::WebGamepad::idLengthCap];
+ blink::WebUChar mapping_[blink::WebGamepad::mappingLengthCap];
+ };
+
+ // Used to detect connections and disconnections.
+ scoped_ptr<PadState[]> pad_states_;
+
+ // Only used on the polling thread.
scoped_ptr<GamepadDataFetcher> data_fetcher_;
+
+ base::Lock shared_memory_lock_;
base::SharedMemory gamepad_shared_memory_;
// Polling is done on this background thread.
diff --git a/content/browser/gamepad/gamepad_service.cc b/content/browser/gamepad/gamepad_service.cc
index 11a6964..a2a83b3 100644
--- a/content/browser/gamepad/gamepad_service.cc
+++ b/content/browser/gamepad/gamepad_service.cc
@@ -7,18 +7,23 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
+#include "content/browser/gamepad/gamepad_consumer.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/render_process_host.h"
namespace content {
-GamepadService::GamepadService() : num_readers_(0) {
+GamepadService::GamepadService()
+ : num_active_consumers_(0),
+ gesture_callback_pending_(false) {
}
GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher)
- : num_readers_(0),
- provider_(new GamepadProvider(fetcher.Pass())) {
+ : provider_(new GamepadProvider(fetcher.Pass())),
+ num_active_consumers_(0),
+ gesture_callback_pending_(false) {
thread_checker_.DetachFromThread();
}
@@ -30,28 +35,48 @@ GamepadService* GamepadService::GetInstance() {
LeakySingletonTraits<GamepadService> >::get();
}
-void GamepadService::AddConsumer() {
+void GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) {
DCHECK(thread_checker_.CalledOnValidThread());
- num_readers_++;
- DCHECK(num_readers_ > 0);
if (!provider_)
provider_.reset(new GamepadProvider);
- provider_->Resume();
+
+ std::pair<ConsumerSet::iterator, bool> insert_result =
+ consumers_.insert(consumer);
+ insert_result.first->is_active = true;
+ if (!insert_result.first->did_observe_user_gesture &&
+ !gesture_callback_pending_) {
+ provider_->RegisterForUserGesture(
+ base::Bind(&GamepadService::OnUserGesture,
+ base::Unretained(this)));
+ }
+
+ if (num_active_consumers_++ == 0)
+ provider_->Resume();
}
-void GamepadService::RemoveConsumer() {
- DCHECK(thread_checker_.CalledOnValidThread());
+void GamepadService::ConsumerBecameInactive(GamepadConsumer* consumer) {
+ DCHECK(provider_);
+ DCHECK(num_active_consumers_ > 0);
+ DCHECK(consumers_.count(consumer) > 0);
+ DCHECK(consumers_.find(consumer)->is_active);
- --num_readers_;
- DCHECK(num_readers_ >= 0);
+ consumers_.find(consumer)->is_active = false;
+ if (--num_active_consumers_ == 0)
+ provider_->Pause();
+}
- if (num_readers_ == 0)
+void GamepadService::RemoveConsumer(GamepadConsumer* consumer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ ConsumerSet::iterator it = consumers_.find(consumer);
+ if (it->is_active && --num_active_consumers_ == 0)
provider_->Pause();
+ consumers_.erase(it);
}
void GamepadService::RegisterForUserGesture(const base::Closure& closure) {
- DCHECK(num_readers_ > 0);
+ DCHECK(consumers_.size() > 0);
DCHECK(thread_checker_.CalledOnValidThread());
provider_->RegisterForUserGesture(closure);
}
@@ -60,10 +85,59 @@ void GamepadService::Terminate() {
provider_.reset();
}
+void GamepadService::OnGamepadConnected(
+ int index,
+ const blink::WebGamepad& pad) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ for (ConsumerSet::iterator it = consumers_.begin();
+ it != consumers_.end(); ++it) {
+ if (it->did_observe_user_gesture && it->is_active)
+ it->consumer->OnGamepadConnected(index, pad);
+ }
+}
+
+void GamepadService::OnGamepadDisconnected(
+ int index,
+ const blink::WebGamepad& pad) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ for (ConsumerSet::iterator it = consumers_.begin();
+ it != consumers_.end(); ++it) {
+ if (it->did_observe_user_gesture && it->is_active)
+ it->consumer->OnGamepadDisconnected(index, pad);
+ }
+}
+
base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess(
base::ProcessHandle handle) {
DCHECK(thread_checker_.CalledOnValidThread());
return provider_->GetSharedMemoryHandleForProcess(handle);
}
+void GamepadService::OnUserGesture() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ gesture_callback_pending_ = false;
+
+ if (!provider_ ||
+ num_active_consumers_ == 0)
+ return;
+
+ for (ConsumerSet::iterator it = consumers_.begin();
+ it != consumers_.end(); ++it) {
+ if (!it->did_observe_user_gesture && it->is_active) {
+ const ConsumerInfo& info = *it;
+ info.did_observe_user_gesture = true;
+ blink::WebGamepads gamepads;
+ provider_->GetCurrentGamepadData(&gamepads);
+ for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) {
+ const blink::WebGamepad& pad = gamepads.items[i];
+ if (pad.connected)
+ info.consumer->OnGamepadConnected(i, pad);
+ }
+ }
+ }
+}
+
} // namespace content
diff --git a/content/browser/gamepad/gamepad_service.h b/content/browser/gamepad/gamepad_service.h
index 94620b34..6008188 100644
--- a/content/browser/gamepad/gamepad_service.h
+++ b/content/browser/gamepad/gamepad_service.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
+#include <set>
+
#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/memory/scoped_ptr.h"
@@ -13,8 +15,13 @@
#include "base/threading/thread_checker.h"
#include "content/common/content_export.h"
+namespace blink {
+class WebGamepad;
+}
+
namespace content {
+class GamepadConsumer;
class GamepadDataFetcher;
class GamepadProvider;
class GamepadServiceTestConstructor;
@@ -30,14 +37,28 @@ class CONTENT_EXPORT GamepadService {
// 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.
+ // consumer is registered to listen for gamepad connections. If this is the
+ // first time it is added to the set of consumers it will be treated
+ // specially: it will not be informed about connections before a new user
+ // gesture is observed at which point it will be notified for every connected
+ // gamepads.
//
// Must be called on the I/O thread.
- void AddConsumer();
+ void ConsumerBecameActive(GamepadConsumer* consumer);
- // Removes a consumer. Should be matched with an AddConsumer call.
+ // Decrements the number of users of the provider. consumer will not be
+ // informed about connections until it's added back via ConsumerBecameActive.
+ // Must be matched with a ConsumerBecameActive call.
//
// Must be called on the I/O thread.
- void RemoveConsumer();
+ void ConsumerBecameInactive(GamepadConsumer* consumer);
+
+ // Decrements the number of users of the provider and removes consumer from
+ // the set of consumers. Should be matched with a a ConsumerBecameActive
+ // call.
+ //
+ // Must be called on the I/O thread.
+ void RemoveConsumer(GamepadConsumer* consumer);
// 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
@@ -52,6 +73,12 @@ class CONTENT_EXPORT GamepadService {
// Stop/join with the background thread in GamepadProvider |provider_|.
void Terminate();
+ // Called on IO thread when a gamepad is connected.
+ void OnGamepadConnected(int index, const blink::WebGamepad& pad);
+
+ // Called on IO thread when a gamepad is disconnected.
+ void OnGamepadDisconnected(int index, const blink::WebGamepad& pad);
+
private:
friend struct DefaultSingletonTraits<GamepadService>;
friend class GamepadServiceTestConstructor;
@@ -64,11 +91,34 @@ class CONTENT_EXPORT GamepadService {
virtual ~GamepadService();
- int num_readers_;
+ void OnUserGesture();
+
+ struct ConsumerInfo {
+ ConsumerInfo(GamepadConsumer* consumer)
+ : consumer(consumer),
+ did_observe_user_gesture(false) {
+ }
+
+ bool operator<(const ConsumerInfo& other) const {
+ return consumer < other.consumer;
+ }
+
+ GamepadConsumer* consumer;
+ mutable bool is_active;
+ mutable bool did_observe_user_gesture;
+ };
+
scoped_ptr<GamepadProvider> provider_;
base::ThreadChecker thread_checker_;
+ typedef std::set<ConsumerInfo> ConsumerSet;
+ ConsumerSet consumers_;
+
+ int num_active_consumers_;
+
+ bool gesture_callback_pending_;
+
DISALLOW_COPY_AND_ASSIGN(GamepadService);
};
diff --git a/content/browser/renderer_host/gamepad_browser_message_filter.cc b/content/browser/renderer_host/gamepad_browser_message_filter.cc
index e6e05f6..f616a74 100644
--- a/content/browser/renderer_host/gamepad_browser_message_filter.cc
+++ b/content/browser/renderer_host/gamepad_browser_message_filter.cc
@@ -17,7 +17,7 @@ GamepadBrowserMessageFilter::GamepadBrowserMessageFilter()
GamepadBrowserMessageFilter::~GamepadBrowserMessageFilter() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (is_started_)
- GamepadService::GetInstance()->RemoveConsumer();
+ GamepadService::GetInstance()->RemoveConsumer(this);
}
bool GamepadBrowserMessageFilter::OnMessageReceived(
@@ -34,28 +34,31 @@ bool GamepadBrowserMessageFilter::OnMessageReceived(
return handled;
}
+void GamepadBrowserMessageFilter::OnGamepadConnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) {
+ Send(new GamepadMsg_GamepadConnected(index, gamepad));
+}
+
+void GamepadBrowserMessageFilter::OnGamepadDisconnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) {
+ Send(new GamepadMsg_GamepadDisconnected(index, gamepad));
+}
+
void GamepadBrowserMessageFilter::OnGamepadStartPolling(
base::SharedMemoryHandle* renderer_handle) {
GamepadService* service = GamepadService::GetInstance();
- if (!is_started_) {
- is_started_ = true;
- service->AddConsumer();
- *renderer_handle = service->GetSharedMemoryHandleForProcess(PeerHandle());
- } else {
- // Currently we only expect the renderer to tell us once to start.
- NOTREACHED();
- }
+ CHECK(!is_started_);
+ is_started_ = true;
+ service->ConsumerBecameActive(this);
+ *renderer_handle = service->GetSharedMemoryHandleForProcess(PeerHandle());
}
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();
- }
+ CHECK(is_started_);
+ is_started_ = false;
+ GamepadService::GetInstance()->ConsumerBecameInactive(this);
}
} // 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 8661e71..f328739 100644
--- a/content/browser/renderer_host/gamepad_browser_message_filter.h
+++ b/content/browser/renderer_host/gamepad_browser_message_filter.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/memory/shared_memory.h"
+#include "content/browser/gamepad/gamepad_consumer.h"
#include "content/public/browser/browser_message_filter.h"
namespace content {
@@ -14,7 +15,9 @@ namespace content {
class GamepadService;
class RenderProcessHost;
-class GamepadBrowserMessageFilter : public BrowserMessageFilter {
+class GamepadBrowserMessageFilter :
+ public BrowserMessageFilter,
+ public GamepadConsumer {
public:
GamepadBrowserMessageFilter();
@@ -22,6 +25,14 @@ class GamepadBrowserMessageFilter : public BrowserMessageFilter {
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE;
+ // GamepadConsumer implementation.
+ virtual void OnGamepadConnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) OVERRIDE;
+ virtual void OnGamepadDisconnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) OVERRIDE;
+
private:
virtual ~GamepadBrowserMessageFilter();
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.cc b/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
index 8783e81..bbb72b8 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
@@ -37,7 +37,7 @@ PepperGamepadHost::PepperGamepadHost(GamepadService* gamepad_service,
PepperGamepadHost::~PepperGamepadHost() {
if (is_started_)
- gamepad_service_->RemoveConsumer();
+ gamepad_service_->RemoveConsumer(this);
}
int32_t PepperGamepadHost::OnResourceMessageReceived(
@@ -55,7 +55,7 @@ int32_t PepperGamepadHost::OnRequestMemory(
if (is_started_)
return PP_ERROR_FAILED;
- gamepad_service_->AddConsumer();
+ gamepad_service_->ConsumerBecameActive(this);
is_started_ = true;
// Don't send the shared memory back until the user has interacted with the
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.h b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
index 1db73aa..c9f2c18 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.h
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
+#include "content/browser/gamepad/gamepad_consumer.h"
#include "content/common/content_export.h"
#include "ppapi/host/resource_host.h"
@@ -21,7 +22,9 @@ namespace content {
class BrowserPpapiHost;
class GamepadService;
-class CONTENT_EXPORT PepperGamepadHost : public ppapi::host::ResourceHost {
+class CONTENT_EXPORT PepperGamepadHost :
+ public ppapi::host::ResourceHost,
+ public GamepadConsumer {
public:
PepperGamepadHost(BrowserPpapiHost* host,
PP_Instance instance,
@@ -40,6 +43,14 @@ class CONTENT_EXPORT PepperGamepadHost : public ppapi::host::ResourceHost {
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) OVERRIDE;
+ // GamepadConsumer implementation.
+ virtual void OnGamepadConnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) OVERRIDE {}
+ virtual void OnGamepadDisconnected(
+ unsigned index,
+ const blink::WebGamepad& gamepad) OVERRIDE {}
+
private:
int32_t OnRequestMemory(ppapi::host::HostMessageContext* context);
diff --git a/content/common/DEPS b/content/common/DEPS
index 2e419da..645304d 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -13,6 +13,7 @@ include_rules = [
"+third_party/WebKit/public/platform/WebDeviceOrientationData.h",
"+third_party/WebKit/public/platform/WebFloatPoint.h",
"+third_party/WebKit/public/platform/WebFloatRect.h",
+ "+third_party/WebKit/public/platform/WebGamepad.h",
"+third_party/WebKit/public/platform/WebGamepads.h",
"+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
"+third_party/WebKit/public/platform/WebHTTPBody.h",
diff --git a/content/common/gamepad_messages.h b/content/common/gamepad_messages.h
index 0532b9c..63d6556 100644
--- a/content/common/gamepad_messages.h
+++ b/content/common/gamepad_messages.h
@@ -1,16 +1,26 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2014 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.
// Multiply-included message file, no include guard.
#include "base/memory/shared_memory.h"
+#include "content/common/gamepad_param_traits.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
#include "ipc/ipc_platform_file.h"
+#include "third_party/WebKit/public/platform/WebGamepad.h"
#define IPC_MESSAGE_START GamepadMsgStart
+IPC_MESSAGE_CONTROL2(GamepadMsg_GamepadConnected,
+ int /* index */,
+ blink::WebGamepad)
+
+IPC_MESSAGE_CONTROL2(GamepadMsg_GamepadDisconnected,
+ int /* index */,
+ blink::WebGamepad)
+
// Messages sent from the renderer to the browser.
// Asks the browser process to start polling, and return a shared memory
diff --git a/content/common/gamepad_param_traits.cc b/content/common/gamepad_param_traits.cc
new file mode 100644
index 0000000..356d875
--- /dev/null
+++ b/content/common/gamepad_param_traits.cc
@@ -0,0 +1,79 @@
+// Copyright 2014 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_param_traits.h"
+
+#include "base/pickle.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ipc/ipc_message_utils.h"
+#include "third_party/WebKit/public/platform/WebGamepad.h"
+
+using blink::WebGamepad;
+
+namespace {
+
+void LogWebUCharString(
+ const blink::WebUChar web_string[],
+ const size_t array_size,
+ std::string* log) {
+ base::string16 utf16;
+ utf16.reserve(array_size);
+ for (size_t i = 0; i < array_size && web_string[i]; ++i) {
+ utf16[i] = web_string[i];
+ }
+ log->append(base::UTF16ToUTF8(utf16));
+}
+
+}
+
+namespace IPC {
+
+void ParamTraits<WebGamepad>::Write(
+ Message* m,
+ const WebGamepad& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(WebGamepad));
+}
+
+bool ParamTraits<WebGamepad>::Read(
+ const Message* m,
+ PickleIterator* iter,
+ WebGamepad* p) {
+ int length;
+ const char* data;
+ if (!m->ReadData(iter, &data, &length) || length != sizeof(WebGamepad))
+ return false;
+ memcpy(p, data, sizeof(WebGamepad));
+
+ return true;
+}
+
+void ParamTraits<WebGamepad>::Log(
+ const WebGamepad& p,
+ std::string* l) {
+ l->append("WebGamepad(");
+ LogParam(p.connected, l);
+ LogWebUCharString(p.id, WebGamepad::idLengthCap, l);
+ l->append(",");
+ LogWebUCharString(p.mapping, WebGamepad::mappingLengthCap, l);
+ l->append(",");
+ LogParam(p.timestamp, l);
+ l->append(",");
+ LogParam(p.axesLength, l);
+ l->append(", [");
+ for (size_t i = 0; i < arraysize(p.axes); ++i) {
+ l->append(base::StringPrintf("%f%s", p.axes[i],
+ i < (arraysize(p.axes) - 1) ? ", " : "], "));
+ }
+ LogParam(p.buttonsLength, l);
+ l->append(", [");
+ for (size_t i = 0; i < arraysize(p.buttons); ++i) {
+ l->append(base::StringPrintf("(%u, %f)%s",
+ p.buttons[i].pressed, p.buttons[i].value,
+ i < (arraysize(p.buttons) - 1) ? ", " : "], "));
+ }
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/content/common/gamepad_param_traits.h b/content/common/gamepad_param_traits.h
new file mode 100644
index 0000000..aa9e440
--- /dev/null
+++ b/content/common/gamepad_param_traits.h
@@ -0,0 +1,32 @@
+// Copyright 2014 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_PARAM_TRAITS_H_
+#define CONTENT_COMMON_GAMEPAD_PARAM_TRAITS_H_
+
+#include <string>
+
+#include "ipc/ipc_param_traits.h"
+
+class PickleIterator;
+
+namespace blink { class WebGamepad; }
+
+namespace IPC {
+
+class Message;
+
+template <>
+struct ParamTraits<blink::WebGamepad> {
+ typedef blink::WebGamepad param_type;
+ static void Write(Message* m, const blink::WebGamepad& p);
+ static bool Read(const Message* m,
+ PickleIterator* iter,
+ blink::WebGamepad* p);
+ static void Log(const blink::WebGamepad& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index c073222..25ac91b 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -574,6 +574,7 @@
'browser/frame_host/render_widget_host_view_child_frame.h',
'browser/frame_host/render_widget_host_view_guest.cc',
'browser/frame_host/render_widget_host_view_guest.h',
+ 'browser/gamepad/gamepad_consumer.h',
'browser/gamepad/gamepad_data_fetcher.h',
'browser/gamepad/gamepad_platform_data_fetcher.h',
'browser/gamepad/gamepad_platform_data_fetcher_linux.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index ff70a16..4fc97bd 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -212,6 +212,8 @@
'common/frame_param_macros.h',
'common/gamepad_hardware_buffer.h',
'common/gamepad_messages.h',
+ 'common/gamepad_param_traits.cc',
+ 'common/gamepad_param_traits.h',
'common/gamepad_user_gesture.cc',
'common/gamepad_user_gesture.h',
'common/geolocation_messages.h',
diff --git a/content/renderer/gamepad_shared_memory_reader.cc b/content/renderer/gamepad_shared_memory_reader.cc
index 23edeb3..f1b1e83 100644
--- a/content/renderer/gamepad_shared_memory_reader.cc
+++ b/content/renderer/gamepad_shared_memory_reader.cc
@@ -6,19 +6,28 @@
#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"
+#include "third_party/WebKit/public/platform/WebGamepadListener.h"
namespace content {
GamepadSharedMemoryReader::GamepadSharedMemoryReader()
: gamepad_hardware_buffer_(NULL),
+ gamepad_listener_(NULL),
+ is_polling_(false),
ever_interacted_with_(false) {
+}
+
+void GamepadSharedMemoryReader::StartPollingIfNecessary() {
+ if (is_polling_)
+ return;
+
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
// probably out of memory or file handles).
bool valid_handle = base::SharedMemory::IsHandleValid(
@@ -26,6 +35,7 @@ GamepadSharedMemoryReader::GamepadSharedMemoryReader()
UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", valid_handle);
if (!valid_handle)
return;
+
renderer_shared_memory_.reset(
new base::SharedMemory(renderer_shared_memory_handle_, true));
CHECK(renderer_shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
@@ -33,9 +43,25 @@ GamepadSharedMemoryReader::GamepadSharedMemoryReader()
CHECK(memory);
gamepad_hardware_buffer_ =
static_cast<GamepadHardwareBuffer*>(memory);
+
+ is_polling_ = true;
+}
+
+void GamepadSharedMemoryReader::StopPollingIfNecessary() {
+ if (is_polling_) {
+ RenderThread::Get()->Send(new GamepadHostMsg_StopPolling());
+ is_polling_ = false;
+ }
}
void GamepadSharedMemoryReader::SampleGamepads(blink::WebGamepads& gamepads) {
+ // Blink should set the listener before start sampling.
+ CHECK(gamepad_listener_);
+
+ StartPollingIfNecessary();
+ if (!is_polling_)
+ return;
+
// ==========
// DANGER
// ==========
@@ -88,8 +114,45 @@ void GamepadSharedMemoryReader::SampleGamepads(blink::WebGamepads& gamepads) {
}
}
+void GamepadSharedMemoryReader::SetGamepadListener(
+ blink::WebGamepadListener* listener) {
+ gamepad_listener_ = listener;
+ if (gamepad_listener_) {
+ // Polling has to be started rigth now and not just on the first sampling
+ // because want to get connection events from now.
+ StartPollingIfNecessary();
+ } else {
+ StopPollingIfNecessary();
+ }
+}
+
GamepadSharedMemoryReader::~GamepadSharedMemoryReader() {
- RenderThread::Get()->Send(new GamepadHostMsg_StopPolling());
+ StopPollingIfNecessary();
+}
+
+bool GamepadSharedMemoryReader::OnControlMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(GamepadSharedMemoryReader, message)
+ IPC_MESSAGE_HANDLER(GamepadMsg_GamepadConnected, OnGamepadConnected)
+ IPC_MESSAGE_HANDLER(GamepadMsg_GamepadDisconnected, OnGamepadDisconnected)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void GamepadSharedMemoryReader::OnGamepadConnected(
+ int index,
+ const blink::WebGamepad& gamepad) {
+ if (gamepad_listener_)
+ gamepad_listener_->didConnectGamepad(index, gamepad);
+}
+
+void GamepadSharedMemoryReader::OnGamepadDisconnected(
+ int index,
+ const blink::WebGamepad& gamepad) {
+ if (gamepad_listener_)
+ gamepad_listener_->didDisconnectGamepad(index, gamepad);
}
} // namespace content
diff --git a/content/renderer/gamepad_shared_memory_reader.h b/content/renderer/gamepad_shared_memory_reader.h
index 08dc41a..3846176 100644
--- a/content/renderer/gamepad_shared_memory_reader.h
+++ b/content/renderer/gamepad_shared_memory_reader.h
@@ -7,23 +7,40 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
+#include "content/common/gamepad_messages.h"
+#include "content/public/renderer/render_process_observer.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
+namespace blink { class WebGamepadListener; }
+
namespace content {
struct GamepadHardwareBuffer;
-class GamepadSharedMemoryReader {
+class GamepadSharedMemoryReader : public RenderProcessObserver {
public:
GamepadSharedMemoryReader();
virtual ~GamepadSharedMemoryReader();
- void SampleGamepads(blink::WebGamepads&);
+
+ void SampleGamepads(blink::WebGamepads& gamepads);
+ void SetGamepadListener(blink::WebGamepadListener* listener);
+
+ // RenderProcessObserver implementation.
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
private:
+ void OnGamepadConnected(int index, const blink::WebGamepad& gamepad);
+ void OnGamepadDisconnected(int index, const blink::WebGamepad& gamepad);
+
+ void StartPollingIfNecessary();
+ void StopPollingIfNecessary();
+
base::SharedMemoryHandle renderer_shared_memory_handle_;
scoped_ptr<base::SharedMemory> renderer_shared_memory_;
GamepadHardwareBuffer* gamepad_hardware_buffer_;
+ blink::WebGamepadListener* gamepad_listener_;
+ bool is_polling_;
bool ever_interacted_with_;
};
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index eabb5c2..9794185 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -396,6 +396,9 @@ void RenderThreadImpl::Init() {
AddFilter((new EmbeddedWorkerContextMessageFilter())->GetFilter());
+ gamepad_shared_memory_reader_.reset(new GamepadSharedMemoryReader());
+ AddObserver(gamepad_shared_memory_reader_.get());
+
GetContentClient()->renderer()->RenderThreadStarted();
InitSkiaEventTracer();
@@ -1463,11 +1466,13 @@ void RenderThreadImpl::SetFlingCurveParameters(
}
void RenderThreadImpl::SampleGamepads(blink::WebGamepads* data) {
- if (!gamepad_shared_memory_reader_)
- gamepad_shared_memory_reader_.reset(new GamepadSharedMemoryReader);
gamepad_shared_memory_reader_->SampleGamepads(*data);
}
+void RenderThreadImpl::SetGamepadListener(blink::WebGamepadListener* listener) {
+ gamepad_shared_memory_reader_->SetGamepadListener(listener);
+}
+
void RenderThreadImpl::WidgetCreated() {
widget_count_++;
}
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index ade85d4..f221bd4 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -33,6 +33,7 @@ struct WorkerProcessMsg_CreateWorker_Params;
namespace blink {
class WebGamepads;
+class WebGamepadListener;
class WebGraphicsContext3D;
class WebMediaStreamCenter;
class WebMediaStreamCenterClient;
@@ -275,6 +276,10 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
return vc_manager_.get();
}
+ GamepadSharedMemoryReader* gamepad_shared_memory_reader() const {
+ return gamepad_shared_memory_reader_.get();
+ }
+
// Get the GPU channel. Returns NULL if the channel is not established or
// has been lost.
GpuChannelHost* GetGpuChannel();
@@ -372,6 +377,10 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
// Retrieve current gamepad data.
void SampleGamepads(blink::WebGamepads* data);
+ // Set a listener for gamepad connected/disconnected events.
+ // A non-null listener must be set first before calling SampleGamepads.
+ void SetGamepadListener(blink::WebGamepadListener* listener);
+
// Called by a RenderWidget when it is created or destroyed. This
// allows the process to know when there are no visible widgets.
void WidgetCreated();
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc
index 8df6722..91906df 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.cc
+++ b/content/renderer/renderer_webkitplatformsupport_impl.cc
@@ -884,7 +884,8 @@ WebBlobRegistry* RendererWebKitPlatformSupportImpl::blobRegistry() {
void RendererWebKitPlatformSupportImpl::sampleGamepads(WebGamepads& gamepads) {
if (g_test_gamepads == 0) {
- RenderThreadImpl::current()->SampleGamepads(&gamepads);
+ RenderThreadImpl::current()->gamepad_shared_memory_reader()->
+ SampleGamepads(gamepads);
} else {
gamepads = g_test_gamepads.Get();
}
@@ -893,6 +894,8 @@ void RendererWebKitPlatformSupportImpl::sampleGamepads(WebGamepads& gamepads) {
void RendererWebKitPlatformSupportImpl::setGamepadListener(
blink::WebGamepadListener* listener) {
web_gamepad_listener = listener;
+ RenderThreadImpl::current()->gamepad_shared_memory_reader()->
+ SetGamepadListener(listener);
}
//------------------------------------------------------------------------------