Bug 987954 - Change camera control size/region attributes to methods to remove direct JS_*() calls, r=bz,mikeh

This commit is contained in:
Andrew Osmond 2014-04-30 17:15:01 -04:00
parent 00313d85ac
commit 5a4c2c9703
5 changed files with 212 additions and 130 deletions

View File

@ -224,124 +224,84 @@ nsDOMCameraControl::IsWindowStillActive()
return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID());
}
// JS-to-native helpers
// Setter for weighted regions: { top, bottom, left, right, weight }
nsresult
nsDOMCameraControl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit)
nsDOMCameraControl::Set(uint32_t aKey, const Optional<Sequence<CameraRegion> >& aValue, uint32_t aLimit)
{
if (aLimit == 0) {
DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
return NS_OK;
}
if (!aValue.isObject()) {
return NS_ERROR_INVALID_ARG;
}
uint32_t length = 0;
JS::Rooted<JSObject*> regions(aCx, &aValue.toObject());
if (!JS_GetArrayLength(aCx, regions, &length)) {
return NS_ERROR_FAILURE;
}
DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
if (length > aLimit) {
length = aLimit;
}
nsTArray<ICameraControl::Region> regionArray;
regionArray.SetCapacity(length);
if (aValue.WasPassed()) {
const Sequence<CameraRegion>& regions = aValue.Value();
uint32_t length = regions.Length();
for (uint32_t i = 0; i < length; ++i) {
JS::Rooted<JS::Value> v(aCx);
if (!JS_GetElement(aCx, regions, i, &v)) {
return NS_ERROR_FAILURE;
DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
if (length > aLimit) {
length = aLimit;
}
CameraRegion region;
if (!region.Init(aCx, v)) {
return NS_ERROR_FAILURE;
// aLimit supplied by camera library provides sane ceiling (i.e. <10)
regionArray.SetCapacity(length);
for (uint32_t i = 0; i < length; ++i) {
ICameraControl::Region* r = regionArray.AppendElement();
const CameraRegion &region = regions[i];
r->top = region.mTop;
r->left = region.mLeft;
r->bottom = region.mBottom;
r->right = region.mRight;
r->weight = region.mWeight;
DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n",
i,
r->top,
r->left,
r->bottom,
r->right,
r->weight
);
}
ICameraControl::Region* r = regionArray.AppendElement();
r->top = region.mTop;
r->left = region.mLeft;
r->bottom = region.mBottom;
r->right = region.mRight;
r->weight = region.mWeight;
DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n",
i,
r->top,
r->left,
r->bottom,
r->right,
r->weight
);
} else {
DOM_CAMERA_LOGI("%s:%d : clear regions\n", __func__, __LINE__);
}
return mCameraControl->Set(aKey, regionArray);
}
// Getter for weighted regions: { top, bottom, left, right, weight }
nsresult
nsDOMCameraControl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
nsDOMCameraControl::Get(uint32_t aKey, nsTArray<CameraRegion>& aValue)
{
nsTArray<ICameraControl::Region> regionArray;
nsresult rv = mCameraControl->Get(aKey, regionArray);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t length = regionArray.Length();
DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
aValue.SetLength(length);
for (uint32_t i = 0; i < length; ++i) {
ICameraControl::Region* r = &regionArray[i];
JS::Rooted<JS::Value> v(aCx);
ICameraControl::Region& r = regionArray[i];
CameraRegion& v = aValue[i];
v.mTop = r.top;
v.mLeft = r.left;
v.mBottom = r.bottom;
v.mRight = r.right;
v.mWeight = r.weight;
JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
if (!o) {
return NS_ERROR_OUT_OF_MEMORY;
}
DOM_CAMERA_LOGI("top=%d\n", r->top);
v = INT_TO_JSVAL(r->top);
if (!JS_SetProperty(aCx, o, "top", v)) {
return NS_ERROR_FAILURE;
}
DOM_CAMERA_LOGI("left=%d\n", r->left);
v = INT_TO_JSVAL(r->left);
if (!JS_SetProperty(aCx, o, "left", v)) {
return NS_ERROR_FAILURE;
}
DOM_CAMERA_LOGI("bottom=%d\n", r->bottom);
v = INT_TO_JSVAL(r->bottom);
if (!JS_SetProperty(aCx, o, "bottom", v)) {
return NS_ERROR_FAILURE;
}
DOM_CAMERA_LOGI("right=%d\n", r->right);
v = INT_TO_JSVAL(r->right);
if (!JS_SetProperty(aCx, o, "right", v)) {
return NS_ERROR_FAILURE;
}
DOM_CAMERA_LOGI("weight=%d\n", r->weight);
v = INT_TO_JSVAL(r->weight);
if (!JS_SetProperty(aCx, o, "weight", v)) {
return NS_ERROR_FAILURE;
}
if (!JS_SetElement(aCx, array, i, o)) {
return NS_ERROR_FAILURE;
}
DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n",
i,
v.mTop,
v.mLeft,
v.mBottom,
v.mRight,
v.mWeight
);
}
*aValue = JS::ObjectValue(*array);
return NS_OK;
}
@ -440,33 +400,27 @@ nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
}
/* attribute jsval meteringAreas; */
JS::Value
nsDOMCameraControl::GetMeteringAreas(JSContext* cx, ErrorResult& aRv)
{
JS::Rooted<JS::Value> areas(cx);
aRv = Get(cx, CAMERA_PARAM_METERINGAREAS, areas.address());
return areas;
}
void
nsDOMCameraControl::SetMeteringAreas(JSContext* cx, JS::Handle<JS::Value> aMeteringAreas, ErrorResult& aRv)
nsDOMCameraControl::GetMeteringAreas(nsTArray<CameraRegion>& aAreas, ErrorResult& aRv)
{
aRv = Set(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas,
aRv = Get(CAMERA_PARAM_METERINGAREAS, aAreas);
}
void
nsDOMCameraControl::SetMeteringAreas(const Optional<Sequence<CameraRegion> >& aMeteringAreas, ErrorResult& aRv)
{
aRv = Set(CAMERA_PARAM_METERINGAREAS, aMeteringAreas,
mCurrentConfiguration->mMaxMeteringAreas);
}
JS::Value
nsDOMCameraControl::GetFocusAreas(JSContext* cx, ErrorResult& aRv)
void
nsDOMCameraControl::GetFocusAreas(nsTArray<CameraRegion>& aAreas, ErrorResult& aRv)
{
JS::Rooted<JS::Value> value(cx);
aRv = Get(cx, CAMERA_PARAM_FOCUSAREAS, value.address());
return value;
aRv = Get(CAMERA_PARAM_FOCUSAREAS, aAreas);
}
void
nsDOMCameraControl::SetFocusAreas(JSContext* cx, JS::Handle<JS::Value> aFocusAreas, ErrorResult& aRv)
nsDOMCameraControl::SetFocusAreas(const Optional<Sequence<CameraRegion> >& aFocusAreas, ErrorResult& aRv)
{
aRv = Set(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas,
aRv = Set(CAMERA_PARAM_FOCUSAREAS, aFocusAreas,
mCurrentConfiguration->mMaxFocusAreas);
}
@ -493,7 +447,7 @@ GetSize(JSContext* aCx, JS::Value* aValue, const ICameraControl::Size& aSize)
return NS_OK;
}
/* attribute any pictureSize */
/* attribute any pictureSize, deprecated */
JS::Value
nsDOMCameraControl::GetPictureSize(JSContext* cx, ErrorResult& aRv)
{
@ -521,7 +475,26 @@ nsDOMCameraControl::SetPictureSize(JSContext* aCx, JS::Handle<JS::Value> aSize,
aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
}
/* attribute any thumbnailSize */
void
nsDOMCameraControl::GetPictureSize(CameraSize& aSize, ErrorResult& aRv)
{
ICameraControl::Size size;
aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
if (aRv.Failed()) {
return;
}
aSize.mWidth = size.width;
aSize.mHeight = size.height;
}
void
nsDOMCameraControl::SetPictureSize(const CameraSize& aSize, ErrorResult& aRv)
{
ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
}
/* attribute any thumbnailSize, deprecated */
JS::Value
nsDOMCameraControl::GetThumbnailSize(JSContext* aCx, ErrorResult& aRv)
{
@ -549,6 +522,25 @@ nsDOMCameraControl::SetThumbnailSize(JSContext* aCx, JS::Handle<JS::Value> aSize
aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
}
void
nsDOMCameraControl::GetThumbnailSize(CameraSize& aSize, ErrorResult& aRv)
{
ICameraControl::Size size;
aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size);
if (aRv.Failed()) {
return;
}
aSize.mWidth = size.width;
aSize.mHeight = size.height;
}
void
nsDOMCameraControl::SetThumbnailSize(const CameraSize& aSize, ErrorResult& aRv)
{
ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
}
double
nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
{

View File

@ -28,6 +28,8 @@ namespace dom {
class CameraCapabilities;
class CameraPictureOptions;
class CameraStartRecordingOptions;
class CameraRegion;
class CameraSize;
template<typename T> class Optional;
}
class ErrorResult;
@ -70,10 +72,6 @@ public:
void SetFocusMode(const nsAString& aMode, ErrorResult& aRv);
double GetZoom(ErrorResult& aRv);
void SetZoom(double aZoom, ErrorResult& aRv);
JS::Value GetMeteringAreas(JSContext* aCx, ErrorResult& aRv);
void SetMeteringAreas(JSContext* aCx, JS::Handle<JS::Value> aAreas, ErrorResult& aRv);
JS::Value GetFocusAreas(JSContext* aCx, ErrorResult& aRv);
void SetFocusAreas(JSContext* aCx, JS::Handle<JS::Value> aAreas, ErrorResult& aRv);
JS::Value GetPictureSize(JSContext* aCx, ErrorResult& aRv);
void SetPictureSize(JSContext* aCx, JS::Handle<JS::Value> aSize, ErrorResult& aRv);
JS::Value GetThumbnailSize(JSContext* aCx, ErrorResult& aRv);
@ -108,6 +106,14 @@ public:
const dom::Optional<dom::OwningNonNull<dom::CameraSetConfigurationCallback> >& aOnSuccess,
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
ErrorResult& aRv);
void GetMeteringAreas(nsTArray<dom::CameraRegion>& aAreas, ErrorResult& aRv);
void SetMeteringAreas(const dom::Optional<dom::Sequence<dom::CameraRegion> >& aAreas, ErrorResult& aRv);
void GetFocusAreas(nsTArray<dom::CameraRegion>& aAreas, ErrorResult& aRv);
void SetFocusAreas(const dom::Optional<dom::Sequence<dom::CameraRegion> >& aAreas, ErrorResult& aRv);
void GetPictureSize(dom::CameraSize& aSize, ErrorResult& aRv);
void SetPictureSize(const dom::CameraSize& aSize, ErrorResult& aRv);
void GetThumbnailSize(dom::CameraSize& aSize, ErrorResult& aRv);
void SetThumbnailSize(const dom::CameraSize& aSize, ErrorResult& aRv);
void AutoFocus(dom::CameraAutoFocusCallback& aOnSuccess,
const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
ErrorResult& aRv);
@ -178,8 +184,8 @@ protected:
// An agent used to join audio channel service.
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit);
nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue);
nsresult Set(uint32_t aKey, const dom::Optional<dom::Sequence<dom::CameraRegion> >& aValue, uint32_t aLimit);
nsresult Get(uint32_t aKey, nsTArray<dom::CameraRegion>& aValue);
nsRefPtr<DOMCameraConfiguration> mCurrentConfiguration;
nsRefPtr<dom::CameraCapabilities> mCapabilities;

View File

@ -55,14 +55,14 @@ var tests = [
{
key: "set-picture-size-after-release",
func: function testSetPictureSize(camera) {
camera.pictureSize = { width: 0, height: 0 };
camera.setPictureSize({ width: 0, height: 0 });
next();
}
},
{
key: "set-thumbnail-size-after-release",
func: function testSetThumbnailSize(camera) {
camera.thumbnailSize = { width: 0, height: 0 };
camera.setThumbnailSize({ width: 0, height: 0 });
next();
}
},
@ -191,7 +191,7 @@ var Camera = {
"capabilities.pictureSizes.length = " +
camera.capabilities.pictureSizes.length);
Camera._otherPictureSize = camera.capabilities.pictureSizes.slice(-1)[0];
camera.pictureSize = camera.capabilities.pictureSizes[0];
camera.setPictureSize(camera.capabilities.pictureSizes[0]);
options.pictureSize = Camera._otherPictureSize;
options.fileFormat = camera.capabilities.fileFormats[0];
info("getCamera callback, setting pictureSize = " + options.pictureSize.toSource());

View File

@ -142,6 +142,74 @@ var tests = [
next();
}
},
{
key: "fake-metering-areas",
prep: function setupFakeMeteringAreas(test) {
test.setFakeParameters("max-num-metering-areas=1", function () {
run();
});
},
test: function testFakeMeteringAreas(cam, cap) {
ok(cap.maxMeteringAreas == 1, "maxMeteringAreas = " + cap.maxMeteringAreas);
cam.setMeteringAreas([
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getMeteringAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -500, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 500, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -500, "area[0] left = " + areas[0].left);
ok(areas[0].right == 500, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 100, "area[0] weight = " + areas[0].weight);
cam.setMeteringAreas([
{top: -501, bottom: 502, left: -503, right: 504, weight: 105},
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getMeteringAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -501, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 502, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -503, "area[0] left = " + areas[0].left);
ok(areas[0].right == 504, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 105, "area[0] weight = " + areas[0].weight);
next();
},
},
{
key: "fake-focus-areas",
prep: function setupFakeFocusAreas(test) {
test.setFakeParameters("max-num-focus-areas=1", function () {
run();
});
},
test: function testFakeFocusAreas(cam, cap) {
ok(cap.maxFocusAreas == 1, "maxFocusAreas = " + cap.maxFocusAreas);
cam.setFocusAreas([
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getFocusAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -500, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 500, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -500, "area[0] left = " + areas[0].left);
ok(areas[0].right == 500, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 100, "area[0] weight = " + areas[0].weight);
cam.setFocusAreas([
{top: -501, bottom: 502, left: -503, right: 504, weight: 105},
{top: -500, bottom: 500, left: -500, right: 500, weight: 100}
]);
areas = cam.getFocusAreas();
ok(areas.length == 1, "areas length = " + areas.length);
ok(areas[0].top == -501, "area[0] top = " + areas[0].top);
ok(areas[0].bottom == 502, "area[0] bottom = " + areas[0].bottom);
ok(areas[0].left == -503, "area[0] left = " + areas[0].left);
ok(areas[0].right == 504, "area[0] right = " + areas[0].right);
ok(areas[0].weight == 105, "area[0] weight = " + areas[0].weight);
next();
},
},
];
var testGenerator = function() {

View File

@ -170,18 +170,20 @@ interface CameraControl : MediaStream
weight: 1000
}
'top', 'left', 'bottom', and 'right' all range from -1000 at
the top-/leftmost of the sensor to 1000 at the bottom-/rightmost
of the sensor.
'top', 'left', 'bottom', and 'right' all range from -1000 at
the top-/leftmost of the sensor to 1000 at the bottom-/rightmost
of the sensor.
objects missing one or more of these properties will be ignored;
if the array contains more than capabilities.maxMeteringAreas,
extra areas will be ignored.
objects missing one or more of these properties will be ignored;
if the array contains more than capabilities.maxMeteringAreas,
extra areas will be ignored.
this attribute can be set to null to allow the camera to determine
where to perform light metering. */
if this setter is called with no arguments, the camera will
determine metering areas on its own. */
[Throws]
attribute any meteringAreas;
sequence<CameraRegion> getMeteringAreas();
[Throws]
void setMeteringAreas(optional sequence<CameraRegion> meteringAreas);
/* an array of one or more objects that define where the camera will
perform auto-focusing, with the same definition as meteringAreas.
@ -189,10 +191,12 @@ interface CameraControl : MediaStream
if the array contains more than capabilities.maxFocusAreas, extra
areas will be ignored.
this attribute can be set to null to allow the camera to determine
where to focus. */
if this setter is called with no arguments, the camera will
determine focus areas on its own. */
[Throws]
attribute any focusAreas;
sequence<CameraRegion> getFocusAreas();
[Throws]
void setFocusAreas(optional sequence<CameraRegion> focusAreas);
/* focal length in millimetres */
[Throws]
@ -245,13 +249,21 @@ interface CameraControl : MediaStream
useful for synchronizing other UI elements. */
attribute CameraPreviewStateChange? onPreviewStateChange;
/* the size of the picture to be returned by a call to takePicture();
/* the attribute is deprecated in favour of get/setPictureSize.
the size of the picture to be returned by a call to takePicture();
an object with 'height' and 'width' properties that corresponds to
one of the options returned by capabilities.pictureSizes. */
[Throws]
attribute any pictureSize;
[Throws]
CameraSize getPictureSize();
[Throws]
void setPictureSize(optional CameraSize size);
/* the size of the thumbnail to be included in the picture returned
/* the attribute is deprecated in favour of get/setThumbnailSize.
the size of the thumbnail to be included in the picture returned
by a call to takePicture(), assuming the chosen fileFormat supports
one; an object with 'height' and 'width' properties that corresponds
to one of the options returned by capabilities.pictureSizes.
@ -259,7 +271,11 @@ interface CameraControl : MediaStream
this setting should be considered a hint: the implementation will
respect it when possible, and override it if necessary. */
[Throws]
attribute any thumbnailSize;
attribute any thumbnailSize;
[Throws]
CameraSize getThumbnailSize();
[Throws]
void setThumbnailSize(optional CameraSize size);
/* the angle, in degrees, that the image sensor is mounted relative
to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),