Bug 965533 - fix the zoom attribute, r=dhylands
authorMike Habicher <mikeh@mozilla.com>
Fri, 21 Feb 2014 13:14:52 -0500
changeset 170352 aee74e1d49588138e5442e8fc2c049161a7f4163
parent 170351 0383ab44b60225f3807781a4b5fdf168949b9135
child 170353 e3054db31b8fa10883a8c8ce6cff31af4b3500f6
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersdhylands
bugs965533
milestone30.0a1
Bug 965533 - fix the zoom attribute, r=dhylands
dom/camera/GonkCameraParameters.cpp
dom/camera/GonkCameraParameters.h
dom/camera/test/test_camera.html
--- a/dom/camera/GonkCameraParameters.cpp
+++ b/dom/camera/GonkCameraParameters.cpp
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2013 Mozilla Foundation
+ * Copyright (C) 2013-2014 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
@@ -148,16 +148,20 @@ GonkCameraParameters::Initialize()
   rv = GetImpl(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, mExposureCompensationMin);
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = GetImpl(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, mExposureCompensationStep);
   if (NS_FAILED(rv)) {
     return rv;
   }
+  rv = GetListAsArray(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, mZoomRatios);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   mInitialized = true;
   return NS_OK;
 }
 
 // Handle nsAStrings
 nsresult
 GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue)
@@ -396,45 +400,82 @@ GonkCameraParameters::GetTranslated(uint
   aValue = val;
   return NS_OK;
 }
 
 // Handle doubles
 nsresult
 GonkCameraParameters::SetTranslated(uint32_t aKey, const double& aValue)
 {
-  if (aKey == CAMERA_PARAM_EXPOSURECOMPENSATION) {
-    /**
-     * Convert from real value to a Gonk index, round
-     * to the nearest step; index is 1-based.
-     */
-    int index =
-      (aValue - mExposureCompensationMin + mExposureCompensationStep / 2) /
-      mExposureCompensationStep + 1;
-    DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index);
-    return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index);
+  int index;
+  int value;
+
+  switch (aKey) {
+    case CAMERA_PARAM_EXPOSURECOMPENSATION:
+      /**
+       * Convert from real value to a Gonk index, round
+       * to the nearest step; index is 1-based.
+       */
+      index =
+        (aValue - mExposureCompensationMin + mExposureCompensationStep / 2) /
+        mExposureCompensationStep + 1;
+      DOM_CAMERA_LOGI("Exposure compensation = %f --> index = %d\n", aValue, index);
+      return SetImpl(CAMERA_PARAM_EXPOSURECOMPENSATION, index);
+
+    case CAMERA_PARAM_ZOOM:
+      {
+        /**
+         * Convert from a real zoom multipler (e.g. 2.5x) to
+         * the index of the nearest supported value.
+         */
+        value = aValue * 100.0;
+
+        // mZoomRatios is sorted, so we can binary search it
+        unsigned int bottom = 0;
+        unsigned int top = mZoomRatios.Length() - 1;
+        unsigned int middle;
+
+        while (bottom != top) {
+          middle = (top + bottom) / 2;
+          if (value == mZoomRatios[middle]) {
+            // exact match
+            break;
+          }
+          if (value > mZoomRatios[middle] && value < mZoomRatios[middle + 1]) {
+            // the specified zoom value lies in this interval
+            break;
+          }
+          if (value > mZoomRatios[middle]) {
+            bottom = middle + 1;
+          } else {
+            top = middle - 1;
+          }
+        }
+        index = middle;
+      }
+      return SetImpl(CAMERA_PARAM_ZOOM, index);
   }
 
   return SetImpl(aKey, aValue);
 }
 
 nsresult
 GonkCameraParameters::GetTranslated(uint32_t aKey, double& aValue)
 {
   double val;
   int index = 0;
   double focusDistance[3];
   const char* s;
   nsresult rv;
 
   switch (aKey) {
     case CAMERA_PARAM_ZOOM:
-      rv = GetImpl(CAMERA_PARAM_ZOOM, val);
+      rv = GetImpl(CAMERA_PARAM_ZOOM, index);
       if (NS_SUCCEEDED(rv)) {
-        val /= 100.0;
+        val = mZoomRatios[index] / 100.0;
       } else {
         // return 1x when zooming is not supported
         val = 1.0;
       }
       break;
 
     /**
      * The gonk camera parameters API only exposes one focus distance property
@@ -552,16 +593,26 @@ ParseItem(const char* aStart, const char
 {
   if (sscanf(aStart, "%lf", aItem) == 1) {
     return NS_OK;
   }
 
   return NS_ERROR_FAILURE;
 }
 
+nsresult
+ParseItem(const char* aStart, const char* aEnd, int* aItem)
+{
+  if (sscanf(aStart, "%d", aItem) == 1) {
+    return NS_OK;
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
 template<class T> nsresult
 GonkCameraParameters::GetListAsArray(uint32_t aKey, nsTArray<T>& aArray)
 {
   const char* p;
   nsresult rv = GetImpl(aKey, p);
   if (NS_FAILED(rv)) {
     return rv;
   }
@@ -604,16 +655,24 @@ nsresult
 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<nsString>& aValues)
 {
   return GetListAsArray(aKey, aValues);
 }
 
 nsresult
 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<double>& aValues)
 {
+  if (aKey == CAMERA_PARAM_SUPPORTED_ZOOMRATIOS) {
+    aValues.Clear();
+    for (int i = 0; i < mZoomRatios.Length(); ++i) {
+      *aValues.AppendElement() = mZoomRatios[i] / 100.0;
+    }
+    return NS_OK;
+  }
+
   return GetListAsArray(aKey, aValues);
 }
 
 nsresult
 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<ICameraControl::Size>& aSizes)
 {
   return GetListAsArray(aKey, aSizes);
 }
--- a/dom/camera/GonkCameraParameters.h
+++ b/dom/camera/GonkCameraParameters.h
@@ -89,16 +89,17 @@ public:
 protected:
   PRRWLock* mLock;
   bool mDirty;
   bool mInitialized;
 
   // Required internal properties
   double mExposureCompensationMin;
   double mExposureCompensationStep;
+  nsTArray<int> mZoomRatios;
 
   // This subclass of android::CameraParameters just gives
   // all of the AOSP getters and setters the same signature.
   class Parameters : public android::CameraParameters
   {
   public:
     using android::CameraParameters::set;
 
--- a/dom/camera/test/test_camera.html
+++ b/dom/camera/test/test_camera.html
@@ -28,32 +28,33 @@ var config = {
   rotation: 90
 };
 
 function onError(e) {
   ok(false, "Error" + JSON.stringify(e));
 }
 
 var capabilities = [ 'previewSizes', 'pictureSizes', 'fileFormats', 'maxFocusAreas', 'minExposureCompensation',
-                     'maxExposureCompensation', 'stepExposureCompensation', 'maxMeteringAreas', 'videoSizes', 
-                     'recorderProfiles'];
+                     'maxExposureCompensation', 'stepExposureCompensation', 'maxMeteringAreas', 'videoSizes',
+                     'recorderProfiles', 'zoomRatios'];
 
 var Camera = {
   cameraObj: null,
   _recording: false,
   _currentTest: null,
   _autoFocusSupported: 0,
   _manuallyFocused: false,
   _flashmodes: null,
   _pictureSizes: null,
   _previewSizes: null,
   _whiteBalanceModes: null,
   _zoomRatios: null,
   _sceneModes: null,
   _focusModes: null,
+  _zoomRatios: null,
   _testsCompleted: 0,
   _shutter: 0,
   _config: {
     dateTime: Date.now() / 1000,
     pictureSize: null,
     fileFormat: 'jpeg',
     rotation: 90
   },
@@ -62,16 +63,22 @@ var Camera = {
     return document.getElementById('viewfinder');
   },
   setFlashMode: function camera_setFlash(mode) {
     this.cameraObj.flashMode = mode;
   },
   setFocus: function camera_setfocus(mode) {
     this.cameraObj.focus = mode;
   },
+  setZoom: function camera_setZoom(zoom) {
+    this.cameraObj.zoom = zoom;
+  },
+  getZoom: function camera_getZoom() {
+    return this.cameraObj.zoom;
+  },
   getFileFormats: function camera_formats() {
     this._fileFormats = this.cameraObj.capabilities.fileFormats;
   },
   getFlashModes: function camera_getFlash() {
     this._flashmodes = this.cameraObj.capabilities.flashModes;
   },
   getFocusModes: function camera_getFocus() {
     this._focusModes = this.cameraObj.capabilities.focusModes;
@@ -86,16 +93,19 @@ var Camera = {
     this._whitebalanceModes = this.cameraObj.capabilities.whiteBalanceModes;
   },
   getPictureSizes: function camera_sizes() {
     this._pictureSizes = this.cameraObj.capabilities.pictureSizes;
   },
   getPreviewSizes: function camera_preview() {
     this._previewSizes = this.cameraObj.capabilities.previewSizes;
   },
+  getZoomRatios: function camera_preview() {
+    this._zoomRatios = this.cameraObj.capabilities.zoomRatios;
+  },
   takePictureSuccess: function taken_foto(blob) {
     var img = new Image();
     var test = this._currentTest;
     img.onload = function Imgsize() {
       ok(this.width == test.pictureSize.width, "The image taken has the width " + 
                                               this.width + " pictureSize width = " + test.pictureSize.width);
       ok(this.height == test.pictureSize.height, "The image taken has the height " + 
                                               this.height + " picturesize height = " + test.pictureSize.height);
@@ -132,19 +142,45 @@ var Camera = {
       if(camcap[prop] && camcap[prop].length > 1)  {
         tests[prop] = camcap[prop];
       }
     }
     Camera.getPictureSizes();
     Camera.getPreviewSizes();
     Camera.getFileFormats();
     Camera.getFocusModes();
+    Camera.getZoomRatios();
     ok(Camera._previewSizes.length > 0, "previewSizes length = " + Camera._previewSizes.length);
     ok(Camera._pictureSizes.length > 0, "picturesizes length = " + Camera._pictureSizes.length);
     ok(Camera._fileFormats.length > 0, "file formats length = " + Camera._fileFormats.length);
+    info("zoom ratios length = " + Camera._zoomRatios.length);
+
+    if (Camera._zoomRatios.length > 0) {
+      Camera._zoomRatios.forEach(function(element, index) {
+        info("zoom[" + index + "] = " + element + "x");
+        Camera.setZoom(element);
+        ok(Camera.getZoom() === element, "zoom[" + index + "] = " + element + "x");
+      });
+
+      var zoom = Camera._zoomRatios[0] - 0.1;
+      Camera.setZoom(zoom);
+      ok(Camera.getZoom() === Camera._zoomRatios[0],
+        zoom + "x zoom clamps to minimum: " + Camera._zoomRatios[0]);
+      zoom = Camera._zoomRatios.slice(-1)[0] + 1.0;
+      Camera.setZoom(zoom);
+      ok(Camera.getZoom() === Camera._zoomRatios[0],
+        zoom + "x zoom clamps to maximum: " + Camera._zoomRatios.slice(-1)[0]);
+      if (Camera._zoomRatios.length > 1) {
+        zoom = (Camera._zoomRatios[0] + Camera._zoomRatios[1]) / 2;
+        Camera.setZoom(zoom);
+        ok(Camera.getZoom() === Camera._zoomRatios[0],
+          zoom + "x zoom rounded down to maximum: " + Camera._zoomRatios.slice[0]);
+      }
+    }
+
     Camera._tests = new Array();
     for (var i in Camera._pictureSizes) {
       for (var l in Camera._fileFormats) {
         var config = {
           pictureSize: Camera._pictureSizes[i],
           fileFormat: Camera._fileFormats[l]
         };
         Camera._tests.push(config);