| Index: content/browser/gamepad/gamepad_provider.cc
 | 
| diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
 | 
| deleted file mode 100644
 | 
| index 5f196b11ecafe656fd6ff0c154cafe72f3b85421..0000000000000000000000000000000000000000
 | 
| --- a/content/browser/gamepad/gamepad_provider.cc
 | 
| +++ /dev/null
 | 
| @@ -1,334 +0,0 @@
 | 
| -// 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_provider.h"
 | 
| -
 | 
| -#include <stddef.h>
 | 
| -#include <string.h>
 | 
| -#include <cmath>
 | 
| -#include <set>
 | 
| -#include <utility>
 | 
| -#include <vector>
 | 
| -
 | 
| -#include "base/bind.h"
 | 
| -#include "base/location.h"
 | 
| -#include "base/logging.h"
 | 
| -#include "base/single_thread_task_runner.h"
 | 
| -#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 | 
| -#include "base/threading/thread.h"
 | 
| -#include "base/threading/thread_restrictions.h"
 | 
| -#include "base/threading/thread_task_runner_handle.h"
 | 
| -#include "build/build_config.h"
 | 
| -#include "content/browser/gamepad/gamepad_data_fetcher.h"
 | 
| -#include "content/browser/gamepad/gamepad_platform_data_fetcher.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 {
 | 
| -
 | 
| -GamepadProvider::ClosureAndThread::ClosureAndThread(
 | 
| -    const base::Closure& c,
 | 
| -    const scoped_refptr<base::SingleThreadTaskRunner>& m)
 | 
| -    : closure(c), task_runner(m) {
 | 
| -}
 | 
| -
 | 
| -GamepadProvider::ClosureAndThread::ClosureAndThread(
 | 
| -    const ClosureAndThread& other) = default;
 | 
| -
 | 
| -GamepadProvider::ClosureAndThread::~ClosureAndThread() {
 | 
| -}
 | 
| -
 | 
| -GamepadProvider::GamepadProvider()
 | 
| -    : is_paused_(true),
 | 
| -      have_scheduled_do_poll_(false),
 | 
| -      devices_changed_(true),
 | 
| -      ever_had_user_gesture_(false) {
 | 
| -  Initialize(std::unique_ptr<GamepadDataFetcher>());
 | 
| -}
 | 
| -
 | 
| -GamepadProvider::GamepadProvider(std::unique_ptr<GamepadDataFetcher> fetcher)
 | 
| -    : is_paused_(true),
 | 
| -      have_scheduled_do_poll_(false),
 | 
| -      devices_changed_(true),
 | 
| -      ever_had_user_gesture_(false) {
 | 
| -  Initialize(std::move(fetcher));
 | 
| -}
 | 
| -
 | 
| -GamepadProvider::~GamepadProvider() {
 | 
| -  base::SystemMonitor* monitor = base::SystemMonitor::Get();
 | 
| -  if (monitor)
 | 
| -    monitor->RemoveDevicesChangedObserver(this);
 | 
| -
 | 
| -  // Use Stop() to join the polling thread, as there may be pending callbacks
 | 
| -  // which dereference |polling_thread_|.
 | 
| -  polling_thread_->Stop();
 | 
| -  data_fetcher_.reset();
 | 
| -}
 | 
| -
 | 
| -base::SharedMemoryHandle GamepadProvider::GetSharedMemoryHandleForProcess(
 | 
| -    base::ProcessHandle process) {
 | 
| -  base::SharedMemoryHandle renderer_handle;
 | 
| -  gamepad_shared_memory_.ShareToProcess(process, &renderer_handle);
 | 
| -  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_);
 | 
| -    is_paused_ = true;
 | 
| -  }
 | 
| -  base::MessageLoop* polling_loop = polling_thread_->message_loop();
 | 
| -  polling_loop->task_runner()->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&GamepadProvider::SendPauseHint, Unretained(this), true));
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::Resume() {
 | 
| -  {
 | 
| -    base::AutoLock lock(is_paused_lock_);
 | 
| -    if (!is_paused_)
 | 
| -        return;
 | 
| -    is_paused_ = false;
 | 
| -  }
 | 
| -
 | 
| -  base::MessageLoop* polling_loop = polling_thread_->message_loop();
 | 
| -  polling_loop->task_runner()->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&GamepadProvider::SendPauseHint, Unretained(this), false));
 | 
| -  polling_loop->task_runner()->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      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, base::ThreadTaskRunnerHandle::Get()));
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::OnDevicesChanged(base::SystemMonitor::DeviceType type) {
 | 
| -  base::AutoLock lock(devices_changed_lock_);
 | 
| -  devices_changed_ = true;
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::Initialize(std::unique_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));
 | 
| -  pad_states_.reset(new PadState[WebGamepads::itemsLengthCap]);
 | 
| -
 | 
| -  polling_thread_.reset(new base::Thread("Gamepad polling thread"));
 | 
| -#if defined(OS_LINUX)
 | 
| -  // On Linux, the data fetcher needs to watch file descriptors, so the message
 | 
| -  // loop needs to be a libevent loop.
 | 
| -  const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_IO;
 | 
| -#elif defined(OS_ANDROID)
 | 
| -  // On Android, keeping a message loop of default type.
 | 
| -  const base::MessageLoop::Type kMessageLoopType =
 | 
| -      base::MessageLoop::TYPE_DEFAULT;
 | 
| -#else
 | 
| -  // On Mac, the data fetcher uses IOKit which depends on CFRunLoop, so the
 | 
| -  // message loop needs to be a UI-type loop. On Windows it must be a UI loop
 | 
| -  // to properly pump the MessageWindow that captures device state.
 | 
| -  const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_UI;
 | 
| -#endif
 | 
| -  polling_thread_->StartWithOptions(base::Thread::Options(kMessageLoopType, 0));
 | 
| -
 | 
| -  polling_thread_->task_runner()->PostTask(
 | 
| -      FROM_HERE, base::Bind(&GamepadProvider::DoInitializePollingThread,
 | 
| -                            base::Unretained(this), base::Passed(&fetcher)));
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::DoInitializePollingThread(
 | 
| -    std::unique_ptr<GamepadDataFetcher> fetcher) {
 | 
| -  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
 | 
| -  DCHECK(!data_fetcher_.get());  // Should only initialize once.
 | 
| -
 | 
| -  if (!fetcher)
 | 
| -    fetcher.reset(new GamepadPlatformDataFetcher);
 | 
| -  data_fetcher_ = std::move(fetcher);
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::SendPauseHint(bool paused) {
 | 
| -  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
 | 
| -  if (data_fetcher_)
 | 
| -    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, sizeof(id_)) == 0 &&
 | 
| -         memcmp(mapping_, pad.mapping, sizeof(mapping_)) == 0;
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
 | 
| -  connected_ = pad.connected;
 | 
| -  axes_length_ = pad.axesLength;
 | 
| -  buttons_length_ = pad.buttonsLength;
 | 
| -  memcpy(id_, pad.id, sizeof(id_));
 | 
| -  memcpy(mapping_, pad.mapping, sizeof(mapping_));
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::PadState::SetDisconnected() {
 | 
| -  connected_ = false;
 | 
| -  axes_length_ = 0;
 | 
| -  buttons_length_ = 0;
 | 
| -  memset(id_, 0, sizeof(id_));
 | 
| -  memset(mapping_, 0, sizeof(mapping_));
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::PadState::AsWebGamepad(WebGamepad* pad) {
 | 
| -  pad->connected = connected_;
 | 
| -  pad->axesLength = axes_length_;
 | 
| -  pad->buttonsLength = buttons_length_;
 | 
| -  memcpy(pad->id, id_, sizeof(id_));
 | 
| -  memcpy(pad->mapping, mapping_, sizeof(mapping_));
 | 
| -  memset(pad->axes, 0, sizeof(pad->axes));
 | 
| -  memset(pad->buttons, 0, sizeof(pad->buttons));
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::DoPoll() {
 | 
| -  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
 | 
| -  DCHECK(have_scheduled_do_poll_);
 | 
| -  have_scheduled_do_poll_ = false;
 | 
| -
 | 
| -  bool changed;
 | 
| -  GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
 | 
| -
 | 
| -  ANNOTATE_BENIGN_RACE_SIZED(
 | 
| -      &hwbuf->buffer,
 | 
| -      sizeof(WebGamepads),
 | 
| -      "Racey reads are discarded");
 | 
| -
 | 
| -  {
 | 
| -    base::AutoLock lock(devices_changed_lock_);
 | 
| -    changed = devices_changed_;
 | 
| -    devices_changed_ = false;
 | 
| -  }
 | 
| -
 | 
| -  {
 | 
| -    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();
 | 
| -  }
 | 
| -
 | 
| -  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);
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  CheckForUserGesture();
 | 
| -
 | 
| -  // Schedule our next interval of polling.
 | 
| -  ScheduleDoPoll();
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::ScheduleDoPoll() {
 | 
| -  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
 | 
| -  if (have_scheduled_do_poll_)
 | 
| -    return;
 | 
| -
 | 
| -  {
 | 
| -    base::AutoLock lock(is_paused_lock_);
 | 
| -    if (is_paused_)
 | 
| -      return;
 | 
| -  }
 | 
| -
 | 
| -  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
 | 
| -      FROM_HERE, base::Bind(&GamepadProvider::DoPoll, Unretained(this)),
 | 
| -      base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs));
 | 
| -  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);
 | 
| -  return static_cast<GamepadHardwareBuffer*>(mem);
 | 
| -}
 | 
| -
 | 
| -void GamepadProvider::CheckForUserGesture() {
 | 
| -  base::AutoLock lock(user_gesture_lock_);
 | 
| -  if (user_gesture_observers_.empty() && ever_had_user_gesture_)
 | 
| -    return;
 | 
| -
 | 
| -  bool had_gesture_before = ever_had_user_gesture_;
 | 
| -  const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
 | 
| -  if (GamepadsHaveUserGesture(pads)) {
 | 
| -    ever_had_user_gesture_ = true;
 | 
| -    for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
 | 
| -      user_gesture_observers_[i].task_runner->PostTask(
 | 
| -          FROM_HERE, user_gesture_observers_[i].closure);
 | 
| -    }
 | 
| -    user_gesture_observers_.clear();
 | 
| -  }
 | 
| -  if (!had_gesture_before && ever_had_user_gesture_) {
 | 
| -    // Initialize pad_states_ for the first time.
 | 
| -    for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
 | 
| -      pad_states_.get()[i].SetPad(pads.items[i]);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -}  // namespace content
 | 
| 
 |