10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file.
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "data_fetcher_shared_memory.h"
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <GuidDef.h>
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <InitGuid.h>
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <PortableDeviceTypes.h>
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <Sensors.h>
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/logging.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/win/iunknown_impl.h"
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/win/windows_version.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace {
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const double kMeanGravity = 9.80665;
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}  // namespace
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace content {
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class DataFetcherSharedMemory::SensorEventSink
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : public ISensorEvents, public base::win::IUnknownImpl {
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SensorEventSink() {}
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~SensorEventSink() {}
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // IUnknown interface
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE {
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return IUnknownImpl::AddRef();
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE {
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return IUnknownImpl::Release();
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE {
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (riid == __uuidof(ISensorEvents)) {
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      *ppv = static_cast<ISensorEvents*>(this);
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AddRef();
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return S_OK;
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return IUnknownImpl::QueryInterface(riid, ppv);
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // ISensorEvents interface
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  STDMETHODIMP OnEvent(ISensor* sensor,
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                       REFGUID event_id,
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                       IPortableDeviceValues* event_data) OVERRIDE {
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return S_OK;
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) OVERRIDE {
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return S_OK;
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) OVERRIDE {
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return S_OK;
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  STDMETHODIMP OnDataUpdated(ISensor* sensor,
66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                             ISensorDataReport* new_data) OVERRIDE {
67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (NULL == new_data || NULL == sensor)
68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return E_INVALIDARG;
69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return UpdateSharedMemoryBuffer(sensor, new_data) ? S_OK : E_FAIL;
70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)protected:
73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual bool UpdateSharedMemoryBuffer(
74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ISensor* sensor, ISensorDataReport* new_data) = 0;
75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void GetSensorValue(REFPROPERTYKEY property, ISensorDataReport* new_data,
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      double* value, bool* has_value) {
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    PROPVARIANT variant_value = {};
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (SUCCEEDED(new_data->GetSensorValue(property, &variant_value))) {
80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (variant_value.vt == VT_R8)
81d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        *value = variant_value.dblVal;
82d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      else if (variant_value.vt == VT_R4)
83d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        *value = variant_value.fltVal;
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      *has_value = true;
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else {
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      *value = 0;
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      *has_value = false;
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private:
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SensorEventSink);
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class DataFetcherSharedMemory::SensorEventSinkOrientation
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : public DataFetcherSharedMemory::SensorEventSink {
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  explicit SensorEventSinkOrientation(
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {}
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~SensorEventSinkOrientation() {}
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)protected:
104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual bool UpdateSharedMemoryBuffer(
105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ISensor* sensor, ISensorDataReport* new_data) OVERRIDE {
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    double alpha, beta, gamma;
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool has_alpha, has_beta, has_gamma;
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetSensorValue(SENSOR_DATA_TYPE_TILT_X_DEGREES, new_data, &alpha,
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        &has_alpha);
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES, new_data, &beta,
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        &has_beta);
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES, new_data, &gamma,
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        &has_gamma);
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (buffer_) {
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->seqlock.WriteBegin();
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.alpha = alpha;
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.hasAlpha = has_alpha;
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.beta = beta;
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.hasBeta = has_beta;
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.gamma = gamma;
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.hasGamma = has_gamma;
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.absolute = true;
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.hasAbsolute = has_alpha || has_beta || has_gamma;
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->data.allAvailableSensorsAreActive = true;
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      buffer_->seqlock.WriteEnd();
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return true;
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private:
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DeviceOrientationHardwareBuffer* const buffer_;
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation);
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class DataFetcherSharedMemory::SensorEventSinkMotion
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : public DataFetcherSharedMemory::SensorEventSink {
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public:
142d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer)
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      : buffer_(buffer) {}
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~SensorEventSinkMotion() {}
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) protected:
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual bool UpdateSharedMemoryBuffer(
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ISensor* sensor, ISensorDataReport* new_data) OVERRIDE {
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    SENSOR_TYPE_ID sensor_type = GUID_NULL;
15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!SUCCEEDED(sensor->GetType(&sensor_type)))
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return false;
15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (IsEqualIID(sensor_type, SENSOR_TYPE_ACCELEROMETER_3D)) {
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      double acceleration_including_gravity_x;
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      double acceleration_including_gravity_y;
157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      double acceleration_including_gravity_z;
158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      bool has_acceleration_including_gravity_x;
159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      bool has_acceleration_including_gravity_y;
160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      bool has_acceleration_including_gravity_z;
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, new_data,
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &acceleration_including_gravity_x,
164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &has_acceleration_including_gravity_x);
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, new_data,
166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &acceleration_including_gravity_y,
167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &has_acceleration_including_gravity_y);
16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, new_data,
169d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &acceleration_including_gravity_z,
170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          &has_acceleration_including_gravity_z);
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (buffer_) {
173d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->seqlock.WriteBegin();
174d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.accelerationIncludingGravityX =
175d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            -acceleration_including_gravity_x * kMeanGravity;
176d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.hasAccelerationIncludingGravityX =
177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            has_acceleration_including_gravity_x;
178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.accelerationIncludingGravityY =
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            -acceleration_including_gravity_y * kMeanGravity;
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.hasAccelerationIncludingGravityY =
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            has_acceleration_including_gravity_y;
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.accelerationIncludingGravityZ =
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            -acceleration_including_gravity_z * kMeanGravity;
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.hasAccelerationIncludingGravityZ =
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            has_acceleration_including_gravity_z;
1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        // TODO(timvolodine): consider setting this after all
1878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        // sensors have fired.
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.allAvailableSensorsAreActive = true;
189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->seqlock.WriteEnd();
190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
19158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
19258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else if (IsEqualIID(sensor_type, SENSOR_TYPE_GYROMETER_3D)) {
19358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      double alpha, beta, gamma;
19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      bool has_alpha, has_beta, has_gamma;
19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
19658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND,
19758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          new_data, &alpha, &has_alpha);
19858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND,
19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          new_data, &beta, &has_beta);
20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND,
20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          new_data, &gamma, &has_gamma);
20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (buffer_) {
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->seqlock.WriteBegin();
205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.rotationRateAlpha = alpha;
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.hasRotationRateAlpha = has_alpha;
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.rotationRateBeta = beta;
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.hasRotationRateBeta = has_beta;
209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.rotationRateGamma = gamma;
210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.hasRotationRateGamma = has_gamma;
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->data.allAvailableSensorsAreActive = true;
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        buffer_->seqlock.WriteEnd();
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return true;
21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  private:
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)   DeviceMotionHardwareBuffer* const buffer_;
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)   DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion);
22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) };
22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)DataFetcherSharedMemory::DataFetcherSharedMemory()
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : motion_buffer_(NULL),
22858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      orientation_buffer_(NULL) {
22958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
23058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
23158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)DataFetcherSharedMemory::~DataFetcherSharedMemory() {
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
23358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const {
2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return FETCHER_TYPE_SEPARATE_THREAD;
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
23858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
23958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(buffer);
24058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  switch (consumer_type) {
24258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case CONSUMER_TYPE_ORIENTATION:
24358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      {
24458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        orientation_buffer_ =
24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            static_cast<DeviceOrientationHardwareBuffer*>(buffer);
24658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        scoped_refptr<SensorEventSink> sink(
24758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            new SensorEventSinkOrientation(orientation_buffer_));
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        bool inclinometer_available = RegisterForSensor(
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SENSOR_TYPE_INCLINOMETER_3D, sensor_inclinometer_.Receive(), sink);
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        UMA_HISTOGRAM_BOOLEAN("InertialSensor.InclinometerWindowsAvailable",
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            inclinometer_available);
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (inclinometer_available)
25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return true;
25458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        // if no sensors are available set buffer to ready, to fire null-events.
25558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        SetBufferAvailableState(consumer_type, true);
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
25858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case CONSUMER_TYPE_MOTION:
25958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      {
26058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
26158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        scoped_refptr<SensorEventSink> sink(
26258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            new SensorEventSinkMotion(motion_buffer_));
26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        bool accelerometer_available = RegisterForSensor(
26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            SENSOR_TYPE_ACCELEROMETER_3D, sensor_accelerometer_.Receive(),
26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            sink);
26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        bool gyrometer_available = RegisterForSensor(
26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            SENSOR_TYPE_GYROMETER_3D, sensor_gyrometer_.Receive(), sink);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerWindowsAvailable",
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            accelerometer_available);
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyrometerWindowsAvailable",
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            gyrometer_available);
2728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        if (accelerometer_available || gyrometer_available) {
2738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          motion_buffer_->seqlock.WriteBegin();
2748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          motion_buffer_->data.interval = GetInterval().InMilliseconds();
2758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          motion_buffer_->seqlock.WriteEnd();
27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return true;
2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        }
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        // if no sensors are available set buffer to ready, to fire null-events.
27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        SetBufferAvailableState(consumer_type, true);
28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      break;
28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    default:
28358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      NOTREACHED();
28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return false;
28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
289d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DisableSensors(consumer_type);
290d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetBufferAvailableState(consumer_type, false);
29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  switch (consumer_type) {
29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case CONSUMER_TYPE_ORIENTATION:
29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      orientation_buffer_ = NULL;
29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return true;
29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    case CONSUMER_TYPE_MOTION:
29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      motion_buffer_ = NULL;
29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return true;
29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    default:
29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      NOTREACHED();
30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return false;
30258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DataFetcherSharedMemory::RegisterForSensor(
30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    REFSENSOR_TYPE_ID sensor_type,
30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ISensor** sensor,
30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    scoped_refptr<SensorEventSink> event_sink) {
30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_WIN7)
30958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
31158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::win::ScopedComPtr<ISensorManager> sensor_manager;
31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager);
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (FAILED(hr) || !sensor_manager)
31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
31658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::win::ScopedComPtr<ISensorCollection> sensor_collection;
31758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hr = sensor_manager->GetSensorsByType(
31858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      sensor_type, sensor_collection.Receive());
31958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
32058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (FAILED(hr) || !sensor_collection)
32158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
32258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
32358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  ULONG count = 0;
32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hr = sensor_collection->GetCount(&count);
32558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (FAILED(hr) || !count)
32658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
32758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
32858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hr = sensor_collection->GetAt(0, sensor);
329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (FAILED(hr) || !(*sensor))
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
33158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
33258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::win::ScopedComPtr<IPortableDeviceValues> device_values;
33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (SUCCEEDED(device_values.CreateInstance(CLSID_PortableDeviceValues))) {
33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (SUCCEEDED(device_values->SetUnsignedIntegerValue(
3358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL,
3368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        GetInterval().InMilliseconds()))) {
33758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::win::ScopedComPtr<IPortableDeviceValues> return_values;
33858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      (*sensor)->SetProperties(device_values.get(), return_values.Receive());
33958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
34058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
34158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::win::ScopedComPtr<ISensorEvents> sensor_events;
34358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hr = event_sink->QueryInterface(
34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      __uuidof(ISensorEvents), sensor_events.ReceiveVoid());
34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (FAILED(hr) || !sensor_events)
34658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
34858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hr = (*sensor)->SetEventSink(sensor_events);
34958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (FAILED(hr))
35058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
35158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
35358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
35458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
355d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void DataFetcherSharedMemory::DisableSensors(ConsumerType consumer_type) {
356d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  switch(consumer_type) {
357d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case CONSUMER_TYPE_ORIENTATION:
358d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (sensor_inclinometer_) {
359d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        sensor_inclinometer_->SetEventSink(NULL);
360d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        sensor_inclinometer_.Release();
361d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
362d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
363d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case CONSUMER_TYPE_MOTION:
364d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (sensor_accelerometer_) {
365d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        sensor_accelerometer_->SetEventSink(NULL);
366d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        sensor_accelerometer_.Release();
367d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
368d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (sensor_gyrometer_) {
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        sensor_gyrometer_->SetEventSink(NULL);
370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        sensor_gyrometer_.Release();
371d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
372d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
373d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    default:
374d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      NOTREACHED();
375d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
376d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
377d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
378d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void DataFetcherSharedMemory::SetBufferAvailableState(
379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ConsumerType consumer_type, bool enabled) {
380d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  switch(consumer_type) {
381d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case CONSUMER_TYPE_ORIENTATION:
382d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (orientation_buffer_) {
383d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        orientation_buffer_->seqlock.WriteBegin();
384d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        orientation_buffer_->data.allAvailableSensorsAreActive = enabled;
385d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        orientation_buffer_->seqlock.WriteEnd();
386d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
38746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      break;
388d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case CONSUMER_TYPE_MOTION:
389d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (motion_buffer_) {
390d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        motion_buffer_->seqlock.WriteBegin();
391d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        motion_buffer_->data.allAvailableSensorsAreActive = enabled;
392d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        motion_buffer_->seqlock.WriteEnd();
393d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
39446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      break;
395d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    default:
396d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      NOTREACHED();
397d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
398d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
399d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
40058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}  // namespace content
401