Backout a74bd5095902, Bug 959405 - Please update the Buri Moz-central, 1.3, 1.2 with...
[gecko.git] / dom / camera / DOMCameraCapabilities.cpp
blob4dcab576c0902e723ff005780a085db22a4db19e
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include <cstring>
6 #include <cstdlib>
7 #include "base/basictypes.h"
8 #include "nsDOMClassInfo.h"
9 #include "jsapi.h"
10 #include "CameraRecorderProfiles.h"
11 #include "DOMCameraControl.h"
12 #include "DOMCameraCapabilities.h"
13 #include "CameraCommon.h"
15 using namespace mozilla;
16 using namespace mozilla::dom;
18 DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
20 NS_INTERFACE_MAP_BEGIN(DOMCameraCapabilities)
21 NS_INTERFACE_MAP_ENTRY(nsISupports)
22 NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
23 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
24 NS_INTERFACE_MAP_END
26 NS_IMPL_ADDREF(DOMCameraCapabilities)
27 NS_IMPL_RELEASE(DOMCameraCapabilities)
29 static nsresult
30 ParseZoomRatioItemAndAdd(JSContext* aCx, JS::Handle<JSObject*> aArray,
31 uint32_t aIndex, const char* aStart, char** aEnd)
33 if (!*aEnd) {
34 // make 'aEnd' follow the same semantics as strchr().
35 aEnd = nullptr;
38 /**
39 * The by-100 divisor is Gonk-specific. For now, assume other platforms
40 * return actual fractional multipliers.
42 double d = strtod(aStart, aEnd);
43 #if MOZ_WIDGET_GONK
44 d /= 100;
45 #endif
47 JS::Rooted<JS::Value> v(aCx, JS_NumberValue(d));
49 if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
50 return NS_ERROR_FAILURE;
53 return NS_OK;
56 static nsresult
57 ParseStringItemAndAdd(JSContext* aCx, JS::Handle<JSObject*> aArray,
58 uint32_t aIndex, const char* aStart, char** aEnd)
60 JSString* s;
62 if (*aEnd) {
63 s = JS_NewStringCopyN(aCx, aStart, *aEnd - aStart);
64 } else {
65 s = JS_NewStringCopyZ(aCx, aStart);
67 if (!s) {
68 return NS_ERROR_OUT_OF_MEMORY;
71 JS::Rooted<JS::Value> v(aCx, STRING_TO_JSVAL(s));
72 if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
73 return NS_ERROR_FAILURE;
76 return NS_OK;
79 static nsresult
80 ParseDimensionItemAndAdd(JSContext* aCx, JS::Handle<JSObject*> aArray,
81 uint32_t aIndex, const char* aStart, char** aEnd)
83 char* x;
85 if (!*aEnd) {
86 // make 'aEnd' follow the same semantics as strchr().
87 aEnd = nullptr;
90 JS::Rooted<JS::Value> w(aCx, INT_TO_JSVAL(strtol(aStart, &x, 10)));
91 JS::Rooted<JS::Value> h(aCx, INT_TO_JSVAL(strtol(x + 1, aEnd, 10)));
93 JS::Rooted<JSObject*> o(aCx, JS_NewObject(aCx, nullptr, nullptr, nullptr));
94 if (!o) {
95 return NS_ERROR_OUT_OF_MEMORY;
98 if (!JS_SetProperty(aCx, o, "width", w)) {
99 return NS_ERROR_FAILURE;
101 if (!JS_SetProperty(aCx, o, "height", h)) {
102 return NS_ERROR_FAILURE;
105 JS::Rooted<JS::Value> v(aCx, OBJECT_TO_JSVAL(o));
106 if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
107 return NS_ERROR_FAILURE;
110 return NS_OK;
113 nsresult
114 DOMCameraCapabilities::ParameterListToNewArray(JSContext* aCx,
115 JS::MutableHandle<JSObject*> aArray,
116 uint32_t aKey,
117 ParseItemAndAddFunc aParseItemAndAdd)
119 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
121 const char* value = mCamera->GetParameterConstChar(aKey);
122 if (!value) {
123 // in case we get nonsense data back
124 aArray.set(nullptr);
125 return NS_OK;
128 aArray.set(JS_NewArrayObject(aCx, 0, nullptr));
129 if (!aArray) {
130 return NS_ERROR_OUT_OF_MEMORY;
133 const char* p = value;
134 uint32_t index = 0;
135 nsresult rv;
136 char* q;
138 while (p) {
140 * In C's string.h, strchr() is declared as returning 'char*'; in C++'s
141 * cstring, it is declared as returning 'const char*', _except_ in MSVC,
142 * where the C version is declared to return const like the C++ version.
144 * Unfortunately, for both cases, strtod() and strtol() take a 'char**' as
145 * the end-of-conversion pointer, so we need to cast away strchr()'s
146 * const-ness here to make the MSVC build everything happy.
148 q = const_cast<char*>(strchr(p, ','));
149 if (q != p) { // skip consecutive delimiters, just in case
150 rv = aParseItemAndAdd(aCx, aArray, index, p, &q);
151 NS_ENSURE_SUCCESS(rv, rv);
152 ++index;
154 p = q;
155 if (p) {
156 ++p;
160 return JS_FreezeObject(aCx, aArray) ? NS_OK : NS_ERROR_FAILURE;
163 nsresult
164 DOMCameraCapabilities::StringListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey)
166 JS::Rooted<JSObject*> array(aCx);
168 nsresult rv = ParameterListToNewArray(aCx, &array, aKey, ParseStringItemAndAdd);
169 NS_ENSURE_SUCCESS(rv, rv);
171 *aArray = OBJECT_TO_JSVAL(array);
172 return NS_OK;
175 nsresult
176 DOMCameraCapabilities::DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey)
178 JS::Rooted<JSObject*> array(aCx);
179 nsresult rv;
181 rv = ParameterListToNewArray(aCx, &array, aKey, ParseDimensionItemAndAdd);
182 NS_ENSURE_SUCCESS(rv, rv);
184 *aArray = OBJECT_TO_JSVAL(array);
185 return NS_OK;
188 /* readonly attribute jsval previewSizes; */
189 NS_IMETHODIMP
190 DOMCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
192 return DimensionListToNewObject(cx, aPreviewSizes, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
195 /* readonly attribute jsval pictureSizes; */
196 NS_IMETHODIMP
197 DOMCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
199 return DimensionListToNewObject(cx, aPictureSizes, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
202 /* readonly attribute jsval thumbnailSizes; */
203 NS_IMETHODIMP
204 DOMCameraCapabilities::GetThumbnailSizes(JSContext* cx, JS::Value* aThumbnailSizes)
206 return DimensionListToNewObject(cx, aThumbnailSizes, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES);
209 /* readonly attribute jsval fileFormats; */
210 NS_IMETHODIMP
211 DOMCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
213 return StringListToNewObject(cx, aFileFormats, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
216 /* readonly attribute jsval whiteBalanceModes; */
217 NS_IMETHODIMP
218 DOMCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
220 return StringListToNewObject(cx, aWhiteBalanceModes, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
223 /* readonly attribute jsval sceneModes; */
224 NS_IMETHODIMP
225 DOMCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
227 return StringListToNewObject(cx, aSceneModes, CAMERA_PARAM_SUPPORTED_SCENEMODES);
230 /* readonly attribute jsval effects; */
231 NS_IMETHODIMP
232 DOMCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
234 return StringListToNewObject(cx, aEffects, CAMERA_PARAM_SUPPORTED_EFFECTS);
237 /* readonly attribute jsval flashModes; */
238 NS_IMETHODIMP
239 DOMCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
241 return StringListToNewObject(cx, aFlashModes, CAMERA_PARAM_SUPPORTED_FLASHMODES);
244 /* readonly attribute jsval focusModes; */
245 NS_IMETHODIMP
246 DOMCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
248 return StringListToNewObject(cx, aFocusModes, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
251 /* readonly attribute long maxFocusAreas; */
252 NS_IMETHODIMP
253 DOMCameraCapabilities::GetMaxFocusAreas(JSContext* cx, int32_t* aMaxFocusAreas)
255 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
257 const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
258 if (!value) {
259 // in case we get nonsense data back
260 *aMaxFocusAreas = 0;
261 return NS_OK;
264 *aMaxFocusAreas = atoi(value);
265 return NS_OK;
268 /* readonly attribute double minExposureCompensation; */
269 NS_IMETHODIMP
270 DOMCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
272 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
274 const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
275 if (!value) {
276 // in case we get nonsense data back
277 *aMinExposureCompensation = 0;
278 return NS_OK;
281 *aMinExposureCompensation = atof(value);
282 return NS_OK;
285 /* readonly attribute double maxExposureCompensation; */
286 NS_IMETHODIMP
287 DOMCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
289 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
291 const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
292 if (!value) {
293 // in case we get nonsense data back
294 *aMaxExposureCompensation = 0;
295 return NS_OK;
298 *aMaxExposureCompensation = atof(value);
299 return NS_OK;
302 /* readonly attribute double stepExposureCompensation; */
303 NS_IMETHODIMP
304 DOMCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
306 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
308 const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
309 if (!value) {
310 // in case we get nonsense data back
311 *aStepExposureCompensation = 0;
312 return NS_OK;
315 *aStepExposureCompensation = atof(value);
316 return NS_OK;
319 /* readonly attribute long maxMeteringAreas; */
320 NS_IMETHODIMP
321 DOMCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, int32_t* aMaxMeteringAreas)
323 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
325 const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
326 if (!value) {
327 // in case we get nonsense data back
328 *aMaxMeteringAreas = 0;
329 return NS_OK;
332 *aMaxMeteringAreas = atoi(value);
333 return NS_OK;
336 /* readonly attribute jsval zoomRatios; */
337 NS_IMETHODIMP
338 DOMCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
340 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
342 const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_ZOOM);
343 if (!value || strcmp(value, "true") != 0) {
344 // if zoom is not supported, return a null object
345 *aZoomRatios = JSVAL_NULL;
346 return NS_OK;
349 JS::Rooted<JSObject*> array(cx);
351 nsresult rv = ParameterListToNewArray(cx, &array, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, ParseZoomRatioItemAndAdd);
352 NS_ENSURE_SUCCESS(rv, rv);
354 *aZoomRatios = OBJECT_TO_JSVAL(array);
355 return NS_OK;
358 /* readonly attribute jsval videoSizes; */
359 NS_IMETHODIMP
360 DOMCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
362 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
364 nsTArray<mozilla::idl::CameraSize> sizes;
365 nsresult rv = mCamera->GetVideoSizes(sizes);
366 NS_ENSURE_SUCCESS(rv, rv);
367 if (sizes.Length() == 0) {
368 // video recording not supported, return a null object
369 *aVideoSizes = JSVAL_NULL;
370 return NS_OK;
373 JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, 0, nullptr));
374 if (!array) {
375 return NS_ERROR_OUT_OF_MEMORY;
378 for (uint32_t i = 0; i < sizes.Length(); ++i) {
379 JS::Rooted<JSObject*> o(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
380 JS::Rooted<JS::Value> v(cx, INT_TO_JSVAL(sizes[i].width));
381 if (!JS_SetProperty(cx, o, "width", v)) {
382 return NS_ERROR_FAILURE;
384 v = INT_TO_JSVAL(sizes[i].height);
385 if (!JS_SetProperty(cx, o, "height", v)) {
386 return NS_ERROR_FAILURE;
389 v = OBJECT_TO_JSVAL(o);
390 if (!JS_SetElement(cx, array, i, &v)) {
391 return NS_ERROR_FAILURE;
395 *aVideoSizes = OBJECT_TO_JSVAL(array);
396 return NS_OK;
399 /* readonly attribute jsval recorderProfiles; */
400 NS_IMETHODIMP
401 DOMCameraCapabilities::GetRecorderProfiles(JSContext* cx, JS::Value* aRecorderProfiles)
403 NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
405 nsRefPtr<RecorderProfileManager> profileMgr = mCamera->GetRecorderProfileManager();
406 if (!profileMgr) {
407 *aRecorderProfiles = JSVAL_NULL;
408 return NS_OK;
411 JS::Rooted<JSObject*> o(cx);
412 nsresult rv = profileMgr->GetJsObject(cx, o.address());
413 NS_ENSURE_SUCCESS(rv, rv);
415 *aRecorderProfiles = OBJECT_TO_JSVAL(o);
416 return NS_OK;