mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			557 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			557 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "mozilla/Hal.h"
 | 
						|
#include "mozilla/HalSensor.h"
 | 
						|
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsDeviceSensors.h"
 | 
						|
 | 
						|
#include "nsGlobalWindowInner.h"
 | 
						|
#include "nsPIDOMWindow.h"
 | 
						|
#include "nsIScriptObjectPrincipal.h"
 | 
						|
#include "mozilla/Preferences.h"
 | 
						|
#include "mozilla/StaticPrefs_device.h"
 | 
						|
#include "mozilla/Attributes.h"
 | 
						|
#include "mozilla/dom/BrowsingContext.h"
 | 
						|
#include "mozilla/dom/DeviceLightEvent.h"
 | 
						|
#include "mozilla/dom/DeviceOrientationEvent.h"
 | 
						|
#include "mozilla/dom/Document.h"
 | 
						|
#include "mozilla/dom/Event.h"
 | 
						|
#include "mozilla/dom/UserProximityEvent.h"
 | 
						|
#include "mozilla/ErrorResult.h"
 | 
						|
 | 
						|
#include <cmath>
 | 
						|
 | 
						|
using namespace mozilla;
 | 
						|
using namespace mozilla::dom;
 | 
						|
using namespace hal;
 | 
						|
 | 
						|
class nsIDOMWindow;
 | 
						|
 | 
						|
#undef near
 | 
						|
 | 
						|
#define DEFAULT_SENSOR_POLL 100
 | 
						|
 | 
						|
static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
 | 
						|
    nsTArray<nsIDOMWindow*>::NoIndex;
 | 
						|
 | 
						|
class nsDeviceSensorData final : public nsIDeviceSensorData {
 | 
						|
 public:
 | 
						|
  NS_DECL_ISUPPORTS
 | 
						|
  NS_DECL_NSIDEVICESENSORDATA
 | 
						|
 | 
						|
  nsDeviceSensorData(unsigned long type, double x, double y, double z);
 | 
						|
 | 
						|
 private:
 | 
						|
  ~nsDeviceSensorData();
 | 
						|
 | 
						|
 protected:
 | 
						|
  unsigned long mType;
 | 
						|
  double mX, mY, mZ;
 | 
						|
};
 | 
						|
 | 
						|
nsDeviceSensorData::nsDeviceSensorData(unsigned long type, double x, double y,
 | 
						|
                                       double z)
 | 
						|
    : mType(type), mX(x), mY(y), mZ(z) {}
 | 
						|
 | 
						|
NS_INTERFACE_MAP_BEGIN(nsDeviceSensorData)
 | 
						|
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDeviceSensorData)
 | 
						|
NS_INTERFACE_MAP_END
 | 
						|
 | 
						|
NS_IMPL_ADDREF(nsDeviceSensorData)
 | 
						|
NS_IMPL_RELEASE(nsDeviceSensorData)
 | 
						|
 | 
						|
nsDeviceSensorData::~nsDeviceSensorData() = default;
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensorData::GetType(uint32_t* aType) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aType);
 | 
						|
  *aType = mType;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensorData::GetX(double* aX) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aX);
 | 
						|
  *aX = mX;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensorData::GetY(double* aY) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aY);
 | 
						|
  *aY = mY;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensorData::GetZ(double* aZ) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aZ);
 | 
						|
  *aZ = mZ;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(nsDeviceSensors, nsIDeviceSensors)
 | 
						|
 | 
						|
nsDeviceSensors::nsDeviceSensors() {
 | 
						|
  mIsUserProximityNear = false;
 | 
						|
  mLastDOMMotionEventTime = TimeStamp::Now();
 | 
						|
 | 
						|
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
 | 
						|
    nsTArray<nsIDOMWindow*>* windows = new nsTArray<nsIDOMWindow*>();
 | 
						|
    mWindowListeners.AppendElement(windows);
 | 
						|
  }
 | 
						|
 | 
						|
  mLastDOMMotionEventTime = TimeStamp::Now();
 | 
						|
}
 | 
						|
 | 
						|
nsDeviceSensors::~nsDeviceSensors() {
 | 
						|
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
 | 
						|
    if (IsSensorEnabled(i)) UnregisterSensorObserver((SensorType)i, this);
 | 
						|
  }
 | 
						|
 | 
						|
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
 | 
						|
    delete mWindowListeners[i];
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensors::HasWindowListener(uint32_t aType,
 | 
						|
                                                 nsIDOMWindow* aWindow,
 | 
						|
                                                 bool* aRetVal) {
 | 
						|
  if (!IsSensorAllowedByPref(aType, aWindow))
 | 
						|
    *aRetVal = false;
 | 
						|
  else
 | 
						|
    *aRetVal = mWindowListeners[aType]->IndexOf(aWindow) != NoIndex;
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
class DeviceSensorTestEvent : public Runnable {
 | 
						|
 public:
 | 
						|
  DeviceSensorTestEvent(nsDeviceSensors* aTarget, uint32_t aType)
 | 
						|
      : mozilla::Runnable("DeviceSensorTestEvent"),
 | 
						|
        mTarget(aTarget),
 | 
						|
        mType(aType) {}
 | 
						|
 | 
						|
  NS_IMETHOD Run() override {
 | 
						|
    SensorData sensorData;
 | 
						|
    sensorData.sensor() = static_cast<SensorType>(mType);
 | 
						|
    sensorData.timestamp() = PR_Now();
 | 
						|
    sensorData.values().AppendElement(0.5f);
 | 
						|
    sensorData.values().AppendElement(0.5f);
 | 
						|
    sensorData.values().AppendElement(0.5f);
 | 
						|
    sensorData.values().AppendElement(0.5f);
 | 
						|
    mTarget->Notify(sensorData);
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  RefPtr<nsDeviceSensors> mTarget;
 | 
						|
  uint32_t mType;
 | 
						|
};
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensors::AddWindowListener(uint32_t aType,
 | 
						|
                                                 nsIDOMWindow* aWindow) {
 | 
						|
  if (!IsSensorAllowedByPref(aType, aWindow)) return NS_OK;
 | 
						|
 | 
						|
  if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex) return NS_OK;
 | 
						|
 | 
						|
  if (!IsSensorEnabled(aType)) {
 | 
						|
    RegisterSensorObserver((SensorType)aType, this);
 | 
						|
  }
 | 
						|
 | 
						|
  mWindowListeners[aType]->AppendElement(aWindow);
 | 
						|
 | 
						|
  if (StaticPrefs::device_sensors_test_events()) {
 | 
						|
    nsCOMPtr<nsIRunnable> event = new DeviceSensorTestEvent(this, aType);
 | 
						|
    NS_DispatchToCurrentThread(event);
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensors::RemoveWindowListener(uint32_t aType,
 | 
						|
                                                    nsIDOMWindow* aWindow) {
 | 
						|
  if (mWindowListeners[aType]->IndexOf(aWindow) == NoIndex) return NS_OK;
 | 
						|
 | 
						|
  mWindowListeners[aType]->RemoveElement(aWindow);
 | 
						|
 | 
						|
  if (mWindowListeners[aType]->Length() == 0)
 | 
						|
    UnregisterSensorObserver((SensorType)aType, this);
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP nsDeviceSensors::RemoveWindowAsListener(nsIDOMWindow* aWindow) {
 | 
						|
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
 | 
						|
    RemoveWindowListener((SensorType)i, aWindow);
 | 
						|
  }
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
static bool WindowCannotReceiveSensorEvent(nsPIDOMWindowInner* aWindow) {
 | 
						|
  // Check to see if this window is in the background.
 | 
						|
  if (!aWindow || !aWindow->IsCurrentInnerWindow()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  nsPIDOMWindowOuter* windowOuter = aWindow->GetOuterWindow();
 | 
						|
  BrowsingContext* topBC = aWindow->GetBrowsingContext()->Top();
 | 
						|
  if (windowOuter->IsBackground() || !topBC->GetIsActiveBrowserWindow()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check to see if this window is a cross-origin iframe:
 | 
						|
  if (!topBC->IsInProcess()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
 | 
						|
  nsCOMPtr<nsIScriptObjectPrincipal> topSop =
 | 
						|
      do_QueryInterface(topBC->GetDOMWindow());
 | 
						|
  if (!sop || !topSop) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  nsIPrincipal* principal = sop->GetPrincipal();
 | 
						|
  nsIPrincipal* topPrincipal = topSop->GetPrincipal();
 | 
						|
  if (!principal || !topPrincipal) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  return !principal->Subsumes(topPrincipal);
 | 
						|
}
 | 
						|
 | 
						|
// Holds the device orientation in Euler angle degrees (azimuth, pitch, roll).
 | 
						|
struct Orientation {
 | 
						|
  enum OrientationReference { kRelative = 0, kAbsolute };
 | 
						|
 | 
						|
  static Orientation RadToDeg(const Orientation& aOrient) {
 | 
						|
    const static double kRadToDeg = 180.0 / M_PI;
 | 
						|
    return {aOrient.alpha * kRadToDeg, aOrient.beta * kRadToDeg,
 | 
						|
            aOrient.gamma * kRadToDeg};
 | 
						|
  }
 | 
						|
 | 
						|
  double alpha;
 | 
						|
  double beta;
 | 
						|
  double gamma;
 | 
						|
};
 | 
						|
 | 
						|
static Orientation RotationVectorToOrientation(double aX, double aY, double aZ,
 | 
						|
                                               double aW) {
 | 
						|
  double mat[9];
 | 
						|
 | 
						|
  mat[0] = 1 - 2 * aY * aY - 2 * aZ * aZ;
 | 
						|
  mat[1] = 2 * aX * aY - 2 * aZ * aW;
 | 
						|
  mat[2] = 2 * aX * aZ + 2 * aY * aW;
 | 
						|
 | 
						|
  mat[3] = 2 * aX * aY + 2 * aZ * aW;
 | 
						|
  mat[4] = 1 - 2 * aX * aX - 2 * aZ * aZ;
 | 
						|
  mat[5] = 2 * aY * aZ - 2 * aX * aW;
 | 
						|
 | 
						|
  mat[6] = 2 * aX * aZ - 2 * aY * aW;
 | 
						|
  mat[7] = 2 * aY * aZ + 2 * aX * aW;
 | 
						|
  mat[8] = 1 - 2 * aX * aX - 2 * aY * aY;
 | 
						|
 | 
						|
  Orientation orient;
 | 
						|
 | 
						|
  if (mat[8] > 0) {
 | 
						|
    orient.alpha = atan2(-mat[1], mat[4]);
 | 
						|
    orient.beta = asin(mat[7]);
 | 
						|
    orient.gamma = atan2(-mat[6], mat[8]);
 | 
						|
  } else if (mat[8] < 0) {
 | 
						|
    orient.alpha = atan2(mat[1], -mat[4]);
 | 
						|
    orient.beta = -asin(mat[7]);
 | 
						|
    orient.beta += (orient.beta >= 0) ? -M_PI : M_PI;
 | 
						|
    orient.gamma = atan2(mat[6], -mat[8]);
 | 
						|
  } else {
 | 
						|
    if (mat[6] > 0) {
 | 
						|
      orient.alpha = atan2(-mat[1], mat[4]);
 | 
						|
      orient.beta = asin(mat[7]);
 | 
						|
      orient.gamma = -M_PI_2;
 | 
						|
    } else if (mat[6] < 0) {
 | 
						|
      orient.alpha = atan2(mat[1], -mat[4]);
 | 
						|
      orient.beta = -asin(mat[7]);
 | 
						|
      orient.beta += (orient.beta >= 0) ? -M_PI : M_PI;
 | 
						|
      orient.gamma = -M_PI_2;
 | 
						|
    } else {
 | 
						|
      orient.alpha = atan2(mat[3], mat[0]);
 | 
						|
      orient.beta = (mat[7] > 0) ? M_PI_2 : -M_PI_2;
 | 
						|
      orient.gamma = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (orient.alpha < 0) {
 | 
						|
    orient.alpha += 2 * M_PI;
 | 
						|
  }
 | 
						|
 | 
						|
  return Orientation::RadToDeg(orient);
 | 
						|
}
 | 
						|
 | 
						|
void nsDeviceSensors::Notify(const mozilla::hal::SensorData& aSensorData) {
 | 
						|
  uint32_t type = aSensorData.sensor();
 | 
						|
 | 
						|
  const nsTArray<float>& values = aSensorData.values();
 | 
						|
  size_t len = values.Length();
 | 
						|
  double x = len > 0 ? values[0] : 0.0;
 | 
						|
  double y = len > 1 ? values[1] : 0.0;
 | 
						|
  double z = len > 2 ? values[2] : 0.0;
 | 
						|
  double w = len > 3 ? values[3] : 0.0;
 | 
						|
  PRTime timestamp = aSensorData.timestamp();
 | 
						|
 | 
						|
  nsCOMArray<nsIDOMWindow> windowListeners;
 | 
						|
  for (uint32_t i = 0; i < mWindowListeners[type]->Length(); i++) {
 | 
						|
    windowListeners.AppendObject(mWindowListeners[type]->SafeElementAt(i));
 | 
						|
  }
 | 
						|
 | 
						|
  for (uint32_t i = windowListeners.Count(); i > 0;) {
 | 
						|
    --i;
 | 
						|
 | 
						|
    nsCOMPtr<nsPIDOMWindowInner> pwindow =
 | 
						|
        do_QueryInterface(windowListeners[i]);
 | 
						|
    if (WindowCannotReceiveSensorEvent(pwindow)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (nsCOMPtr<Document> doc = pwindow->GetDoc()) {
 | 
						|
      nsCOMPtr<mozilla::dom::EventTarget> target =
 | 
						|
          do_QueryInterface(windowListeners[i]);
 | 
						|
      if (type == nsIDeviceSensorData::TYPE_ACCELERATION ||
 | 
						|
          type == nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION ||
 | 
						|
          type == nsIDeviceSensorData::TYPE_GYROSCOPE) {
 | 
						|
        FireDOMMotionEvent(doc, target, type, timestamp, x, y, z);
 | 
						|
      } else if (type == nsIDeviceSensorData::TYPE_ORIENTATION) {
 | 
						|
        FireDOMOrientationEvent(target, x, y, z, Orientation::kAbsolute);
 | 
						|
      } else if (type == nsIDeviceSensorData::TYPE_ROTATION_VECTOR) {
 | 
						|
        const Orientation orient = RotationVectorToOrientation(x, y, z, w);
 | 
						|
        FireDOMOrientationEvent(target, orient.alpha, orient.beta, orient.gamma,
 | 
						|
                                Orientation::kAbsolute);
 | 
						|
      } else if (type == nsIDeviceSensorData::TYPE_GAME_ROTATION_VECTOR) {
 | 
						|
        const Orientation orient = RotationVectorToOrientation(x, y, z, w);
 | 
						|
        FireDOMOrientationEvent(target, orient.alpha, orient.beta, orient.gamma,
 | 
						|
                                Orientation::kRelative);
 | 
						|
      } else if (type == nsIDeviceSensorData::TYPE_PROXIMITY) {
 | 
						|
        MaybeFireDOMUserProximityEvent(target, x, z);
 | 
						|
      } else if (type == nsIDeviceSensorData::TYPE_LIGHT) {
 | 
						|
        FireDOMLightEvent(target, x);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsDeviceSensors::FireDOMLightEvent(mozilla::dom::EventTarget* aTarget,
 | 
						|
                                        double aValue) {
 | 
						|
  DeviceLightEventInit init;
 | 
						|
  init.mBubbles = true;
 | 
						|
  init.mCancelable = false;
 | 
						|
  init.mValue = round(aValue);
 | 
						|
  RefPtr<DeviceLightEvent> event =
 | 
						|
      DeviceLightEvent::Constructor(aTarget, u"devicelight"_ns, init);
 | 
						|
 | 
						|
  event->SetTrusted(true);
 | 
						|
 | 
						|
  aTarget->DispatchEvent(*event);
 | 
						|
}
 | 
						|
 | 
						|
void nsDeviceSensors::MaybeFireDOMUserProximityEvent(
 | 
						|
    mozilla::dom::EventTarget* aTarget, double aValue, double aMax) {
 | 
						|
  bool near = (aValue < aMax);
 | 
						|
  if (mIsUserProximityNear != near) {
 | 
						|
    mIsUserProximityNear = near;
 | 
						|
    FireDOMUserProximityEvent(aTarget, mIsUserProximityNear);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsDeviceSensors::FireDOMUserProximityEvent(
 | 
						|
    mozilla::dom::EventTarget* aTarget, bool aNear) {
 | 
						|
  UserProximityEventInit init;
 | 
						|
  init.mBubbles = true;
 | 
						|
  init.mCancelable = false;
 | 
						|
  init.mNear = aNear;
 | 
						|
  RefPtr<UserProximityEvent> event =
 | 
						|
      UserProximityEvent::Constructor(aTarget, u"userproximity"_ns, init);
 | 
						|
 | 
						|
  event->SetTrusted(true);
 | 
						|
 | 
						|
  aTarget->DispatchEvent(*event);
 | 
						|
}
 | 
						|
 | 
						|
void nsDeviceSensors::FireDOMOrientationEvent(EventTarget* aTarget,
 | 
						|
                                              double aAlpha, double aBeta,
 | 
						|
                                              double aGamma, bool aIsAbsolute) {
 | 
						|
  DeviceOrientationEventInit init;
 | 
						|
  init.mBubbles = true;
 | 
						|
  init.mCancelable = false;
 | 
						|
  init.mAlpha.SetValue(aAlpha);
 | 
						|
  init.mBeta.SetValue(aBeta);
 | 
						|
  init.mGamma.SetValue(aGamma);
 | 
						|
  init.mAbsolute = aIsAbsolute;
 | 
						|
 | 
						|
  auto Dispatch = [&](EventTarget* aEventTarget, const nsAString& aType) {
 | 
						|
    RefPtr<DeviceOrientationEvent> event =
 | 
						|
        DeviceOrientationEvent::Constructor(aEventTarget, aType, init);
 | 
						|
    event->SetTrusted(true);
 | 
						|
    aEventTarget->DispatchEvent(*event);
 | 
						|
  };
 | 
						|
 | 
						|
  Dispatch(aTarget, aIsAbsolute ? u"deviceorientationabsolute"_ns
 | 
						|
                                : u"deviceorientation"_ns);
 | 
						|
 | 
						|
  // This is used to determine whether relative events have been dispatched
 | 
						|
  // during the current session, in which case we don't dispatch the additional
 | 
						|
  // compatibility events.
 | 
						|
  static bool sIsDispatchingRelativeEvents = false;
 | 
						|
  sIsDispatchingRelativeEvents = sIsDispatchingRelativeEvents || !aIsAbsolute;
 | 
						|
 | 
						|
  // Android devices with SENSOR_GAME_ROTATION_VECTOR support dispatch
 | 
						|
  // relative events for "deviceorientation" by default, while other platforms
 | 
						|
  // and devices without such support dispatch absolute events by default.
 | 
						|
  if (aIsAbsolute && !sIsDispatchingRelativeEvents) {
 | 
						|
    // For absolute events on devices without support for relative events,
 | 
						|
    // we need to additionally dispatch type "deviceorientation" to keep
 | 
						|
    // backwards-compatibility.
 | 
						|
    Dispatch(aTarget, u"deviceorientation"_ns);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsDeviceSensors::FireDOMMotionEvent(Document* doc, EventTarget* target,
 | 
						|
                                         uint32_t type, PRTime timestamp,
 | 
						|
                                         double x, double y, double z) {
 | 
						|
  // Attempt to coalesce events
 | 
						|
  TimeDuration sensorPollDuration =
 | 
						|
      TimeDuration::FromMilliseconds(DEFAULT_SENSOR_POLL);
 | 
						|
  bool fireEvent =
 | 
						|
      (TimeStamp::Now() > mLastDOMMotionEventTime + sensorPollDuration) ||
 | 
						|
      StaticPrefs::device_sensors_test_events();
 | 
						|
 | 
						|
  switch (type) {
 | 
						|
    case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
 | 
						|
      if (!mLastAcceleration) {
 | 
						|
        mLastAcceleration.emplace();
 | 
						|
      }
 | 
						|
      mLastAcceleration->mX.SetValue(x);
 | 
						|
      mLastAcceleration->mY.SetValue(y);
 | 
						|
      mLastAcceleration->mZ.SetValue(z);
 | 
						|
      break;
 | 
						|
    case nsIDeviceSensorData::TYPE_ACCELERATION:
 | 
						|
      if (!mLastAccelerationIncludingGravity) {
 | 
						|
        mLastAccelerationIncludingGravity.emplace();
 | 
						|
      }
 | 
						|
      mLastAccelerationIncludingGravity->mX.SetValue(x);
 | 
						|
      mLastAccelerationIncludingGravity->mY.SetValue(y);
 | 
						|
      mLastAccelerationIncludingGravity->mZ.SetValue(z);
 | 
						|
      break;
 | 
						|
    case nsIDeviceSensorData::TYPE_GYROSCOPE:
 | 
						|
      if (!mLastRotationRate) {
 | 
						|
        mLastRotationRate.emplace();
 | 
						|
      }
 | 
						|
      mLastRotationRate->mAlpha.SetValue(x);
 | 
						|
      mLastRotationRate->mBeta.SetValue(y);
 | 
						|
      mLastRotationRate->mGamma.SetValue(z);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fireEvent) {
 | 
						|
    if (!mLastAcceleration) {
 | 
						|
      mLastAcceleration.emplace();
 | 
						|
    }
 | 
						|
    if (!mLastAccelerationIncludingGravity) {
 | 
						|
      mLastAccelerationIncludingGravity.emplace();
 | 
						|
    }
 | 
						|
    if (!mLastRotationRate) {
 | 
						|
      mLastRotationRate.emplace();
 | 
						|
    }
 | 
						|
  } else if (!mLastAcceleration || !mLastAccelerationIncludingGravity ||
 | 
						|
             !mLastRotationRate) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  IgnoredErrorResult ignored;
 | 
						|
  RefPtr<Event> event =
 | 
						|
      doc->CreateEvent(u"DeviceMotionEvent"_ns, CallerType::System, ignored);
 | 
						|
  if (!event) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DeviceMotionEvent* me = static_cast<DeviceMotionEvent*>(event.get());
 | 
						|
 | 
						|
  me->InitDeviceMotionEvent(
 | 
						|
      u"devicemotion"_ns, true, false, *mLastAcceleration,
 | 
						|
      *mLastAccelerationIncludingGravity, *mLastRotationRate,
 | 
						|
      Nullable<double>(DEFAULT_SENSOR_POLL), Nullable<uint64_t>(timestamp));
 | 
						|
 | 
						|
  event->SetTrusted(true);
 | 
						|
 | 
						|
  target->DispatchEvent(*event);
 | 
						|
 | 
						|
  mLastRotationRate.reset();
 | 
						|
  mLastAccelerationIncludingGravity.reset();
 | 
						|
  mLastAcceleration.reset();
 | 
						|
  mLastDOMMotionEventTime = TimeStamp::Now();
 | 
						|
}
 | 
						|
 | 
						|
bool nsDeviceSensors::IsSensorAllowedByPref(uint32_t aType,
 | 
						|
                                            nsIDOMWindow* aWindow) {
 | 
						|
  // checks "device.sensors.enabled" master pref
 | 
						|
  if (!StaticPrefs::device_sensors_enabled()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aWindow);
 | 
						|
  nsCOMPtr<Document> doc;
 | 
						|
  if (window) {
 | 
						|
    doc = window->GetExtantDoc();
 | 
						|
  }
 | 
						|
 | 
						|
  switch (aType) {
 | 
						|
    case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
 | 
						|
    case nsIDeviceSensorData::TYPE_ACCELERATION:
 | 
						|
    case nsIDeviceSensorData::TYPE_GYROSCOPE:
 | 
						|
      // checks "device.sensors.motion.enabled" pref
 | 
						|
      if (!StaticPrefs::device_sensors_motion_enabled()) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (doc) {
 | 
						|
        doc->WarnOnceAbout(DeprecatedOperations::eMotionEvent);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case nsIDeviceSensorData::TYPE_GAME_ROTATION_VECTOR:
 | 
						|
    case nsIDeviceSensorData::TYPE_ORIENTATION:
 | 
						|
    case nsIDeviceSensorData::TYPE_ROTATION_VECTOR:
 | 
						|
      // checks "device.sensors.orientation.enabled" pref
 | 
						|
      if (!StaticPrefs::device_sensors_orientation_enabled()) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (doc) {
 | 
						|
        doc->WarnOnceAbout(DeprecatedOperations::eOrientationEvent);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case nsIDeviceSensorData::TYPE_PROXIMITY:
 | 
						|
      // checks "device.sensors.proximity.enabled" pref
 | 
						|
      if (!StaticPrefs::device_sensors_proximity_enabled()) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (doc) {
 | 
						|
        doc->WarnOnceAbout(DeprecatedOperations::eProximityEvent, true);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case nsIDeviceSensorData::TYPE_LIGHT:
 | 
						|
      // checks "device.sensors.ambientLight.enabled" pref
 | 
						|
      if (!StaticPrefs::device_sensors_ambientLight_enabled()) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (doc) {
 | 
						|
        doc->WarnOnceAbout(DeprecatedOperations::eAmbientLightEvent, true);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      MOZ_ASSERT_UNREACHABLE("Device sensor type not recognised");
 | 
						|
      return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!window) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return !nsGlobalWindowInner::Cast(window)->ShouldResistFingerprinting(
 | 
						|
      RFPTarget::DeviceSensors);
 | 
						|
}
 |