dom/camera/DOMCameraManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/camera/DOMCameraManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,453 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "DOMCameraManager.h"
     1.9 +#include "nsDebug.h"
    1.10 +#include "jsapi.h"
    1.11 +#include "Navigator.h"
    1.12 +#include "nsPIDOMWindow.h"
    1.13 +#include "mozilla/Services.h"
    1.14 +#include "nsContentPermissionHelper.h"
    1.15 +#include "nsIObserverService.h"
    1.16 +#include "nsIPermissionManager.h"
    1.17 +#include "DOMCameraControl.h"
    1.18 +#include "nsDOMClassInfo.h"
    1.19 +#include "CameraCommon.h"
    1.20 +#include "mozilla/dom/BindingUtils.h"
    1.21 +#include "mozilla/dom/CameraManagerBinding.h"
    1.22 +#include "mozilla/dom/PermissionMessageUtils.h"
    1.23 +#include "mozilla/dom/TabChild.h"
    1.24 +#include "PCOMContentPermissionRequestChild.h"
    1.25 +
    1.26 +using namespace mozilla;
    1.27 +using namespace mozilla::dom;
    1.28 +
    1.29 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCameraManager, mWindow)
    1.30 +
    1.31 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager)
    1.32 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
    1.33 +  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    1.34 +  NS_INTERFACE_MAP_ENTRY(nsIObserver)
    1.35 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    1.36 +NS_INTERFACE_MAP_END
    1.37 +
    1.38 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraManager)
    1.39 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCameraManager)
    1.40 +
    1.41 +/**
    1.42 + * Global camera logging object
    1.43 + *
    1.44 + * Set the NSPR_LOG_MODULES environment variable to enable logging
    1.45 + * in a debug build, e.g. NSPR_LOG_MODULES=Camera:5
    1.46 + */
    1.47 +PRLogModuleInfo*
    1.48 +GetCameraLog()
    1.49 +{
    1.50 +  static PRLogModuleInfo *sLog;
    1.51 +  if (!sLog) {
    1.52 +    sLog = PR_NewLogModule("Camera");
    1.53 +  }
    1.54 +  return sLog;
    1.55 +}
    1.56 +
    1.57 +WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
    1.58 +
    1.59 +nsDOMCameraManager::nsDOMCameraManager(nsPIDOMWindow* aWindow)
    1.60 +  : mWindowId(aWindow->WindowID())
    1.61 +  , mPermission(nsIPermissionManager::DENY_ACTION)
    1.62 +  , mWindow(aWindow)
    1.63 +{
    1.64 +  /* member initializers and constructor code */
    1.65 +  DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%llx\n", __func__, __LINE__, this, mWindowId);
    1.66 +  MOZ_COUNT_CTOR(nsDOMCameraManager);
    1.67 +  SetIsDOMBinding();
    1.68 +}
    1.69 +
    1.70 +nsDOMCameraManager::~nsDOMCameraManager()
    1.71 +{
    1.72 +  /* destructor code */
    1.73 +  MOZ_COUNT_DTOR(nsDOMCameraManager);
    1.74 +  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
    1.75 +}
    1.76 +
    1.77 +/* static */
    1.78 +void
    1.79 +nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv)
    1.80 +{
    1.81 +  aRv = ICameraControl::GetListOfCameras(aList);
    1.82 +}
    1.83 +
    1.84 +/* static */
    1.85 +bool
    1.86 +nsDOMCameraManager::HasSupport(JSContext* aCx, JSObject* aGlobal)
    1.87 +{
    1.88 +  return Navigator::HasCameraSupport(aCx, aGlobal);
    1.89 +}
    1.90 +
    1.91 +/* static */
    1.92 +bool
    1.93 +nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow)
    1.94 +{
    1.95 +  nsCOMPtr<nsIPermissionManager> permMgr =
    1.96 +    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
    1.97 +  NS_ENSURE_TRUE(permMgr, false);
    1.98 +
    1.99 +  uint32_t permission = nsIPermissionManager::DENY_ACTION;
   1.100 +  permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
   1.101 +  if (permission != nsIPermissionManager::ALLOW_ACTION &&
   1.102 +      permission != nsIPermissionManager::PROMPT_ACTION) {
   1.103 +    return false;
   1.104 +  }
   1.105 +
   1.106 +  return true;
   1.107 +}
   1.108 +
   1.109 +/* static */
   1.110 +already_AddRefed<nsDOMCameraManager>
   1.111 +nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
   1.112 +{
   1.113 +  // Initialize the shared active window tracker
   1.114 +  if (!sActiveWindows) {
   1.115 +    sActiveWindows = new WindowTable();
   1.116 +  }
   1.117 +
   1.118 +  nsRefPtr<nsDOMCameraManager> cameraManager =
   1.119 +    new nsDOMCameraManager(aWindow);
   1.120 +
   1.121 +  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   1.122 +  obs->AddObserver(cameraManager, "xpcom-shutdown", true);
   1.123 +
   1.124 +  return cameraManager.forget();
   1.125 +}
   1.126 +
   1.127 +class CameraPermissionRequest : public nsIContentPermissionRequest
   1.128 +                              , public PCOMContentPermissionRequestChild
   1.129 +                              , public nsIRunnable
   1.130 +{
   1.131 +public:
   1.132 +  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   1.133 +  NS_DECL_NSICONTENTPERMISSIONREQUEST
   1.134 +  NS_DECL_NSIRUNNABLE
   1.135 +  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CameraPermissionRequest,
   1.136 +                                           nsIContentPermissionRequest)
   1.137 +
   1.138 +  CameraPermissionRequest(nsIPrincipal* aPrincipal,
   1.139 +                          nsPIDOMWindow* aWindow,
   1.140 +                          nsRefPtr<nsDOMCameraManager> aManager,
   1.141 +                          uint32_t aCameraId,
   1.142 +                          const CameraConfiguration& aInitialConfig,
   1.143 +                          nsRefPtr<GetCameraCallback> aOnSuccess,
   1.144 +                          nsRefPtr<CameraErrorCallback> aOnError)
   1.145 +    : mPrincipal(aPrincipal)
   1.146 +    , mWindow(aWindow)
   1.147 +    , mCameraManager(aManager)
   1.148 +    , mCameraId(aCameraId)
   1.149 +    , mInitialConfig(aInitialConfig)
   1.150 +    , mOnSuccess(aOnSuccess)
   1.151 +    , mOnError(aOnError)
   1.152 +  {
   1.153 +  }
   1.154 +
   1.155 +  virtual ~CameraPermissionRequest()
   1.156 +  {
   1.157 +  }
   1.158 +
   1.159 +  bool Recv__delete__(const bool& aAllow,
   1.160 +                      const InfallibleTArray<PermissionChoice>& choices);
   1.161 +
   1.162 +  void IPDLRelease()
   1.163 +  {
   1.164 +    Release();
   1.165 +  }
   1.166 +
   1.167 +protected:
   1.168 +  nsresult DispatchCallback(uint32_t aPermission);
   1.169 +  void CallAllow();
   1.170 +  void CallCancel();
   1.171 +  nsCOMPtr<nsIPrincipal> mPrincipal;
   1.172 +  nsCOMPtr<nsPIDOMWindow> mWindow;
   1.173 +  nsRefPtr<nsDOMCameraManager> mCameraManager;
   1.174 +  uint32_t mCameraId;
   1.175 +  CameraConfiguration mInitialConfig;
   1.176 +  nsRefPtr<GetCameraCallback> mOnSuccess;
   1.177 +  nsRefPtr<CameraErrorCallback> mOnError;
   1.178 +};
   1.179 +
   1.180 +NS_IMPL_CYCLE_COLLECTION(CameraPermissionRequest, mWindow, mOnSuccess, mOnError)
   1.181 +
   1.182 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraPermissionRequest)
   1.183 +  NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
   1.184 +  NS_INTERFACE_MAP_ENTRY(nsIRunnable)
   1.185 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   1.186 +NS_INTERFACE_MAP_END
   1.187 +
   1.188 +NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraPermissionRequest)
   1.189 +NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraPermissionRequest)
   1.190 +
   1.191 +NS_IMETHODIMP
   1.192 +CameraPermissionRequest::Run()
   1.193 +{
   1.194 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.195 +    TabChild* child = TabChild::GetFrom(mWindow->GetDocShell());
   1.196 +    if (!child) {
   1.197 +      return NS_ERROR_NOT_AVAILABLE;
   1.198 +    }
   1.199 +
   1.200 +    // Retain a reference so the object isn't deleted without IPDL's knowledge.
   1.201 +    // Corresponding release occurs in DeallocPContentPermissionRequest.
   1.202 +    AddRef();
   1.203 +
   1.204 +    nsTArray<PermissionRequest> permArray;
   1.205 +    nsTArray<nsString> emptyOptions;
   1.206 +    permArray.AppendElement(PermissionRequest(
   1.207 +                            NS_LITERAL_CSTRING("camera"),
   1.208 +                            NS_LITERAL_CSTRING("unused"),
   1.209 +                            emptyOptions));
   1.210 +    child->SendPContentPermissionRequestConstructor(this, permArray,
   1.211 +                                                    IPC::Principal(mPrincipal));
   1.212 +
   1.213 +    Sendprompt();
   1.214 +    return NS_OK;
   1.215 +  }
   1.216 +
   1.217 +  nsCOMPtr<nsIContentPermissionPrompt> prompt =
   1.218 +    do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   1.219 +  if (prompt) {
   1.220 +    prompt->Prompt(this);
   1.221 +  }
   1.222 +
   1.223 +  return NS_OK;
   1.224 +}
   1.225 +
   1.226 +bool
   1.227 +CameraPermissionRequest::Recv__delete__(const bool& aAllow,
   1.228 +                                        const InfallibleTArray<PermissionChoice>& choices)
   1.229 +{
   1.230 +  if (aAllow) {
   1.231 +    Allow(JS::UndefinedHandleValue);
   1.232 +  } else {
   1.233 +    Cancel();
   1.234 +  }
   1.235 +  return true;
   1.236 +}
   1.237 +
   1.238 +NS_IMETHODIMP
   1.239 +CameraPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal)
   1.240 +{
   1.241 +  NS_ADDREF(*aRequestingPrincipal = mPrincipal);
   1.242 +  return NS_OK;
   1.243 +}
   1.244 +
   1.245 +NS_IMETHODIMP
   1.246 +CameraPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
   1.247 +{
   1.248 +  NS_ADDREF(*aRequestingWindow = mWindow);
   1.249 +  return NS_OK;
   1.250 +}
   1.251 +
   1.252 +NS_IMETHODIMP
   1.253 +CameraPermissionRequest::GetElement(nsIDOMElement** aElement)
   1.254 +{
   1.255 +  *aElement = nullptr;
   1.256 +  return NS_OK;
   1.257 +}
   1.258 +
   1.259 +NS_IMETHODIMP
   1.260 +CameraPermissionRequest::Cancel()
   1.261 +{
   1.262 +  return DispatchCallback(nsIPermissionManager::DENY_ACTION);
   1.263 +}
   1.264 +
   1.265 +NS_IMETHODIMP
   1.266 +CameraPermissionRequest::Allow(JS::HandleValue aChoices)
   1.267 +{
   1.268 +  MOZ_ASSERT(aChoices.isUndefined());
   1.269 +  return DispatchCallback(nsIPermissionManager::ALLOW_ACTION);
   1.270 +}
   1.271 +
   1.272 +nsresult
   1.273 +CameraPermissionRequest::DispatchCallback(uint32_t aPermission)
   1.274 +{
   1.275 +  nsCOMPtr<nsIRunnable> callbackRunnable;
   1.276 +  if (aPermission == nsIPermissionManager::ALLOW_ACTION) {
   1.277 +    callbackRunnable = NS_NewRunnableMethod(this, &CameraPermissionRequest::CallAllow);
   1.278 +  } else {
   1.279 +    callbackRunnable = NS_NewRunnableMethod(this, &CameraPermissionRequest::CallCancel);
   1.280 +  }
   1.281 +  return NS_DispatchToMainThread(callbackRunnable);
   1.282 +}
   1.283 +
   1.284 +void
   1.285 +CameraPermissionRequest::CallAllow()
   1.286 +{
   1.287 +  mCameraManager->PermissionAllowed(mCameraId, mInitialConfig, mOnSuccess, mOnError);
   1.288 +}
   1.289 +
   1.290 +void
   1.291 +CameraPermissionRequest::CallCancel()
   1.292 +{
   1.293 +  mCameraManager->PermissionCancelled(mCameraId, mInitialConfig, mOnSuccess, mOnError);
   1.294 +}
   1.295 +
   1.296 +NS_IMETHODIMP
   1.297 +CameraPermissionRequest::GetTypes(nsIArray** aTypes)
   1.298 +{
   1.299 +  nsTArray<nsString> emptyOptions;
   1.300 +  return CreatePermissionArray(NS_LITERAL_CSTRING("camera"),
   1.301 +                               NS_LITERAL_CSTRING("unused"),
   1.302 +                               emptyOptions,
   1.303 +                               aTypes);
   1.304 +}
   1.305 +
   1.306 +void
   1.307 +nsDOMCameraManager::GetCamera(const nsAString& aCamera,
   1.308 +                              const CameraConfiguration& aInitialConfig,
   1.309 +                              GetCameraCallback& aOnSuccess,
   1.310 +                              const OptionalNonNullCameraErrorCallback& aOnError,
   1.311 +                              ErrorResult& aRv)
   1.312 +{
   1.313 +  DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
   1.314 +
   1.315 +  uint32_t cameraId = 0;  // back (or forward-facing) camera by default
   1.316 +  if (aCamera.EqualsLiteral("front")) {
   1.317 +    cameraId = 1;
   1.318 +  }
   1.319 +
   1.320 +  nsRefPtr<CameraErrorCallback> errorCallback = nullptr;
   1.321 +  if (aOnError.WasPassed()) {
   1.322 +    errorCallback = &aOnError.Value();
   1.323 +  }
   1.324 +
   1.325 +  if (mPermission == nsIPermissionManager::ALLOW_ACTION) {
   1.326 +    PermissionAllowed(cameraId, aInitialConfig, &aOnSuccess, errorCallback);
   1.327 +    return;
   1.328 +  }
   1.329 +
   1.330 +  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
   1.331 +  if (!sop) {
   1.332 +    aRv.Throw(NS_ERROR_UNEXPECTED);
   1.333 +    return;
   1.334 +  }
   1.335 +
   1.336 +  nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
   1.337 +
   1.338 +  nsCOMPtr<nsIRunnable> permissionRequest =
   1.339 +    new CameraPermissionRequest(principal, mWindow, this, cameraId, aInitialConfig,
   1.340 +                                &aOnSuccess, errorCallback);
   1.341 +
   1.342 +  NS_DispatchToMainThread(permissionRequest);
   1.343 +}
   1.344 +
   1.345 +void
   1.346 +nsDOMCameraManager::PermissionAllowed(uint32_t aCameraId,
   1.347 +                                      const CameraConfiguration& aInitialConfig,
   1.348 +                                      GetCameraCallback* aOnSuccess,
   1.349 +                                      CameraErrorCallback* aOnError)
   1.350 +{
   1.351 +  mPermission = nsIPermissionManager::ALLOW_ACTION;
   1.352 +
   1.353 +  // Creating this object will trigger the aOnSuccess callback
   1.354 +  //  (or the aOnError one, if it fails).
   1.355 +  nsRefPtr<nsDOMCameraControl> cameraControl =
   1.356 +    new nsDOMCameraControl(aCameraId, aInitialConfig, aOnSuccess, aOnError, mWindow);
   1.357 +
   1.358 +  Register(cameraControl);
   1.359 +}
   1.360 +
   1.361 +void
   1.362 +nsDOMCameraManager::PermissionCancelled(uint32_t aCameraId,
   1.363 +                                        const CameraConfiguration& aInitialConfig,
   1.364 +                                        GetCameraCallback* aOnSuccess,
   1.365 +                                        CameraErrorCallback* aOnError)
   1.366 +{
   1.367 +  mPermission = nsIPermissionManager::DENY_ACTION;
   1.368 +
   1.369 +  if (aOnError) {
   1.370 +    ErrorResult ignored;
   1.371 +    aOnError->Call(NS_LITERAL_STRING("Permission denied."), ignored);
   1.372 +  }
   1.373 +}
   1.374 +
   1.375 +void
   1.376 +nsDOMCameraManager::Register(nsDOMCameraControl* aDOMCameraControl)
   1.377 +{
   1.378 +  DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%llx\n", aDOMCameraControl, mWindowId);
   1.379 +  MOZ_ASSERT(NS_IsMainThread());
   1.380 +
   1.381 +  // Put the camera control into the hash table
   1.382 +  CameraControls* controls = sActiveWindows->Get(mWindowId);
   1.383 +  if (!controls) {
   1.384 +    controls = new CameraControls;
   1.385 +    sActiveWindows->Put(mWindowId, controls);
   1.386 +  }
   1.387 +  controls->AppendElement(aDOMCameraControl);
   1.388 +}
   1.389 +
   1.390 +void
   1.391 +nsDOMCameraManager::Shutdown(uint64_t aWindowId)
   1.392 +{
   1.393 +  DOM_CAMERA_LOGI(">>> Shutdown( aWindowId = 0x%llx )\n", aWindowId);
   1.394 +  MOZ_ASSERT(NS_IsMainThread());
   1.395 +
   1.396 +  CameraControls* controls = sActiveWindows->Get(aWindowId);
   1.397 +  if (!controls) {
   1.398 +    return;
   1.399 +  }
   1.400 +
   1.401 +  uint32_t length = controls->Length();
   1.402 +  for (uint32_t i = 0; i < length; i++) {
   1.403 +    nsRefPtr<nsDOMCameraControl> cameraControl = controls->ElementAt(i);
   1.404 +    cameraControl->Shutdown();
   1.405 +  }
   1.406 +  controls->Clear();
   1.407 +
   1.408 +  sActiveWindows->Remove(aWindowId);
   1.409 +}
   1.410 +
   1.411 +void
   1.412 +nsDOMCameraManager::XpComShutdown()
   1.413 +{
   1.414 +  DOM_CAMERA_LOGI(">>> XPCOM Shutdown\n");
   1.415 +  MOZ_ASSERT(NS_IsMainThread());
   1.416 +
   1.417 +  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   1.418 +  obs->RemoveObserver(this, "xpcom-shutdown");
   1.419 +
   1.420 +  delete sActiveWindows;
   1.421 +  sActiveWindows = nullptr;
   1.422 +}
   1.423 +
   1.424 +nsresult
   1.425 +nsDOMCameraManager::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
   1.426 +{
   1.427 +  if (strcmp(aTopic, "xpcom-shutdown") == 0) {
   1.428 +    XpComShutdown();
   1.429 +  }
   1.430 +  return NS_OK;
   1.431 +}
   1.432 +
   1.433 +void
   1.434 +nsDOMCameraManager::OnNavigation(uint64_t aWindowId)
   1.435 +{
   1.436 +  DOM_CAMERA_LOGI(">>> OnNavigation event\n");
   1.437 +  Shutdown(aWindowId);
   1.438 +}
   1.439 +
   1.440 +bool
   1.441 +nsDOMCameraManager::IsWindowStillActive(uint64_t aWindowId)
   1.442 +{
   1.443 +  MOZ_ASSERT(NS_IsMainThread());
   1.444 +
   1.445 +  if (!sActiveWindows) {
   1.446 +    return false;
   1.447 +  }
   1.448 +
   1.449 +  return !!sActiveWindows->Get(aWindowId);
   1.450 +}
   1.451 +
   1.452 +JSObject*
   1.453 +nsDOMCameraManager::WrapObject(JSContext* aCx)
   1.454 +{
   1.455 +  return CameraManagerBinding::Wrap(aCx, this);
   1.456 +}

mercurial