Merge backout, a=bustage fix

This commit is contained in:
Nicholas Cameron 2012-07-31 18:17:53 +12:00
commit 18785cc98b
58 changed files with 5219 additions and 196 deletions

View File

@ -165,6 +165,7 @@
#ifdef MOZ_B2G_BT
@BINPATH@/components/dom_bluetooth.xpt
#endif
@BINPATH@/components/dom_camera.xpt
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_contacts.xpt
@BINPATH@/components/dom_alarm.xpt

View File

@ -160,10 +160,10 @@ let SocialShareButton = {
updateProfileInfo: function SSB_updateProfileInfo() {
let profileRow = document.getElementById("editSharePopupHeader");
let profile = Social.provider.profile;
if (profile && profile.displayName) {
if (profile && profile.portrait && profile.displayName) {
profileRow.hidden = false;
let portrait = document.getElementById("socialUserPortrait");
portrait.setAttribute("src", profile.portrait || "chrome://browser/skin/social/social.png");
portrait.style.listStyleImage = profile.portrait;
let displayName = document.getElementById("socialUserDisplayName");
displayName.setAttribute("label", profile.displayName);
} else {

View File

@ -1245,7 +1245,8 @@ var gBrowserInit = {
gDelayedStartupTimeoutId = null;
#ifdef MOZ_SAFE_BROWSING
SafeBrowsing.init();
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
setTimeout(function() { SafeBrowsing.init(); }, 2000);
#endif
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);

View File

@ -174,6 +174,7 @@
#ifdef MOZ_B2G_BT
@BINPATH@/components/dom_bluetooth.xpt
#endif
@BINPATH@/components/dom_camera.xpt
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_contacts.xpt
@BINPATH@/components/dom_alarm.xpt

View File

@ -273,6 +273,7 @@ MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
MOZ_B2G_RIL = @MOZ_B2G_RIL@
MOZ_B2G_BT = @MOZ_B2G_BT@
MOZ_B2G_CAMERA = @MOZ_B2G_CAMERA@
MOZ_SYS_MSG = @MOZ_SYS_MSG@

View File

@ -192,7 +192,7 @@ if test -n "$gonkdir" ; then
;;
esac
CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice"
CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/$ARCH_DIR/include -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/kernel/$ARCH_DIR -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice -I$gonkdir/frameworks/base/services/camera"
CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS $STLPORT_CPPFLAGS"
LIBS="$LIBS $STLPORT_LIBS"
@ -7351,6 +7351,18 @@ if test -n "$MOZ_SYS_MSG"; then
fi
AC_SUBST(MOZ_SYS_MSG)
dnl ========================================================
dnl = Enable Camera Interface for B2G (Gonk usually)
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(b2g-camera,
[ --enable-b2g-camera Set compile flags necessary for compiling camera API for B2G ],
MOZ_B2G_CAMERA=1,
MOZ_B2G_CAMERA= )
if test -n "$MOZ_B2G_CAMERA"; then
AC_DEFINE(MOZ_B2G_CAMERA)
fi
AC_SUBST(MOZ_B2G_CAMERA)
dnl ========================================================
dnl = Support for demangling undefined symbols
dnl ========================================================

View File

@ -185,11 +185,15 @@ nsHTMLAudioElement::MozCurrentSampleOffset(PRUint64 *aRetVal)
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
*aRetVal = mAudioStream->GetPositionInFrames() * mChannels;
PRInt64 position = mAudioStream->GetPositionInFrames();
if (position < 0) {
*aRetVal = 0;
} else {
*aRetVal = mAudioStream->GetPositionInFrames() * mChannels;
}
return NS_OK;
}
nsresult nsHTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
{
nsCAutoString value(

View File

@ -880,13 +880,13 @@ private:
return static_cast<nsBufferedAudioStream*>(aThis)->DataCallback(aBuffer, aFrames);
}
static int StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
{
return static_cast<nsBufferedAudioStream*>(aThis)->StateCallback(aState);
static_cast<nsBufferedAudioStream*>(aThis)->StateCallback(aState);
}
long DataCallback(void* aBuffer, long aFrames);
int StateCallback(cubeb_state aState);
void StateCallback(cubeb_state aState);
// Shared implementation of underflow adjusted position calculation.
// Caller must own the monitor.
@ -1147,12 +1147,19 @@ nsBufferedAudioStream::GetPosition()
return -1;
}
// This function is miscompiled by PGO with MSVC 2010. See bug 768333.
#ifdef _MSC_VER
#pragma optimize("", off)
#endif
PRInt64
nsBufferedAudioStream::GetPositionInFrames()
{
MonitorAutoLock mon(mMonitor);
return GetPositionInFramesUnlocked();
}
#ifdef _MSC_VER
#pragma optimize("", on)
#endif
PRInt64
nsBufferedAudioStream::GetPositionInFramesUnlocked()
@ -1173,11 +1180,11 @@ nsBufferedAudioStream::GetPositionInFramesUnlocked()
// Adjust the reported position by the number of silent frames written
// during stream underruns.
PRInt64 adjustedPosition = 0;
PRUint64 adjustedPosition = 0;
if (position >= mLostFrames) {
adjustedPosition = position - mLostFrames;
}
return adjustedPosition;
return NS_MIN<PRUint64>(adjustedPosition, PR_INT64_MAX);
}
bool
@ -1261,7 +1268,7 @@ nsBufferedAudioStream::DataCallback(void* aBuffer, long aFrames)
return aFrames - (bytesWanted / mBytesPerFrame);
}
int
void
nsBufferedAudioStream::StateCallback(cubeb_state aState)
{
MonitorAutoLock mon(mMonitor);
@ -1271,7 +1278,6 @@ nsBufferedAudioStream::StateCallback(cubeb_state aState)
mState = ERRORED;
}
mon.NotifyAll();
return CUBEB_OK;
}
#endif

View File

@ -70,6 +70,7 @@ DIRS += \
ipc \
identity \
workers \
camera \
$(NULL)
ifdef MOZ_B2G_RIL

View File

@ -50,6 +50,8 @@
#include "nsIDOMBluetoothManager.h"
#include "BluetoothManager.h"
#endif
#include "nsIDOMCameraManager.h"
#include "DOMCameraManager.h"
#include "nsIDOMGlobalPropertyInitializer.h"
@ -112,6 +114,7 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
#ifdef MOZ_B2G_BT
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth)
#endif
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorCamera)
NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorSystemMessages)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
NS_INTERFACE_MAP_END
@ -181,6 +184,8 @@ Navigator::Invalidate()
}
#endif
mCameraManager = nullptr;
#ifdef MOZ_SYS_MSG
if (mMessagesManager) {
mMessagesManager = nullptr;
@ -1320,6 +1325,30 @@ Navigator::MozSetMessageHandler(const nsAString& aType,
#endif
}
//*****************************************************************************
// nsNavigator::nsIDOMNavigatorCamera
//*****************************************************************************
NS_IMETHODIMP
Navigator::GetMozCameras(nsIDOMCameraManager** aCameraManager)
{
if (!mCameraManager) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
if (!win->GetOuterWindow() || win->GetOuterWindow()->GetCurrentInnerWindow() != win) {
return NS_ERROR_NOT_AVAILABLE;
}
mCameraManager = nsDOMCameraManager::Create(win->WindowID());
}
nsRefPtr<nsDOMCameraManager> cameraManager = mCameraManager;
cameraManager.forget(aCameraManager);
return NS_OK;
}
size_t
Navigator::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
@ -1344,12 +1373,19 @@ Navigator::SetWindow(nsPIDOMWindow *aInnerWindow)
void
Navigator::OnNavigation()
{
// Inform MediaManager in case there are live streams or pending callbacks.
#ifdef MOZ_MEDIA_NAVIGATOR
MediaManager *manager = MediaManager::Get();
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
return manager->OnNavigation(win->WindowID());
if (!win) {
return;
}
#ifdef MOZ_MEDIA_NAVIGATOR
// Inform MediaManager in case there are live streams or pending callbacks.
MediaManager *manager = MediaManager::Get();
manager->OnNavigation(win->WindowID());
#endif
if (mCameraManager) {
mCameraManager->OnNavigation(win->WindowID());
}
}
} // namespace dom

View File

@ -41,6 +41,9 @@ class nsIDOMMozVoicemail;
#include "nsIDOMNavigatorSystemMessages.h"
#include "nsIDOMNavigatorCamera.h"
#include "DOMCameraManager.h"
//*****************************************************************************
// Navigator: Script "navigator" object
//*****************************************************************************
@ -82,6 +85,7 @@ class Navigator : public nsIDOMNavigator
#ifdef MOZ_B2G_BT
, public nsIDOMNavigatorBluetooth
#endif
, public nsIDOMNavigatorCamera
, public nsIDOMNavigatorSystemMessages
{
public:
@ -134,6 +138,7 @@ public:
// Helper to initialize mMessagesManager.
nsresult EnsureMessagesManager();
#endif
NS_DECL_NSIDOMNAVIGATORCAMERA
private:
bool IsSmsAllowed() const;
@ -155,6 +160,7 @@ private:
#ifdef MOZ_B2G_BT
nsCOMPtr<nsIDOMBluetoothManager> mBluetooth;
#endif
nsRefPtr<nsDOMCameraManager> mCameraManager;
nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
nsWeakPtr mWindow;
};

View File

@ -522,6 +522,10 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
#include "mozilla/dom/Activity.h"
#include "DOMCameraManager.h"
#include "CameraControl.h"
#include "CameraCapabilities.h"
#include "DOMError.h"
#include "DOMRequest.h"
#include "nsIOpenWindowEventDetail.h"
@ -1668,6 +1672,13 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif
NS_DEFINE_CLASSINFO_DATA(CameraManager, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CameraControl, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -2466,6 +2477,7 @@ nsDOMClassInfo::Init()
#ifdef MOZ_B2G_BT
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth)
#endif
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorCamera)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorSystemMessages)
DOM_CLASSINFO_MAP_END
@ -4457,6 +4469,18 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_END
#endif
DOM_CLASSINFO_MAP_BEGIN(CameraManager, nsIDOMCameraManager)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCameraManager)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CameraControl, nsICameraControl)
DOM_CLASSINFO_MAP_ENTRY(nsICameraControl)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CameraCapabilities, nsICameraCapabilities)
DOM_CLASSINFO_MAP_ENTRY(nsICameraCapabilities)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
DOM_CLASSINFO_MAP_END

View File

@ -526,6 +526,10 @@ DOMCI_CLASS(BluetoothDevice)
DOMCI_CLASS(BluetoothDeviceEvent)
#endif
DOMCI_CLASS(CameraManager)
DOMCI_CLASS(CameraControl)
DOMCI_CLASS(CameraCapabilities)
DOMCI_CLASS(DOMError)
DOMCI_CLASS(DOMRequest)
DOMCI_CLASS(OpenWindowEventDetail)

View File

@ -857,6 +857,7 @@ enum StringificationBehavior {
eNull
};
// pval must not be null and must point to a rooted JS::Value
static inline bool
ConvertJSValueToString(JSContext* cx, const JS::Value& v, JS::Value* pval,
StringificationBehavior nullBehavior,
@ -876,12 +877,7 @@ ConvertJSValueToString(JSContext* cx, const JS::Value& v, JS::Value* pval,
behavior = eStringify;
}
// If pval is null, that means the argument was optional and
// not passed; turn those into void strings if they're
// supposed to be stringified.
if (behavior != eStringify || !pval) {
// Here behavior == eStringify implies !pval, so both eNull and
// eStringify should end up with void strings.
if (behavior != eStringify) {
if (behavior == eEmpty) {
result.Truncate();
} else {

View File

@ -1355,6 +1355,14 @@ builtinNames = {
IDLType.Tags.double: 'double'
}
numericTags = [
IDLType.Tags.int8, IDLType.Tags.uint8,
IDLType.Tags.int16, IDLType.Tags.uint16,
IDLType.Tags.int32, IDLType.Tags.uint32,
IDLType.Tags.int64, IDLType.Tags.uint64,
IDLType.Tags.float, IDLType.Tags.double
]
class CastableObjectUnwrapper():
"""
A class for unwrapping an object named by the "source" argument
@ -1440,7 +1448,8 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
isDefinitelyObject=False,
isMember=False,
isOptional=False,
invalidEnumValueFatal=True):
invalidEnumValueFatal=True,
defaultValue=None):
"""
Get a template for converting a JS value to a native object based on the
given type and descriptor. If failureCode is given, then we're actually
@ -1461,6 +1470,12 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
If isOptional is true, then we are doing conversion of an optional
argument with no default value.
invalidEnumValueFatal controls whether an invalid enum value conversion
attempt will throw (if true) or simply return without doing anything (if
false).
If defaultValue is not None, it's the IDL default value for this conversion
The return value from this function is a tuple consisting of four things:
1) A string representing the conversion code. This will have template
@ -1470,6 +1485,9 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
${valPtr} is a pointer to the JS::Value in question
${holderName} replaced by the holder's name, if any
${declName} replaced by the declaration's name
${haveValue} replaced by an expression that evaluates to a boolean
for whether we have a JS::Value. Only used when
defaultValue is not None.
2) A CGThing representing the native C++ type we're converting to
(declType). This is allowed to be None if the conversion code is
@ -1488,6 +1506,12 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
If holderType is not None then ${holderName} must be in scope
before the generated code is entered.
"""
# If we have a defaultValue then we're not actually optional for
# purposes of what we need to be declared as.
assert(defaultValue is None or not isOptional)
# Also, we should not have a defaultValue if we know we're an object
assert(not isDefinitelyObject or defaultValue is None)
# A helper function for dealing with failures due to the JS value being the
# wrong type of value
@ -1497,6 +1521,29 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
"return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);"
% toStringBool(isWorker)), post="\n")
# A helper function for handling default values. Takes a template
# body and the C++ code to set the default value and wraps the
# given template body in handling for the default value.
def handleDefault(template, setDefault):
if defaultValue is None:
return template
return CGWrapper(
CGIndenter(CGGeneric(template)),
pre="if (${haveValue}) {\n",
post=("\n"
"} else {\n"
"%s;\n"
"}" %
CGIndenter(CGGeneric(setDefault)).define())).define()
# A helper function for handling null default values. Much like
# handleDefault, but checks that the default value, if it exists, is null.
def handleDefaultNull(template, codeToSetNull):
if (defaultValue is not None and
not isinstance(defaultValue, IDLNullValue)):
raise TypeError("Can't handle non-null default value here")
return handleDefault(template, codeToSetNull)
# A helper function for wrapping up the template body for
# possibly-nullable objecty stuff
def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
@ -1515,6 +1562,11 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
"} else {\n" +
CGIndenter(onFailure(failureCode, isWorker)).define() +
"}")
if type.nullable():
templateBody = handleDefaultNull(templateBody, codeToSetNull)
else:
assert(defaultValue is None)
return templateBody
if type.isArray():
@ -1602,11 +1654,13 @@ for (uint32_t i = 0; i < length; ++i) {
if isMember:
raise TypeError("Can't handle unions as members, we have a "
"holderType")
nullable = type.nullable();
if nullable:
type = type.inner
assert(defaultValue is None or
(isinstance(defaultValue, IDLNullValue) and nullable))
unionArgumentObj = "${holderName}"
if isOptional or nullable:
unionArgumentObj += ".ref()"
@ -1759,10 +1813,10 @@ for (uint32_t i = 0; i < length; ++i) {
nonConstDecl = "const_cast<" + typeName + "& >(${declName})"
typeName = "const " + typeName
def handleNull(templateBody, setToNullVar):
null = CGGeneric("if (${val}.isNullOrUndefined()) {\n"
def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
null = CGGeneric("if (%s${val}.isNullOrUndefined()) {\n"
" %s.SetNull();\n"
"}" % setToNullVar)
"}" % (extraConditionForNull, setToNullVar))
templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}")
return CGList([null, templateBody], " else ")
@ -1792,7 +1846,13 @@ for (uint32_t i = 0; i < length; ++i) {
templateBody = CGList([constructHolder, templateBody], "\n")
if nullable:
templateBody = handleNull(templateBody, mutableDecl)
if defaultValue:
assert(isinstance(defaultValue, IDLNullValue))
valueMissing = "!(${haveValue}) || "
else:
valueMissing = ""
templateBody = handleNull(templateBody, mutableDecl,
extraConditionForNull=valueMissing)
templateBody = CGList([constructDecl, templateBody], "\n")
return templateBody.define(), declType, holderType, False
@ -1980,6 +2040,25 @@ for (uint32_t i = 0; i < length; ++i) {
nullBehavior = "eStringify"
undefinedBehavior = "eStringify"
def getConversionCode(varName):
conversionCode = (
"if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
" return false;\n"
"}" % (nullBehavior, undefinedBehavior, varName))
if defaultValue is None:
return conversionCode
if isinstance(defaultValue, IDLNullValue):
assert(type.nullable())
return handleDefault(conversionCode,
"%s.SetNull()" % varName)
return handleDefault(
conversionCode,
("static const PRUnichar data[] = { %s, 0 };\n"
"%s.SetData(data, ArrayLength(data) - 1)" %
(", ".join("'" + char + "'" for char in defaultValue.value),
varName)))
if isMember:
# We have to make a copy, because our jsval may well not
# live as long as our string needs to.
@ -1987,25 +2066,20 @@ for (uint32_t i = 0; i < length; ++i) {
return (
"{\n"
" FakeDependentString str;\n"
" if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, str)) {\n"
" return false;\n"
" }\n"
"%s\n"
" ${declName} = str;\n"
"}\n" %
(nullBehavior, undefinedBehavior),
declType, None,
isOptional)
"}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(),
declType, None, isOptional)
if isOptional:
declType = "Optional<nsAString>"
else:
declType = "NonNull<nsAString>"
return (
"if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, ${holderName})) {\n"
" return false;\n"
"}\n"
"%s\n"
"const_cast<%s&>(${declName}) = &${holderName};" %
(nullBehavior, undefinedBehavior, declType),
(getConversionCode("${holderName}"), declType),
CGGeneric("const " + declType), CGGeneric("FakeDependentString"),
# No need to deal with Optional here; we have handled it already
False)
@ -2023,7 +2097,7 @@ for (uint32_t i = 0; i < length; ++i) {
" return true;\n"
" }\n")
return (
template = (
"{\n"
" bool ok;\n"
" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
@ -2035,8 +2109,15 @@ for (uint32_t i = 0; i < length; ++i) {
"}" % { "enumtype" : enum,
"values" : enum + "Values::strings",
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
"handleInvalidEnumValueCode" : handleInvalidEnumValueCode },
CGGeneric(enum), None, isOptional)
"handleInvalidEnumValueCode" : handleInvalidEnumValueCode })
if defaultValue is not None:
assert(defaultValue.type.tag() == IDLType.Tags.domstring)
template = handleDefault(template,
("${declName} = %sValues::%s" %
(enum,
getEnumValueName(defaultValue.value))))
return (template, CGGeneric(enum), None, isOptional)
if type.isCallback():
if isMember:
@ -2044,18 +2125,26 @@ for (uint32_t i = 0; i < length; ++i) {
"rooting issues")
# XXXbz we're going to assume that callback types are always
# nullable and always have [TreatNonCallableAsNull] for now.
haveCallable = "${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())"
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
haveCallable = "${haveValue} && " + haveCallable
return (
"if (${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())) {\n"
"if (%s) {\n"
" ${declName} = &${val}.toObject();\n"
"} else {\n"
" ${declName} = NULL;\n"
"}", CGGeneric("JSObject*"), None, isOptional)
"}" % haveCallable,
CGGeneric("JSObject*"), None, isOptional)
if type.isAny():
if isMember:
raise TypeError("Can't handle member 'any'; need to sort out "
"rooting issues")
return ("${declName} = ${val};", CGGeneric("JS::Value"), None, isOptional)
templateBody = "${declName} = ${val};"
templateBody = handleDefaultNull(templateBody,
"${declName} = JS::NullValue()")
return (templateBody, CGGeneric("JS::Value"), None, isOptional)
if type.isObject():
if isMember:
@ -2093,9 +2182,17 @@ for (uint32_t i = 0; i < length; ++i) {
declType = CGWrapper(declType, pre="const ")
selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef)
template = ("if (!%s.Init(cx, ${val})) {\n"
# We do manual default value handling here, because we
# actually do want a jsval, and we only handle null anyway
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
val = "(${haveValue}) ? ${val} : JSVAL_NULL"
else:
val = "${val}"
template = ("if (!%s.Init(cx, %s)) {\n"
" return false;\n"
"}" % selfRef)
"}" % (selfRef, val))
return (template, declType, None, False)
@ -2105,15 +2202,43 @@ for (uint32_t i = 0; i < length; ++i) {
# XXXbz need to add support for [EnforceRange] and [Clamp]
typeName = builtinNames[type.tag()]
if type.nullable():
return ("if (${val}.isNullOrUndefined()) {\n"
" ${declName}.SetNull();\n"
"} else if (!ValueToPrimitive<" + typeName + ">(cx, ${val}, &${declName}.SetValue())) {\n"
" return false;\n"
"}", CGGeneric("Nullable<" + typeName + ">"), None, isOptional)
dataLoc = "${declName}.SetValue()"
nullCondition = "${val}.isNullOrUndefined()"
if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
nullCondition = "!(${haveValue}) || " + nullCondition
template = (
"if (%s) {\n"
" ${declName}.SetNull();\n"
"} else if (!ValueToPrimitive<%s>(cx, ${val}, &%s)) {\n"
" return false;\n"
"}" % (nullCondition, typeName, dataLoc))
declType = CGGeneric("Nullable<" + typeName + ">")
else:
return ("if (!ValueToPrimitive<" + typeName + ">(cx, ${val}, &${declName})) {\n"
" return false;\n"
"}", CGGeneric(typeName), None, isOptional)
assert(defaultValue is None or
not isinstance(defaultValue, IDLNullValue))
dataLoc = "${declName}"
template = (
"if (!ValueToPrimitive<%s>(cx, ${val}, &%s)) {\n"
" return false;\n"
"}" % (typeName, dataLoc))
declType = CGGeneric(typeName)
if (defaultValue is not None and
# We already handled IDLNullValue, so just deal with the other ones
not isinstance(defaultValue, IDLNullValue)):
tag = defaultValue.type.tag()
if tag in numericTags:
defaultStr = defaultValue.value
else:
assert(tag == IDLType.Tags.bool)
defaultStr = toStringBool(defaultValue.value)
template = CGWrapper(CGIndenter(CGGeneric(template)),
pre="if (${haveValue}) {\n",
post=("\n"
"} else {\n"
" %s = %s;\n"
"}" % (dataLoc, defaultStr))).define()
return (template, declType, None, isOptional)
def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
argcAndIndex=None):
@ -2216,14 +2341,6 @@ def convertConstIDLValueToJSVal(value):
return "DOUBLE_TO_JSVAL(%s)" % (value.value)
raise TypeError("Const value of unhandled type: " + value.type)
def convertIDLDefaultValueToJSVal(value):
if value.type:
tag = value.type.tag()
if (tag == IDLType.Tags.domstring and
(not value.type.nullable() or not isinstance(value, IDLNullValue))):
assert False # Not implemented!
return convertConstIDLValueToJSVal(value)
class CGArgumentConverter(CGThing):
"""
A class that takes an IDL argument object, its index in the
@ -2237,8 +2354,8 @@ class CGArgumentConverter(CGThing):
if argument.variadic:
raise TypeError("We don't support variadic arguments yet " +
str(argument.location))
# XXXbz should optional jsval args get JSVAL_VOID? What about
# others?
assert(not argument.defaultValue or argument.optional)
replacer = {
"index" : index,
"argc" : argc,
@ -2248,20 +2365,14 @@ class CGArgumentConverter(CGThing):
"declName" : "arg%d" % index,
"holderName" : ("arg%d" % index) + "_holder"
}
if argument.optional and argument.defaultValue:
replacer["defaultValue"] = convertIDLDefaultValueToJSVal(argument.defaultValue)
self.replacementVariables["val"] = string.Template(
"(${index} < ${argc} ? ${argv}[${index}] : ${defaultValue})"
).substitute(replacer)
self.replacementVariables["valPtr"] = string.Template(
"(${index} < ${argc} ? &${argv}[${index}] : NULL)"
).substitute(replacer)
else:
self.replacementVariables["val"] = string.Template(
"${argv}[${index}]"
).substitute(replacer)
self.replacementVariables["valPtr"] = (
"&" + self.replacementVariables["val"])
self.replacementVariables["val"] = string.Template(
"${argv}[${index}]"
).substitute(replacer)
self.replacementVariables["valPtr"] = (
"&" + self.replacementVariables["val"])
if argument.defaultValue:
self.replacementVariables["haveValue"] = string.Template(
"${index} < ${argc}").substitute(replacer)
self.descriptorProvider = descriptorProvider
if self.argument.optional and not self.argument.defaultValue:
self.argcAndIndex = replacer
@ -2274,7 +2385,8 @@ class CGArgumentConverter(CGThing):
getJSToNativeConversionTemplate(self.argument.type,
self.descriptorProvider,
isOptional=(self.argcAndIndex is not None),
invalidEnumValueFatal=self.invalidEnumValueFatal),
invalidEnumValueFatal=self.invalidEnumValueFatal,
defaultValue=self.argument.defaultValue),
self.replacementVariables,
self.argcAndIndex).define()
@ -3051,6 +3163,7 @@ class FakeArgument():
self.type = type
self.optional = False
self.variadic = False
self.defaultValue = None
class CGSetterCall(CGGetterSetterCall):
"""
@ -4067,7 +4180,8 @@ class CGDictionary(CGThing):
getJSToNativeConversionTemplate(member.type,
descriptorProvider,
isMember=True,
isOptional=(not member.defaultValue)))
isOptional=(not member.defaultValue),
defaultValue=member.defaultValue))
for member in dictionary.members ]
except NoSuchDescriptorError, err:
if not self.workers:
@ -4204,6 +4318,8 @@ class CGDictionary(CGThing):
assert holderType is None
if dealWithOptional:
replacements["declName"] = "(" + replacements["declName"] + ".Value())"
if member.defaultValue:
replacements["haveValue"] = "found"
conversionReplacements = {
"propId" : self.makeIdName(member.identifier.name),
@ -4221,12 +4337,8 @@ class CGDictionary(CGThing):
" if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
" return false;\n"
" }\n"
"} else {\n"
" temp = ${defaultVal};\n"
"}\n"
"${convert}")
conversionReplacements["defaultVal"] = (
convertIDLDefaultValueToJSVal(member.defaultValue))
else:
conversion += (
"if (found) {\n"

View File

@ -1725,11 +1725,7 @@ class IDLValue(IDLObject):
return IDLValue(self.location, type, innerValue.value)
# Else, see if we can coerce to 'type'.
if self.type.isInteger():
if not type.isInteger():
raise WebIDLError("Cannot coerce type %s to type %s." %
(self.type, type), [location])
if self.type.isInteger() and type.isInteger():
# We're both integer types. See if we fit.
(min, max) = integerTypeSizes[type._typeTag]
@ -1739,10 +1735,16 @@ class IDLValue(IDLObject):
else:
raise WebIDLError("Value %s is out of range for type %s." %
(self.value, type), [location])
elif self.type.isString() and type.isEnum():
# Just keep our string, but make sure it's a valid value for this enum
if self.value not in type.inner.values():
raise WebIDLError("'%s' is not a valid default value for enum %s"
% (self.value, type.inner.identifier.name),
[location, type.inner.location])
return self
else:
pass
assert False # Not implemented!
raise WebIDLError("Cannot coerce type %s to type %s." %
(self.type, type), [location])
class IDLNullValue(IDLObject):
def __init__(self, location):
@ -1753,7 +1755,8 @@ class IDLNullValue(IDLObject):
def coerceToType(self, type, location):
if (not isinstance(type, IDLNullableType) and
not (type.isUnion() and type.hasNullableType) and
not type.isDictionary()):
not type.isDictionary() and
not type.isAny()):
raise WebIDLError("Cannot coerce null value to type %s." % type,
[location])
@ -2766,8 +2769,9 @@ class Parser(Tokenizer):
"""
ConstValue : STRING
"""
assert False
pass
location = self.getLocation(p, 1)
stringType = BuiltinTypes[IDLBuiltinType.Types.domstring]
p[0] = IDLValue(location, stringType, p[1])
def p_ConstValueNull(self, p):
"""

View File

@ -59,3 +59,23 @@ def WebIDLTest(parser, harness):
harness.check(attr.identifier.name, "foo", "Attr has correct name")
harness.check(str(attr.type), "TestEnum (Wrapper)", "Attr type is the correct name")
# Now reset our parser
parser = parser.reset()
threw = False
try:
parser.parse("""
enum Enum {
"a",
"b",
"c"
};
interface TestInterface {
void foo(optional Enum e = "d");
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow a bogus default value for an enum")

View File

@ -335,12 +335,14 @@ public:
void PassString(const nsAString&, ErrorResult&);
void PassNullableString(const nsAString&, ErrorResult&);
void PassOptionalString(const Optional<nsAString>&, ErrorResult&);
void PassOptionalStringWithDefaultValue(const nsAString&, ErrorResult&);
void PassOptionalNullableString(const Optional<nsAString>&, ErrorResult&);
void PassOptionalNullableStringWithDefaultValue(const nsAString&, ErrorResult&);
// Enumarated types
void PassEnum(TestEnum, ErrorResult&);
void PassOptionalEnum(const Optional<TestEnum>&, ErrorResult&);
void PassEnumWithDefault(TestEnum, ErrorResult&);
TestEnum ReceiveEnum(ErrorResult&);
TestEnum GetEnumAttribute(ErrorResult&);
TestEnum GetReadonlyEnumAttribute(ErrorResult&);
@ -361,6 +363,7 @@ public:
// Any types
void PassAny(JSContext*, JS::Value, ErrorResult&);
void PassOptionalAny(JSContext*, const Optional<JS::Value>&, ErrorResult&);
void PassAnyDefaultNull(JSContext*, JS::Value, ErrorResult&);
JS::Value ReceiveAny(JSContext*, ErrorResult&);
// object types
@ -549,6 +552,7 @@ private:
void PassString(nsAString&, ErrorResult&) MOZ_DELETE;
void PassNullableString(nsAString&, ErrorResult&) MOZ_DELETE;
void PassOptionalString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
void PassOptionalStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
void PassOptionalNullableString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
void PassOptionalNullableStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;

View File

@ -51,49 +51,49 @@ interface TestInterface {
void passShort(short arg);
short receiveShort();
void passOptionalShort(optional short arg);
void passOptionalShortWithDefault(optional short arg = 0);
void passOptionalShortWithDefault(optional short arg = 5);
readonly attribute long readonlyLong;
attribute long writableLong;
void passLong(long arg);
long receiveLong();
void passOptionalLong(optional long arg);
void passOptionalLongWithDefault(optional long arg = 0);
void passOptionalLongWithDefault(optional long arg = 7);
readonly attribute long long readonlyLongLong;
attribute long long writableLongLong;
void passLongLong(long long arg);
long long receiveLongLong();
void passOptionalLongLong(optional long long arg);
void passOptionalLongLongWithDefault(optional long long arg = 0);
void passOptionalLongLongWithDefault(optional long long arg = -12);
readonly attribute octet readonlyOctet;
attribute octet writableOctet;
void passOctet(octet arg);
octet receiveOctet();
void passOptionalOctet(optional octet arg);
void passOptionalOctetWithDefault(optional octet arg = 0);
void passOptionalOctetWithDefault(optional octet arg = 19);
readonly attribute unsigned short readonlyUnsignedShort;
attribute unsigned short writableUnsignedShort;
void passUnsignedShort(unsigned short arg);
unsigned short receiveUnsignedShort();
void passOptionalUnsignedShort(optional unsigned short arg);
void passOptionalUnsignedShortWithDefault(optional unsigned short arg = 0);
void passOptionalUnsignedShortWithDefault(optional unsigned short arg = 2);
readonly attribute unsigned long readonlyUnsignedLong;
attribute unsigned long writableUnsignedLong;
void passUnsignedLong(unsigned long arg);
unsigned long receiveUnsignedLong();
void passOptionalUnsignedLong(optional unsigned long arg);
void passOptionalUnsignedLongWithDefault(optional unsigned long arg = 0);
void passOptionalUnsignedLongWithDefault(optional unsigned long arg = 6);
readonly attribute unsigned long long readonlyUnsignedLongLong;
attribute unsigned long long writableUnsignedLongLong;
void passUnsignedLongLong(unsigned long long arg);
unsigned long long receiveUnsignedLongLong();
void passOptionalUnsignedLongLong(optional unsigned long long arg);
void passOptionalUnsignedLongLongWithDefault(optional unsigned long long arg = 0);
void passOptionalUnsignedLongLongWithDefault(optional unsigned long long arg = 17);
// Castable interface types
// XXXbz add tests for infallible versions of all the castable interface stuff
@ -233,6 +233,7 @@ interface TestInterface {
void passString(DOMString arg);
void passNullableString(DOMString? arg);
void passOptionalString(optional DOMString arg);
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
void passOptionalNullableString(optional DOMString? arg);
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
@ -241,6 +242,7 @@ interface TestInterface {
// No support for nullable enums yet
// void passNullableEnum(TestEnum? arg);
void passOptionalEnum(optional TestEnum arg);
void passEnumWithDefault(optional TestEnum arg = "a");
// void passOptionalNullableEnum(optional TestEnum? arg);
// void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
TestEnum receiveEnum();
@ -259,6 +261,7 @@ interface TestInterface {
// Any types
void passAny(any arg);
void passOptionalAny(optional any arg);
void passAnyDefaultNull(optional any arg = null);
any receiveAny();
// object types
@ -354,6 +357,9 @@ dictionary Dict : ParentDict {
long b = 8;
long z = 9;
DOMString str;
TestEnum otherEnum = "b";
DOMString otherStr = "def";
DOMString? yetAnotherStr = null;
};
dictionary ParentDict : GrandparentDict {

View File

@ -0,0 +1,44 @@
/* 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/. */
#ifndef DOM_CAMERA_NSCAMERACAPABILITIES_H
#define DOM_CAMERA_NSCAMERACAPABILITIES_H
#include "CameraControl.h"
#include "nsAutoPtr.h"
namespace mozilla {
typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd);
class nsCameraCapabilities : public nsICameraCapabilities
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICAMERACAPABILITIES
nsCameraCapabilities(nsCameraControl* aCamera);
nsresult ParameterListToNewArray(
JSContext* cx,
JSObject** aArray,
PRUint32 aKey,
ParseItemAndAddFunc aParseItemAndAdd
);
nsresult StringListToNewObject(JSContext* aCx, JS::Value* aArray, PRUint32 aKey);
nsresult DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, PRUint32 aKey);
private:
nsCameraCapabilities(const nsCameraCapabilities&) MOZ_DELETE;
nsCameraCapabilities& operator=(const nsCameraCapabilities&) MOZ_DELETE;
protected:
/* additional members */
~nsCameraCapabilities();
nsCOMPtr<nsCameraControl> mCamera;
};
} // namespace mozilla
#endif // DOM_CAMERA_NSCAMERACAPABILITIES_H

68
dom/camera/CameraCommon.h Normal file
View File

@ -0,0 +1,68 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* 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/. */
#ifndef DOM_CAMERA_CAMERACOMMON_H
#define DOM_CAMERA_CAMERACOMMON_H
#ifndef __func__
#ifdef __FUNCTION__
#define __func__ __FUNCTION__
#else
#define __func__ __FILE__
#endif
#endif
#ifndef NAN
#define NAN std::numeric_limits<double>::quiet_NaN()
#endif
#include "nsThreadUtils.h"
#include "nsIDOMCameraManager.h"
#define DOM_CAMERA_LOG( l, ... ) \
do { \
if ( DOM_CAMERA_LOG_LEVEL >= (l) ) { \
printf_stderr (__VA_ARGS__); \
} \
} while (0)
#define DOM_CAMERA_LOGA( ... ) DOM_CAMERA_LOG( 0, __VA_ARGS__ )
enum {
DOM_CAMERA_LOG_NOTHING,
DOM_CAMERA_LOG_ERROR,
DOM_CAMERA_LOG_WARNING,
DOM_CAMERA_LOG_INFO
};
#define DOM_CAMERA_LOGI( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_INFO, __VA_ARGS__ )
#define DOM_CAMERA_LOGW( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_WARNING, __VA_ARGS__ )
#define DOM_CAMERA_LOGE( ... ) DOM_CAMERA_LOG( DOM_CAMERA_LOG_ERROR, __VA_ARGS__ )
class CameraErrorResult : public nsRunnable
{
public:
CameraErrorResult(nsICameraErrorCallback* onError, const nsString& aErrorMsg)
: mOnErrorCb(onError)
, mErrorMsg(aErrorMsg)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnErrorCb) {
mOnErrorCb->HandleEvent(mErrorMsg);
}
return NS_OK;
}
protected:
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
const nsString mErrorMsg;
};
#endif // DOM_CAMERA_CAMERACOMMON_H

View File

@ -0,0 +1,486 @@
/* 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 "nsCOMPtr.h"
#include "nsDOMClassInfo.h"
#include "jsapi.h"
#include "nsThread.h"
#include "DOMCameraManager.h"
#include "CameraControl.h"
#include "CameraCapabilities.h"
#include "CameraControl.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
using namespace dom;
DOMCI_DATA(CameraControl, nsICameraControl)
NS_INTERFACE_MAP_BEGIN(nsCameraControl)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsICameraControl)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraControl)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsCameraControl)
NS_IMPL_RELEASE(nsCameraControl)
// Helpers for string properties.
nsresult
nsCameraControl::SetHelper(PRUint32 aKey, const nsAString& aValue)
{
SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
return NS_OK;
}
nsresult
nsCameraControl::GetHelper(PRUint32 aKey, nsAString& aValue)
{
const char* value = GetParameterConstChar(aKey);
if (!value) {
return NS_ERROR_FAILURE;
}
aValue.AssignASCII(value);
return NS_OK;
}
// Helpers for doubles.
nsresult
nsCameraControl::SetHelper(PRUint32 aKey, double aValue)
{
SetParameter(aKey, aValue);
return NS_OK;
}
nsresult
nsCameraControl::GetHelper(PRUint32 aKey, double* aValue)
{
MOZ_ASSERT(aValue);
*aValue = GetParameterDouble(aKey);
return NS_OK;
}
// Helper for weighted regions.
nsresult
nsCameraControl::SetHelper(JSContext* aCx, PRUint32 aKey, const JS::Value& aValue, PRUint32 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;
JSObject* regions = &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<CameraRegion> regionArray;
regionArray.SetCapacity(length);
for (PRUint32 i = 0; i < length; ++i) {
JS::Value v;
if (!JS_GetElement(aCx, regions, i, &v)) {
return NS_ERROR_FAILURE;
}
CameraRegion* r = regionArray.AppendElement();
/**
* These are the default values. We can remove these when the xpidl
* dictionary parser gains the ability to grok default values.
*/
r->top = -1000;
r->left = -1000;
r->bottom = 1000;
r->right = 1000;
r->weight = 1000;
nsresult rv = r->Init(aCx, &v);
NS_ENSURE_SUCCESS(rv, rv);
DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%d\n",
i,
r->top,
r->left,
r->bottom,
r->right,
r->weight
);
}
SetParameter(aKey, regionArray);
return NS_OK;
}
nsresult
nsCameraControl::GetHelper(JSContext* aCx, PRUint32 aKey, JS::Value* aValue)
{
nsTArray<CameraRegion> regionArray;
GetParameter(aKey, regionArray);
JSObject* array = JS_NewArrayObject(aCx, 0, nullptr);
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
PRUint32 length = regionArray.Length();
DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
for (PRUint32 i = 0; i < length; ++i) {
CameraRegion* r = &regionArray[i];
JS::Value v;
JSObject* o = JS_NewObject(aCx, nullptr, nullptr, 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;
}
v = OBJECT_TO_JSVAL(o);
if (!JS_SetElement(aCx, array, i, &v)) {
return NS_ERROR_FAILURE;
}
}
*aValue = JS::ObjectValue(*array);
return NS_OK;
}
/* readonly attribute nsICameraCapabilities capabilities; */
NS_IMETHODIMP
nsCameraControl::GetCapabilities(nsICameraCapabilities** aCapabilities)
{
if (!mCapabilities) {
mCapabilities = new nsCameraCapabilities(this);
}
nsCOMPtr<nsICameraCapabilities> capabilities = mCapabilities;
capabilities.forget(aCapabilities);
return NS_OK;
}
/* attribute DOMString effect; */
NS_IMETHODIMP
nsCameraControl::GetEffect(nsAString& aEffect)
{
return GetHelper(CAMERA_PARAM_EFFECT, aEffect);
}
NS_IMETHODIMP
nsCameraControl::SetEffect(const nsAString& aEffect)
{
return SetHelper(CAMERA_PARAM_EFFECT, aEffect);
}
/* attribute DOMString whiteBalanceMode; */
NS_IMETHODIMP
nsCameraControl::GetWhiteBalanceMode(nsAString& aWhiteBalanceMode)
{
return GetHelper(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
}
NS_IMETHODIMP
nsCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode)
{
return SetHelper(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
}
/* attribute DOMString sceneMode; */
NS_IMETHODIMP
nsCameraControl::GetSceneMode(nsAString& aSceneMode)
{
return GetHelper(CAMERA_PARAM_SCENEMODE, aSceneMode);
}
NS_IMETHODIMP
nsCameraControl::SetSceneMode(const nsAString& aSceneMode)
{
return SetHelper(CAMERA_PARAM_SCENEMODE, aSceneMode);
}
/* attribute DOMString flashMode; */
NS_IMETHODIMP
nsCameraControl::GetFlashMode(nsAString& aFlashMode)
{
return GetHelper(CAMERA_PARAM_FLASHMODE, aFlashMode);
}
NS_IMETHODIMP
nsCameraControl::SetFlashMode(const nsAString& aFlashMode)
{
return SetHelper(CAMERA_PARAM_FLASHMODE, aFlashMode);
}
/* attribute DOMString focusMode; */
NS_IMETHODIMP
nsCameraControl::GetFocusMode(nsAString& aFocusMode)
{
return GetHelper(CAMERA_PARAM_FOCUSMODE, aFocusMode);
}
NS_IMETHODIMP
nsCameraControl::SetFocusMode(const nsAString& aFocusMode)
{
return SetHelper(CAMERA_PARAM_FOCUSMODE, aFocusMode);
}
/* attribute double zoom; */
NS_IMETHODIMP
nsCameraControl::GetZoom(double* aZoom)
{
return GetHelper(CAMERA_PARAM_ZOOM, aZoom);
}
NS_IMETHODIMP
nsCameraControl::SetZoom(double aZoom)
{
return SetHelper(CAMERA_PARAM_ZOOM, aZoom);
}
/* attribute jsval meteringAreas; */
NS_IMETHODIMP
nsCameraControl::GetMeteringAreas(JSContext* cx, JS::Value* aMeteringAreas)
{
return GetHelper(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas);
}
NS_IMETHODIMP
nsCameraControl::SetMeteringAreas(JSContext* cx, const JS::Value& aMeteringAreas)
{
return SetHelper(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas, mMaxMeteringAreas);
}
/* attribute jsval focusAreas; */
NS_IMETHODIMP
nsCameraControl::GetFocusAreas(JSContext* cx, JS::Value* aFocusAreas)
{
return GetHelper(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas);
}
NS_IMETHODIMP
nsCameraControl::SetFocusAreas(JSContext* cx, const JS::Value& aFocusAreas)
{
return SetHelper(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas, mMaxFocusAreas);
}
/* readonly attribute double focalLength; */
NS_IMETHODIMP
nsCameraControl::GetFocalLength(double* aFocalLength)
{
return GetHelper(CAMERA_PARAM_FOCALLENGTH, aFocalLength);
}
/* readonly attribute double focusDistanceNear; */
NS_IMETHODIMP
nsCameraControl::GetFocusDistanceNear(double* aFocusDistanceNear)
{
return GetHelper(CAMERA_PARAM_FOCUSDISTANCENEAR, aFocusDistanceNear);
}
/* readonly attribute double focusDistanceOptimum; */
NS_IMETHODIMP
nsCameraControl::GetFocusDistanceOptimum(double* aFocusDistanceOptimum)
{
return GetHelper(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, aFocusDistanceOptimum);
}
/* readonly attribute double focusDistanceFar; */
NS_IMETHODIMP
nsCameraControl::GetFocusDistanceFar(double* aFocusDistanceFar)
{
return GetHelper(CAMERA_PARAM_FOCUSDISTANCEFAR, aFocusDistanceFar);
}
/* void setExposureCompensation (const JS::Value& aCompensation, JSContext* cx); */
NS_IMETHODIMP
nsCameraControl::SetExposureCompensation(const JS::Value& aCompensation, JSContext* cx)
{
if (aCompensation.isNullOrUndefined()) {
// use NaN to switch the camera back into auto mode
return SetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
}
double compensation;
if (!JS_ValueToNumber(cx, aCompensation, &compensation)) {
return NS_ERROR_INVALID_ARG;
}
return SetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
}
/* readonly attribute double exposureCompensation; */
NS_IMETHODIMP
nsCameraControl::GetExposureCompensation(double* aExposureCompensation)
{
return GetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, aExposureCompensation);
}
/* attribute nsICameraShutterCallback onShutter; */
NS_IMETHODIMP
nsCameraControl::GetOnShutter(nsICameraShutterCallback** aOnShutter)
{
*aOnShutter = mOnShutterCb;
return NS_OK;
}
NS_IMETHODIMP
nsCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
{
mOnShutterCb = aOnShutter;
return NS_OK;
}
/* void startRecording (in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
CameraSize size;
nsresult rv = size.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, size, onSuccess, onError);
mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
return NS_OK;
}
/* void stopRecording (); */
NS_IMETHODIMP
nsCameraControl::StopRecording()
{
nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
return NS_OK;
}
/* [implicit_jscontext] void getPreviewStream (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsCameraControl::GetPreviewStream(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
CameraSize size;
nsresult rv = size.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, size, onSuccess, onError);
mCameraThread->Dispatch(getPreviewStreamTask, NS_DISPATCH_NORMAL);
return NS_OK;
}
/* void autoFocus (in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
nsCOMPtr<nsIRunnable> autoFocusTask = new AutoFocusTask(this, onSuccess, onError);
mCameraThread->Dispatch(autoFocusTask, NS_DISPATCH_NORMAL);
return NS_OK;
}
/* void takePicture (in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP nsCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
CameraPictureOptions options;
CameraSize size;
CameraPosition pos;
nsresult rv = options.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
rv = size.Init(cx, &options.pictureSize);
NS_ENSURE_SUCCESS(rv, rv);
/**
* Default values, until the dictionary parser can handle them.
* NaN indicates no value provided.
*/
pos.latitude = NAN;
pos.longitude = NAN;
pos.altitude = NAN;
pos.timestamp = NAN;
rv = pos.Init(cx, &options.position);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, size, options.rotation, options.fileFormat, pos, onSuccess, onError);
mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
return NS_OK;
}
void
nsCameraControl::AutoFocusComplete(bool aSuccess)
{
/**
* Auto focusing can change some of the camera's parameters, so
* we need to pull a new set before sending the result to the
* main thread.
*/
PullParametersImpl(nullptr);
nsCOMPtr<nsIRunnable> autoFocusResult = new AutoFocusResult(aSuccess, mAutoFocusOnSuccessCb);
nsresult rv = NS_DispatchToMainThread(autoFocusResult);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch autoFocus() onSuccess callback to main thread!");
}
}
void
nsCameraControl::TakePictureComplete(PRUint8* aData, PRUint32 aLength)
{
PRUint8* data = new PRUint8[aLength];
memcpy(data, aData, aLength);
/**
* TODO: pick up the actual specified picture format for the MIME type;
* for now, assume we'll be using JPEGs.
*/
nsIDOMBlob* blob = new nsDOMMemoryFile(static_cast<void*>(data), static_cast<PRUint64>(aLength), NS_LITERAL_STRING("image/jpeg"));
nsCOMPtr<nsIRunnable> takePictureResult = new TakePictureResult(blob, mTakePictureOnSuccessCb);
nsresult rv = NS_DispatchToMainThread(takePictureResult);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch takePicture() onSuccess callback to main thread!");
}
}

438
dom/camera/CameraControl.h Normal file
View File

@ -0,0 +1,438 @@
/* 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/. */
#ifndef DOM_CAMERA_NSCAMERACONTROL_H
#define DOM_CAMERA_NSCAMERACONTROL_H
#include "prtypes.h"
#include "nsCOMPtr.h"
#include "nsThread.h"
#include "nsDOMFile.h"
#include "DictionaryHelpers.h"
#include "CameraPreview.h"
#include "nsIDOMCameraManager.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
namespace mozilla {
using namespace dom;
class GetPreviewStreamTask;
class AutoFocusTask;
class TakePictureTask;
class StartRecordingTask;
class StopRecordingTask;
class SetParameterTask;
class GetParameterTask;
class PushParametersTask;
class PullParametersTask;
// Main camera control.
class nsCameraControl : public nsICameraControl
{
friend class GetPreviewStreamTask;
friend class AutoFocusTask;
friend class TakePictureTask;
friend class StartRecordingTask;
friend class StopRecordingTask;
friend class SetParameterTask;
friend class GetParameterTask;
friend class PushParametersTask;
friend class PullParametersTask;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICAMERACONTROL
enum {
CAMERA_PARAM_EFFECT,
CAMERA_PARAM_WHITEBALANCE,
CAMERA_PARAM_SCENEMODE,
CAMERA_PARAM_FLASHMODE,
CAMERA_PARAM_FOCUSMODE,
CAMERA_PARAM_ZOOM,
CAMERA_PARAM_METERINGAREAS,
CAMERA_PARAM_FOCUSAREAS,
CAMERA_PARAM_FOCALLENGTH,
CAMERA_PARAM_FOCUSDISTANCENEAR,
CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
CAMERA_PARAM_FOCUSDISTANCEFAR,
CAMERA_PARAM_EXPOSURECOMPENSATION,
CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
CAMERA_PARAM_SUPPORTED_PICTURESIZES,
CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
CAMERA_PARAM_SUPPORTED_SCENEMODES,
CAMERA_PARAM_SUPPORTED_EFFECTS,
CAMERA_PARAM_SUPPORTED_FLASHMODES,
CAMERA_PARAM_SUPPORTED_FOCUSMODES,
CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
CAMERA_PARAM_SUPPORTED_ZOOM,
CAMERA_PARAM_SUPPORTED_ZOOMRATIOS
};
virtual const char* GetParameter(const char* aKey) = 0;
virtual const char* GetParameterConstChar(PRUint32 aKey) = 0;
virtual double GetParameterDouble(PRUint32 aKey) = 0;
virtual void GetParameter(PRUint32 aKey, nsTArray<CameraRegion>& aRegions) = 0;
virtual void SetParameter(const char* aKey, const char* aValue) = 0;
virtual void SetParameter(PRUint32 aKey, const char* aValue) = 0;
virtual void SetParameter(PRUint32 aKey, double aValue) = 0;
virtual void SetParameter(PRUint32 aKey, const nsTArray<CameraRegion>& aRegions) = 0;
virtual void PushParameters() = 0;
nsCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread)
: mCameraId(aCameraId)
, mCameraThread(aCameraThread)
, mCapabilities(nullptr)
, mPreview(nullptr)
, mFileFormat()
, mMaxMeteringAreas(0)
, mMaxFocusAreas(0)
, mAutoFocusOnSuccessCb(nullptr)
, mAutoFocusOnErrorCb(nullptr)
, mTakePictureOnSuccessCb(nullptr)
, mTakePictureOnErrorCb(nullptr)
, mStartRecordingOnSuccessCb(nullptr)
, mStartRecordingOnErrorCb(nullptr)
, mOnShutterCb(nullptr)
{ }
void TakePictureComplete(PRUint8 *aData, PRUint32 aLength);
void AutoFocusComplete(bool aSuccess);
protected:
virtual ~nsCameraControl() { }
nsresult SetHelper(PRUint32 aKey, const nsAString& aValue);
nsresult GetHelper(PRUint32 aKey, nsAString& aValue);
nsresult SetHelper(PRUint32 aKey, double aValue);
nsresult GetHelper(PRUint32 aKey, double* aValue);
nsresult SetHelper(JSContext* aCx, PRUint32 aKey, const JS::Value& aValue, PRUint32 aLimit);
nsresult GetHelper(JSContext* aCx, PRUint32 aKey, JS::Value* aValue);
virtual nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream) = 0;
virtual nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus) = 0;
virtual nsresult TakePictureImpl(TakePictureTask* aTakePicture) = 0;
virtual nsresult StartRecordingImpl(StartRecordingTask* aStartRecording) = 0;
virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
virtual nsresult PushParametersImpl(PushParametersTask* aPushParameters) = 0;
virtual nsresult PullParametersImpl(PullParametersTask* aPullParameters) = 0;
private:
nsCameraControl(const nsCameraControl&) MOZ_DELETE;
nsCameraControl& operator=(const nsCameraControl&) MOZ_DELETE;
protected:
/* additional members */
PRUint32 mCameraId;
nsCOMPtr<nsIThread> mCameraThread;
nsCOMPtr<nsICameraCapabilities> mCapabilities;
PRUint32 mPreviewWidth;
PRUint32 mPreviewHeight;
nsCOMPtr<CameraPreview> mPreview;
nsString mFileFormat;
PRUint32 mMaxMeteringAreas;
PRUint32 mMaxFocusAreas;
nsCOMPtr<nsICameraAutoFocusCallback> mAutoFocusOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mAutoFocusOnErrorCb;
nsCOMPtr<nsICameraTakePictureCallback> mTakePictureOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mTakePictureOnErrorCb;
nsCOMPtr<nsICameraStartRecordingCallback> mStartRecordingOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mStartRecordingOnErrorCb;
nsCOMPtr<nsICameraShutterCallback> mOnShutterCb;
};
// Return the resulting preview stream to JS. Runs on the main thread.
class GetPreviewStreamResult : public nsRunnable
{
public:
GetPreviewStreamResult(nsIDOMMediaStream* aStream, nsICameraPreviewStreamCallback* onSuccess)
: mStream(aStream)
, mOnSuccessCb(onSuccess)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb) {
mOnSuccessCb->HandleEvent(mStream);
}
return NS_OK;
}
protected:
nsCOMPtr<nsIDOMMediaStream> mStream;
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
};
// Get the desired preview stream.
class GetPreviewStreamTask : public nsRunnable
{
public:
GetPreviewStreamTask(nsCameraControl* aCameraControl, CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
: mSize(aSize)
, mCameraControl(aCameraControl)
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{ }
NS_IMETHOD Run()
{
nsresult rv = mCameraControl->GetPreviewStreamImpl(this);
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
CameraSize mSize;
nsCOMPtr<nsCameraControl> mCameraControl;
nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the autofocus status to JS. Runs on the main thread.
class AutoFocusResult : public nsRunnable
{
public:
AutoFocusResult(bool aSuccess, nsICameraAutoFocusCallback* onSuccess)
: mSuccess(aSuccess)
, mOnSuccessCb(onSuccess)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb) {
mOnSuccessCb->HandleEvent(mSuccess);
}
return NS_OK;
}
protected:
bool mSuccess;
nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
};
// Autofocus the camera.
class AutoFocusTask : public nsRunnable
{
public:
AutoFocusTask(nsCameraControl* aCameraControl, nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
: mCameraControl(aCameraControl)
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{ }
NS_IMETHOD Run()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsresult rv = mCameraControl->AutoFocusImpl(this);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
nsCOMPtr<nsCameraControl> mCameraControl;
nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the captured picture to JS. Runs on the main thread.
class TakePictureResult : public nsRunnable
{
public:
TakePictureResult(nsIDOMBlob* aImage, nsICameraTakePictureCallback* onSuccess)
: mImage(aImage)
, mOnSuccessCb(onSuccess)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb) {
mOnSuccessCb->HandleEvent(mImage);
}
return NS_OK;
}
protected:
nsCOMPtr<nsIDOMBlob> mImage;
nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
};
// Capture a still image with the camera.
class TakePictureTask : public nsRunnable
{
public:
TakePictureTask(nsCameraControl* aCameraControl, CameraSize aSize, PRInt32 aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
: mCameraControl(aCameraControl)
, mSize(aSize)
, mRotation(aRotation)
, mFileFormat(aFileFormat)
, mPosition(aPosition)
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{ }
NS_IMETHOD Run()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsresult rv = mCameraControl->TakePictureImpl(this);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
nsCOMPtr<nsCameraControl> mCameraControl;
CameraSize mSize;
PRInt32 mRotation;
nsString mFileFormat;
CameraPosition mPosition;
nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Return the captured video to JS. Runs on the main thread.
class StartRecordingResult : public nsRunnable
{
public:
StartRecordingResult(nsIDOMMediaStream* aStream, nsICameraStartRecordingCallback* onSuccess)
: mStream(aStream)
, mOnSuccessCb(onSuccess)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
if (mOnSuccessCb) {
mOnSuccessCb->HandleEvent(mStream);
}
return NS_OK;
}
protected:
nsCOMPtr<nsIDOMMediaStream> mStream;
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
};
// Start video recording.
class StartRecordingTask : public nsRunnable
{
public:
StartRecordingTask(nsCameraControl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
: mSize(aSize)
, mCameraControl(aCameraControl)
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
{ }
NS_IMETHOD Run()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsresult rv = mCameraControl->StartRecordingImpl(this);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
if (NS_FAILED(rv) && mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
CameraSize mSize;
nsCOMPtr<nsCameraControl> mCameraControl;
nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
};
// Stop video recording.
class StopRecordingTask : public nsRunnable
{
public:
StopRecordingTask(nsCameraControl* aCameraControl)
: mCameraControl(aCameraControl)
{ }
NS_IMETHOD Run()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsresult rv = mCameraControl->StopRecordingImpl(this);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsCOMPtr<nsCameraControl> mCameraControl;
};
// Pushes all camera parameters to the camera.
class PushParametersTask : public nsRunnable
{
public:
PushParametersTask(nsCameraControl* aCameraControl)
: mCameraControl(aCameraControl)
{ }
NS_IMETHOD Run()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsresult rv = mCameraControl->PushParametersImpl(this);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsCOMPtr<nsCameraControl> mCameraControl;
};
// Get all camera parameters from the camera.
class PullParametersTask : public nsRunnable
{
public:
PullParametersTask(nsCameraControl* aCameraControl)
: mCameraControl(aCameraControl)
{ }
NS_IMETHOD Run()
{
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsresult rv = mCameraControl->PullParametersImpl(this);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsCOMPtr<nsCameraControl> mCameraControl;
};
} // namespace mozilla
#endif // DOM_CAMERA_NSCAMERACONTROL_H

View File

@ -0,0 +1,98 @@
/* 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 "CameraPreview.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
NS_IMPL_ISUPPORTS1(CameraPreview, CameraPreview)
class CameraPreviewListener : public MediaStreamListener
{
public:
CameraPreviewListener(CameraPreview* aPreview) :
mPreview(aPreview)
{
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
}
~CameraPreviewListener()
{
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
}
void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
{
const char* state;
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
switch (aConsuming) {
case NOT_CONSUMED:
state = "not consuming";
break;
case CONSUMED:
state = "consuming";
break;
default:
state = "unknown";
break;
}
DOM_CAMERA_LOGA("camera viewfinder is %s\n", state);
switch (aConsuming) {
case NOT_CONSUMED:
mPreview->Stop();
break;
case CONSUMED:
mPreview->Start();
break;
}
}
protected:
nsCOMPtr<CameraPreview> mPreview;
};
CameraPreview::CameraPreview(PRUint32 aWidth, PRUint32 aHeight)
: nsDOMMediaStream()
, mWidth(aWidth)
, mHeight(aHeight)
, mFramesPerSecond(0)
, mFrameCount(0)
{
DOM_CAMERA_LOGI("%s:%d : mWidth=%d, mHeight=%d : this=%p\n", __func__, __LINE__, mWidth, mHeight, this);
mImageContainer = LayerManager::CreateImageContainer();
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
mStream = gm->CreateInputStream(this);
mInput = GetStream()->AsSourceStream();
mInput->AddListener(new CameraPreviewListener(this));
}
void
CameraPreview::SetFrameRate(PRUint32 aFramesPerSecond)
{
mFramesPerSecond = aFramesPerSecond;
mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment());
mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX);
}
CameraPreview::~CameraPreview()
{
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
/**
* We _must_ remember to call RemoveListener on this before destroying this,
* else the media framework will trigger a double-free.
*/
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
}

View File

@ -0,0 +1,58 @@
/* 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/. */
#ifndef DOM_CAMERA_CAMERAPREVIEW_H
#define DOM_CAMERA_CAMERAPREVIEW_H
#include "MediaStreamGraph.h"
#include "StreamBuffer.h"
#include "nsDOMMediaStream.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
using namespace mozilla::layers;
namespace mozilla {
class CameraPreview : public nsDOMMediaStream
, public MediaStreamListener
{
public:
NS_DECL_ISUPPORTS
CameraPreview(PRUint32 aWidth, PRUint32 aHeight);
void SetFrameRate(PRUint32 aFramesPerSecond);
NS_IMETHODIMP
GetCurrentTime(double* aCurrentTime) {
return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
}
virtual void Start() = 0;
virtual void Stop() = 0;
protected:
virtual ~CameraPreview();
PRUint32 mWidth;
PRUint32 mHeight;
PRUint32 mFramesPerSecond;
SourceMediaStream* mInput;
nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
VideoSegment mVideoSegment;
PRUint32 mFrameCount;
enum { TRACK_VIDEO = 1 };
private:
CameraPreview(const CameraPreview&) MOZ_DELETE;
CameraPreview& operator=(const CameraPreview&) MOZ_DELETE;
};
} // namespace mozilla
#endif // DOM_CAMERA_CAMERAPREVIEW_H

View File

@ -0,0 +1,89 @@
/* 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 "CameraControl.h"
#include "DOMCameraManager.h"
#include "nsDOMClassInfo.h"
#include "DictionaryHelpers.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
DOMCI_DATA(CameraManager, nsIDOMCameraManager)
NS_INTERFACE_MAP_BEGIN(nsDOMCameraManager)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMCameraManager)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraManager)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMCameraManager)
NS_IMPL_RELEASE(nsDOMCameraManager)
/**
* nsDOMCameraManager::GetListOfCameras
* is implementation-specific, and can be found in (e.g.)
* GonkCameraManager.cpp and FallbackCameraManager.cpp.
*/
nsDOMCameraManager::nsDOMCameraManager(PRUint64 aWindowId)
: mWindowId(aWindowId)
{
/* member initializers and constructor code */
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
}
nsDOMCameraManager::~nsDOMCameraManager()
{
/* destructor code */
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
}
void
nsDOMCameraManager::OnNavigation(PRUint64 aWindowId)
{
// TODO: implement -- see getUserMedia() implementation
}
// static creator
already_AddRefed<nsDOMCameraManager>
nsDOMCameraManager::Create(PRUint64 aWindowId)
{
// TODO: check for permissions here to access cameras
nsRefPtr<nsDOMCameraManager> cameraManager = new nsDOMCameraManager(aWindowId);
return cameraManager.forget();
}
/* [implicit_jscontext] void getCamera ([optional] in jsval aOptions, in nsICameraGetCameraCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsDOMCameraManager::GetCamera(const JS::Value& aOptions, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
PRUint32 cameraId = 0; // back (or forward-facing) camera by default
CameraSelector selector;
nsresult rv = selector.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
if (selector.camera.EqualsASCII("front")) {
cameraId = 1;
}
// reuse the same camera thread to conserve resources
if (!mCameraThread) {
rv = NS_NewThread(getter_AddRefs(mCameraThread));
NS_ENSURE_SUCCESS(rv, rv);
}
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
nsCOMPtr<nsIRunnable> getCameraTask = new GetCameraTask(cameraId, onSuccess, onError, mCameraThread);
mCameraThread->Dispatch(getCameraTask, NS_DISPATCH_NORMAL);
return NS_OK;
}

View File

@ -0,0 +1,82 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* 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/. */
#ifndef DOM_CAMERA_DOMCAMERAMANAGER_H
#define DOM_CAMERA_DOMCAMERAMANAGER_H
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsIDOMCameraManager.h"
class nsDOMCameraManager : public nsIDOMCameraManager
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMCAMERAMANAGER
static already_AddRefed<nsDOMCameraManager> Create(PRUint64 aWindowId);
void OnNavigation(PRUint64 aWindowId);
private:
nsDOMCameraManager();
nsDOMCameraManager(PRUint64 aWindowId);
nsDOMCameraManager(const nsDOMCameraManager&) MOZ_DELETE;
nsDOMCameraManager& operator=(const nsDOMCameraManager&) MOZ_DELETE;
~nsDOMCameraManager();
protected:
PRUint64 mWindowId;
nsCOMPtr<nsIThread> mCameraThread;
};
class GetCameraTask : public nsRunnable
{
public:
GetCameraTask(PRUint32 aCameraId, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsIThread* aCameraThread)
: mCameraId(aCameraId)
, mOnSuccessCb(onSuccess)
, mOnErrorCb(onError)
, mCameraThread(aCameraThread)
{ }
NS_IMETHOD Run();
protected:
PRUint32 mCameraId;
nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
nsCOMPtr<nsIThread> mCameraThread;
};
class GetCameraResult : public nsRunnable
{
public:
GetCameraResult(nsICameraControl* aCameraControl, nsICameraGetCameraCallback* onSuccess)
: mCameraControl(aCameraControl)
, mOnSuccessCb(onSuccess)
{ }
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: window management stuff
if (mOnSuccessCb) {
mOnSuccessCb->HandleEvent(mCameraControl);
}
return NS_OK;
}
protected:
nsCOMPtr<nsICameraControl> mCameraControl;
nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
};
#endif // DOM_CAMERA_DOMCAMERAMANAGER_H

View File

@ -0,0 +1,140 @@
/* 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 "nsDOMClassInfoID.h"
#include "CameraControl.h"
#include "CameraCapabilities.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
NS_INTERFACE_MAP_BEGIN(nsCameraCapabilities)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsCameraCapabilities)
NS_IMPL_RELEASE(nsCameraCapabilities)
nsCameraCapabilities::nsCameraCapabilities(nsCameraControl* aCamera)
: mCamera(aCamera)
{
/* member initializers and constructor code */
DOM_CAMERA_LOGI("%s:%d : FALLBACK CAMERA CAPABILITIES\n", __func__, __LINE__);
}
nsCameraCapabilities::~nsCameraCapabilities()
{
/* destructor code */
}
/* [implicit_jscontext] readonly attribute jsval previewSizes; */
NS_IMETHODIMP
nsCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval pictureSizes; */
NS_IMETHODIMP
nsCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval fileFormats; */
NS_IMETHODIMP
nsCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval whiteBalanceModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval sceneModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval effects; */
NS_IMETHODIMP
nsCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval flashModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval focusModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute long maxFocusAreas; */
NS_IMETHODIMP
nsCameraCapabilities::GetMaxFocusAreas(JSContext* cx, PRInt32* aMaxFocusAreas)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute double minExposureCompensation; */
NS_IMETHODIMP
nsCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute double maxExposureCompensation; */
NS_IMETHODIMP
nsCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute double stepExposureCompensation; */
NS_IMETHODIMP
nsCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute long maxMeteringAreas; */
NS_IMETHODIMP
nsCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, PRInt32* aMaxMeteringAreas)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval zoomRatios; */
NS_IMETHODIMP
nsCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [implicit_jscontext] readonly attribute jsval videoSizes; */
NS_IMETHODIMP
nsCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -0,0 +1,147 @@
/* 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 "nsDOMClassInfoID.h"
#include "DOMCameraManager.h"
#include "CameraControl.h"
using namespace mozilla;
/**
* Fallback camera control subclass. Can be used as a template for the
* definition of new camera support classes.
*/
class nsFallbackCameraControl : public nsCameraControl
{
public:
nsFallbackCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread);
const char* GetParameter(const char* aKey);
const char* GetParameterConstChar(PRUint32 aKey);
double GetParameterDouble(PRUint32 aKey);
void GetParameter(PRUint32 aKey, nsTArray<dom::CameraRegion>& aRegions);
void SetParameter(const char* aKey, const char* aValue);
void SetParameter(PRUint32 aKey, const char* aValue);
void SetParameter(PRUint32 aKey, double aValue);
void SetParameter(PRUint32 aKey, const nsTArray<dom::CameraRegion>& aRegions);
void PushParameters();
protected:
~nsFallbackCameraControl();
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
nsresult PushParametersImpl(PushParametersTask* aPushParameters);
nsresult PullParametersImpl(PullParametersTask* aPullParameters);
private:
nsFallbackCameraControl(const nsFallbackCameraControl&) MOZ_DELETE;
nsFallbackCameraControl& operator=(const nsFallbackCameraControl&) MOZ_DELETE;
};
/**
* Stub implemetations of the fallback camera control.
*
* None of these should ever get called--they exist to keep the linker happy,
* and may be used as templates for new camera support classes.
*/
nsFallbackCameraControl::nsFallbackCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread)
: nsCameraControl(aCameraId, aCameraThread)
{ }
nsFallbackCameraControl::~nsFallbackCameraControl()
{ }
const char*
nsFallbackCameraControl::GetParameter(const char* aKey)
{
return nullptr;
}
const char*
nsFallbackCameraControl::GetParameterConstChar(PRUint32 aKey)
{
return nullptr;
}
double
nsFallbackCameraControl::GetParameterDouble(PRUint32 aKey)
{
return NAN;
}
void
nsFallbackCameraControl::GetParameter(PRUint32 aKey, nsTArray<dom::CameraRegion>& aRegions)
{
}
void
nsFallbackCameraControl::SetParameter(const char* aKey, const char* aValue)
{
}
void
nsFallbackCameraControl::SetParameter(PRUint32 aKey, const char* aValue)
{
}
void
nsFallbackCameraControl::SetParameter(PRUint32 aKey, double aValue)
{
}
void
nsFallbackCameraControl::SetParameter(PRUint32 aKey, const nsTArray<dom::CameraRegion>& aRegions)
{
}
void
nsFallbackCameraControl::PushParameters()
{
}
nsresult
nsFallbackCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFallbackCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFallbackCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFallbackCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFallbackCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFallbackCameraControl::PushParametersImpl(PushParametersTask* aPushParameters)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFallbackCameraControl::PullParametersImpl(PullParametersTask* aPullParameters)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -0,0 +1,22 @@
/* 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 "DOMCameraManager.h"
// From nsDOMCameraManager.
/* [implicit_jscontext] jsval getListOfCameras (); */
NS_IMETHODIMP
nsDOMCameraManager::GetListOfCameras(JSContext* cx, JS::Value* _retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
using namespace mozilla;
NS_IMETHODIMP
GetCameraTask::Run()
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -0,0 +1,352 @@
/* 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 <string.h>
#include <stdlib.h>
#include "nsDOMClassInfo.h"
#include "jsapi.h"
#include "camera/CameraParameters.h"
#include "CameraControl.h"
#include "CameraCapabilities.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace android;
using namespace mozilla;
DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
NS_INTERFACE_MAP_BEGIN(nsCameraCapabilities)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsCameraCapabilities)
NS_IMPL_RELEASE(nsCameraCapabilities)
nsCameraCapabilities::nsCameraCapabilities(nsCameraControl* aCamera)
: mCamera(aCamera)
{
// member initializers and constructor code
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
}
nsCameraCapabilities::~nsCameraCapabilities()
{
// destructor code
DOM_CAMERA_LOGI("%s:%d : this=%p, mCamera=%p\n", __func__, __LINE__, this, mCamera.get());
}
static nsresult
ParseZoomRatioItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
{
if (!*aEnd) {
// make 'aEnd' follow the same semantics as strchr().
aEnd = nullptr;
}
double d = strtod(aStart, aEnd);
jsval v;
d /= 100;
if (!JS_NewNumberValue(aCx, d, &v)) {
return NS_ERROR_FAILURE;
}
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
static nsresult
ParseStringItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
{
JSString* s;
if (*aEnd) {
s = JS_NewStringCopyN(aCx, aStart, *aEnd - aStart);
} else {
s = JS_NewStringCopyZ(aCx, aStart);
}
if (!s) {
return NS_ERROR_OUT_OF_MEMORY;
}
jsval v = STRING_TO_JSVAL(s);
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
static nsresult
ParseDimensionItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
{
char* x;
if (!*aEnd) {
// make 'aEnd' follow the same semantics as strchr().
aEnd = nullptr;
}
jsval w = INT_TO_JSVAL(strtol(aStart, &x, 10));
jsval h = INT_TO_JSVAL(strtol(x + 1, aEnd, 10));
JSObject* o = JS_NewObject(aCx, nullptr, nullptr, nullptr);
if (!o) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!JS_SetProperty(aCx, o, "width", &w)) {
return NS_ERROR_FAILURE;
}
if (!JS_SetProperty(aCx, o, "height", &h)) {
return NS_ERROR_FAILURE;
}
jsval v = OBJECT_TO_JSVAL(o);
if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsCameraCapabilities::ParameterListToNewArray(JSContext* aCx, JSObject** aArray, PRUint32 aKey, ParseItemAndAddFunc aParseItemAndAdd)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(aKey);
if (!value) {
// in case we get nonsense data back
*aArray = nullptr;
return NS_OK;
}
*aArray = JS_NewArrayObject(aCx, 0, nullptr);
if (!*aArray) {
return NS_ERROR_OUT_OF_MEMORY;
}
const char* p = value;
PRUint32 index = 0;
nsresult rv;
char* q;
while (p) {
q = strchr(p, ',');
if (q != p) { // skip consecutive delimiters, just in case
rv = aParseItemAndAdd(aCx, *aArray, index, p, &q);
NS_ENSURE_SUCCESS(rv, rv);
++index;
}
p = q;
if (p) {
++p;
}
}
return JS_FreezeObject(aCx, *aArray) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
nsCameraCapabilities::StringListToNewObject(JSContext* aCx, JS::Value* aArray, PRUint32 aKey)
{
JSObject* array;
nsresult rv = ParameterListToNewArray(aCx, &array, aKey, ParseStringItemAndAdd);
NS_ENSURE_SUCCESS(rv, rv);
*aArray = OBJECT_TO_JSVAL(array);
return NS_OK;
}
nsresult
nsCameraCapabilities::DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, PRUint32 aKey)
{
JSObject* array;
nsresult rv;
rv = ParameterListToNewArray(aCx, &array, aKey, ParseDimensionItemAndAdd);
NS_ENSURE_SUCCESS(rv, rv);
*aArray = OBJECT_TO_JSVAL(array);
return NS_OK;
}
/* readonly attribute jsval previewSizes; */
NS_IMETHODIMP
nsCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
{
return DimensionListToNewObject(cx, aPreviewSizes, nsCameraControl::CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
}
/* readonly attribute jsval pictureSizes; */
NS_IMETHODIMP
nsCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
{
return DimensionListToNewObject(cx, aPictureSizes, nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTURESIZES);
}
/* readonly attribute jsval fileFormats; */
NS_IMETHODIMP
nsCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
{
return StringListToNewObject(cx, aFileFormats, nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
}
/* readonly attribute jsval whiteBalanceModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
{
return StringListToNewObject(cx, aWhiteBalanceModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
}
/* readonly attribute jsval sceneModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
{
return StringListToNewObject(cx, aSceneModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_SCENEMODES);
}
/* readonly attribute jsval effects; */
NS_IMETHODIMP
nsCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
{
return StringListToNewObject(cx, aEffects, nsCameraControl::CAMERA_PARAM_SUPPORTED_EFFECTS);
}
/* readonly attribute jsval flashModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
{
return StringListToNewObject(cx, aFlashModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_FLASHMODES);
}
/* readonly attribute jsval focusModes; */
NS_IMETHODIMP
nsCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
{
return StringListToNewObject(cx, aFocusModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_FOCUSMODES);
}
/* readonly attribute long maxFocusAreas; */
NS_IMETHODIMP
nsCameraCapabilities::GetMaxFocusAreas(JSContext* cx, PRInt32* aMaxFocusAreas)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
if (!value) {
// in case we get nonsense data back
*aMaxFocusAreas = 0;
return NS_OK;
}
*aMaxFocusAreas = atoi(value);
return NS_OK;
}
/* readonly attribute double minExposureCompensation; */
NS_IMETHODIMP
nsCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
if (!value) {
// in case we get nonsense data back
*aMinExposureCompensation = 0;
return NS_OK;
}
*aMinExposureCompensation = atof(value);
return NS_OK;
}
/* readonly attribute double maxExposureCompensation; */
NS_IMETHODIMP
nsCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
if (!value) {
// in case we get nonsense data back
*aMaxExposureCompensation = 0;
return NS_OK;
}
*aMaxExposureCompensation = atof(value);
return NS_OK;
}
/* readonly attribute double stepExposureCompensation; */
NS_IMETHODIMP
nsCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
if (!value) {
// in case we get nonsense data back
*aStepExposureCompensation = 0;
return NS_OK;
}
*aStepExposureCompensation = atof(value);
return NS_OK;
}
/* readonly attribute long maxMeteringAreas; */
NS_IMETHODIMP
nsCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, PRInt32* aMaxMeteringAreas)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
if (!value) {
// in case we get nonsense data back
*aMaxMeteringAreas = 0;
return NS_OK;
}
*aMaxMeteringAreas = atoi(value);
return NS_OK;
}
/* readonly attribute jsval zoomRatios; */
NS_IMETHODIMP
nsCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
{
NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOM);
if (!value || strcmp(value, CameraParameters::TRUE) != 0) {
// if zoom is not supported, return a null object
*aZoomRatios = JSVAL_NULL;
return NS_OK;
}
JSObject* array;
nsresult rv = ParameterListToNewArray(cx, &array, nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, ParseZoomRatioItemAndAdd);
NS_ENSURE_SUCCESS(rv, rv);
*aZoomRatios = OBJECT_TO_JSVAL(array);
return NS_OK;
}
/* readonly attribute jsval videoSizes; */
NS_IMETHODIMP
nsCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
{
return DimensionListToNewObject(cx, aVideoSizes, nsCameraControl::CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
}

View File

@ -0,0 +1,602 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "libcameraservice/CameraHardwareInterface.h"
#include "camera/CameraParameters.h"
#include "nsCOMPtr.h"
#include "nsDOMClassInfo.h"
#include "nsMemory.h"
#include "jsapi.h"
#include "nsThread.h"
#include "nsPrintfCString.h"
#include "DOMCameraManager.h"
#include "GonkCameraHwMgr.h"
#include "CameraCapabilities.h"
#include "GonkCameraControl.h"
#include "GonkCameraPreview.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
static const char* getKeyText(PRUint32 aKey)
{
switch (aKey) {
case nsCameraControl::CAMERA_PARAM_EFFECT:
return CameraParameters::KEY_EFFECT;
case nsCameraControl::CAMERA_PARAM_WHITEBALANCE:
return CameraParameters::KEY_WHITE_BALANCE;
case nsCameraControl::CAMERA_PARAM_SCENEMODE:
return CameraParameters::KEY_SCENE_MODE;
case nsCameraControl::CAMERA_PARAM_FLASHMODE:
return CameraParameters::KEY_FLASH_MODE;
case nsCameraControl::CAMERA_PARAM_FOCUSMODE:
return CameraParameters::KEY_FOCUS_MODE;
case nsCameraControl::CAMERA_PARAM_ZOOM:
return CameraParameters::KEY_ZOOM;
case nsCameraControl::CAMERA_PARAM_METERINGAREAS:
return CameraParameters::KEY_METERING_AREAS;
case nsCameraControl::CAMERA_PARAM_FOCUSAREAS:
return CameraParameters::KEY_FOCUS_AREAS;
case nsCameraControl::CAMERA_PARAM_FOCALLENGTH:
return CameraParameters::KEY_FOCAL_LENGTH;
case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCENEAR:
return CameraParameters::KEY_FOCUS_DISTANCES;
case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
return CameraParameters::KEY_FOCUS_DISTANCES;
case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCEFAR:
return CameraParameters::KEY_FOCUS_DISTANCES;
case nsCameraControl::CAMERA_PARAM_EXPOSURECOMPENSATION:
return CameraParameters::KEY_EXPOSURE_COMPENSATION;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
return CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
return CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTURESIZES:
return CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
return CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
return CameraParameters::KEY_SUPPORTED_WHITE_BALANCE;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_SCENEMODES:
return CameraParameters::KEY_SUPPORTED_SCENE_MODES;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_EFFECTS:
return CameraParameters::KEY_SUPPORTED_EFFECTS;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_FLASHMODES:
return CameraParameters::KEY_SUPPORTED_FLASH_MODES;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_FOCUSMODES:
return CameraParameters::KEY_SUPPORTED_FOCUS_MODES;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
return CameraParameters::KEY_MAX_NUM_FOCUS_AREAS;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
return CameraParameters::KEY_MAX_NUM_METERING_AREAS;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
return CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
return CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
return CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOM:
return CameraParameters::KEY_ZOOM_SUPPORTED;
case nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
return CameraParameters::KEY_ZOOM_RATIOS;
default:
return nullptr;
}
}
// Gonk-specific CameraControl implementation.
nsGonkCameraControl::nsGonkCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread)
: nsCameraControl(aCameraId, aCameraThread)
, mHwHandle(0)
, mExposureCompensationMin(0.0)
, mExposureCompensationStep(0.0)
, mDeferConfigUpdate(false)
{
// Constructor runs on the camera thread--see DOMCameraManager.cpp::GetCameraImpl().
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
mHwHandle = GonkCameraHardware::GetHandle(this, mCameraId);
DOM_CAMERA_LOGI("%s:%d : this = %p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
// Initialize our camera configuration database.
mRwLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraControl.Parameters.Lock");
PullParametersImpl(nullptr);
// Grab any settings we'll need later.
mExposureCompensationMin = mParams.getFloat(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
mExposureCompensationStep = mParams.getFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
mMaxMeteringAreas = mParams.getInt(CameraParameters::KEY_MAX_NUM_METERING_AREAS);
mMaxFocusAreas = mParams.getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS);
DOM_CAMERA_LOGI("minimum exposure compensation = %f\n", mExposureCompensationMin);
DOM_CAMERA_LOGI("exposure compensation step = %f\n", mExposureCompensationStep);
DOM_CAMERA_LOGI("maximum metering areas = %d\n", mMaxMeteringAreas);
DOM_CAMERA_LOGI("maximum focus areas = %d\n", mMaxFocusAreas);
}
nsGonkCameraControl::~nsGonkCameraControl()
{
DOM_CAMERA_LOGI("%s:%d : this = %p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
GonkCameraHardware::ReleaseHandle(mHwHandle);
if (mRwLock) {
PRRWLock* lock = mRwLock;
mRwLock = nullptr;
PR_DestroyRWLock(lock);
}
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
}
class RwAutoLockRead
{
public:
RwAutoLockRead(PRRWLock* aRwLock)
: mRwLock(aRwLock)
{
PR_RWLock_Rlock(mRwLock);
}
~RwAutoLockRead()
{
PR_RWLock_Unlock(mRwLock);
}
protected:
PRRWLock* mRwLock;
};
class RwAutoLockWrite
{
public:
RwAutoLockWrite(PRRWLock* aRwLock)
: mRwLock(aRwLock)
{
PR_RWLock_Wlock(mRwLock);
}
~RwAutoLockWrite()
{
PR_RWLock_Unlock(mRwLock);
}
protected:
PRRWLock* mRwLock;
};
const char*
nsGonkCameraControl::GetParameter(const char* aKey)
{
RwAutoLockRead lock(mRwLock);
return mParams.get(aKey);
}
const char*
nsGonkCameraControl::GetParameterConstChar(PRUint32 aKey)
{
const char* key = getKeyText(aKey);
if (!key) {
return nullptr;
}
RwAutoLockRead lock(mRwLock);
return mParams.get(key);
}
double
nsGonkCameraControl::GetParameterDouble(PRUint32 aKey)
{
double val;
int index = 0;
double focusDistance[3];
const char* s;
const char* key = getKeyText(aKey);
if (!key) {
// return 1x when zooming is not supported
return aKey == CAMERA_PARAM_ZOOM ? 1.0 : 0.0;
}
RwAutoLockRead lock(mRwLock);
switch (aKey) {
case CAMERA_PARAM_ZOOM:
val = mParams.getInt(key);
return val / 100;
/**
* The gonk camera parameters API only exposes one focus distance property
* that contains "Near,Optimum,Far" distances, in metres, where 'Far' may
* be 'Infinity'.
*/
case CAMERA_PARAM_FOCUSDISTANCEFAR:
++index;
// intentional fallthrough
case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
++index;
// intentional fallthrough
case CAMERA_PARAM_FOCUSDISTANCENEAR:
s = mParams.get(key);
if (sscanf(s, "%lf,%lf,%lf", &focusDistance[0], &focusDistance[1], &focusDistance[2]) == 3) {
return focusDistance[index];
}
return 0.0;
case CAMERA_PARAM_EXPOSURECOMPENSATION:
index = mParams.getInt(key);
if (!index) {
// NaN indicates automatic exposure compensation
return NAN;
}
val = (index - 1) * mExposureCompensationStep + mExposureCompensationMin;
DOM_CAMERA_LOGI("index = %d --> compensation = %f\n", index, val);
return val;
default:
return mParams.getFloat(key);
}
}
void
nsGonkCameraControl::GetParameter(PRUint32 aKey, nsTArray<CameraRegion>& aRegions)
{
aRegions.Clear();
const char* key = getKeyText(aKey);
if (!key) {
return;
}
RwAutoLockRead lock(mRwLock);
const char* value = mParams.get(key);
DOM_CAMERA_LOGI("key='%s' --> value='%s'\n", key, value);
if (!value) {
return;
}
const char* p = value;
PRUint32 count = 1;
// count the number of regions in the string
while ((p = strstr(p, "),("))) {
++count;
p += 3;
}
aRegions.SetCapacity(count);
CameraRegion* r;
// parse all of the region sets
PRUint32 i;
for (i = 0, p = value; p && i < count; ++i, p = strchr(p + 1, '(')) {
r = aRegions.AppendElement();
if (sscanf(p, "(%d,%d,%d,%d,%u)", &r->top, &r->left, &r->bottom, &r->right, &r->weight) != 5) {
DOM_CAMERA_LOGE("%s:%d : region tuple has bad format: '%s'\n", __func__, __LINE__, p);
goto GetParameter_error;
}
}
return;
GetParameter_error:
aRegions.Clear();
}
void
nsGonkCameraControl::PushParameters()
{
if (!mDeferConfigUpdate) {
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
/**
* If we're already on the camera thread, call PushParametersImpl()
* directly, so that it executes synchronously. Some callers
* require this so that changes take effect immediately before
* we can proceed.
*/
if (NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> pushParametersTask = new PushParametersTask(this);
mCameraThread->Dispatch(pushParametersTask, NS_DISPATCH_NORMAL);
} else {
PushParametersImpl(nullptr);
}
}
}
void
nsGonkCameraControl::SetParameter(const char* aKey, const char* aValue)
{
{
RwAutoLockWrite lock(mRwLock);
mParams.set(aKey, aValue);
}
PushParameters();
}
void
nsGonkCameraControl::SetParameter(PRUint32 aKey, const char* aValue)
{
const char* key = getKeyText(aKey);
if (!key) {
return;
}
{
RwAutoLockWrite lock(mRwLock);
mParams.set(key, aValue);
}
PushParameters();
}
void
nsGonkCameraControl::SetParameter(PRUint32 aKey, double aValue)
{
PRUint32 index;
const char* key = getKeyText(aKey);
if (!key) {
return;
}
{
RwAutoLockWrite lock(mRwLock);
if (aKey == 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("compensation = %f --> index = %d\n", aValue, index);
mParams.set(key, index);
} else {
mParams.setFloat(key, aValue);
}
}
PushParameters();
}
void
nsGonkCameraControl::SetParameter(PRUint32 aKey, const nsTArray<CameraRegion>& aRegions)
{
const char* key = getKeyText(aKey);
if (!key) {
return;
}
PRUint32 length = aRegions.Length();
if (!length) {
// This tells the camera driver to revert to automatic regioning.
mParams.set(key, "(0,0,0,0,0)");
PushParameters();
return;
}
nsCString s;
for (PRUint32 i = 0; i < length; ++i) {
const CameraRegion* r = &aRegions[i];
s.AppendPrintf("(%d,%d,%d,%d,%d),", r->top, r->left, r->bottom, r->right, r->weight);
}
// remove the trailing comma
s.Trim(",", false, true, true);
DOM_CAMERA_LOGI("camera region string '%s'\n", s.get());
{
RwAutoLockWrite lock(mRwLock);
mParams.set(key, s.get());
}
PushParameters();
}
nsresult
nsGonkCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream)
{
nsCOMPtr<CameraPreview> preview = mPreview;
nsresult rv;
if (!preview) {
preview = new GonkCameraPreview(mHwHandle, aGetPreviewStream->mSize.width, aGetPreviewStream->mSize.height);
if (!preview) {
if (aGetPreviewStream->mOnErrorCb) {
rv = NS_DispatchToMainThread(new CameraErrorResult(aGetPreviewStream->mOnErrorCb, NS_LITERAL_STRING("OUT_OF_MEMORY")));
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_ERROR_OUT_OF_MEMORY;
}
}
mPreview = preview;
return NS_DispatchToMainThread(new GetPreviewStreamResult(preview.get(), aGetPreviewStream->mOnSuccessCb));
}
nsresult
nsGonkCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
{
nsCOMPtr<nsICameraAutoFocusCallback> cb = mAutoFocusOnSuccessCb;
if (cb) {
/**
* We already have a callback, so someone has already
* called autoFocus() -- cancel it.
*/
mAutoFocusOnSuccessCb = nullptr;
nsCOMPtr<nsICameraErrorCallback> ecb = mAutoFocusOnErrorCb;
mAutoFocusOnErrorCb = nullptr;
if (ecb) {
nsresult rv = NS_DispatchToMainThread(new CameraErrorResult(ecb, NS_LITERAL_STRING("CANCELLED")));
NS_ENSURE_SUCCESS(rv, rv);
}
GonkCameraHardware::CancelAutoFocus(mHwHandle);
}
mAutoFocusOnSuccessCb = aAutoFocus->mOnSuccessCb;
mAutoFocusOnErrorCb = aAutoFocus->mOnErrorCb;
if (GonkCameraHardware::AutoFocus(mHwHandle) != OK) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
{
nsCOMPtr<nsICameraTakePictureCallback> cb = mTakePictureOnSuccessCb;
if (cb) {
/**
* We already have a callback, so someone has already
* called TakePicture() -- cancel it.
*/
mTakePictureOnSuccessCb = nullptr;
nsCOMPtr<nsICameraErrorCallback> ecb = mTakePictureOnErrorCb;
mTakePictureOnErrorCb = nullptr;
if (ecb) {
nsresult rv = NS_DispatchToMainThread(new CameraErrorResult(ecb, NS_LITERAL_STRING("CANCELLED")));
NS_ENSURE_SUCCESS(rv, rv);
}
GonkCameraHardware::CancelTakePicture(mHwHandle);
}
mTakePictureOnSuccessCb = aTakePicture->mOnSuccessCb;
mTakePictureOnErrorCb = aTakePicture->mOnErrorCb;
// batch-update camera configuration
mDeferConfigUpdate = true;
/**
* height and width: some drivers are less friendly about getting one of
* these set to zero, so if either is not specified, ignore both and go
* with current or default settings.
*/
if (aTakePicture->mSize.width && aTakePicture->mSize.height) {
nsCString s;
s.AppendPrintf("%dx%d", aTakePicture->mSize.width, aTakePicture->mSize.height);
DOM_CAMERA_LOGI("setting picture size to '%s'\n", s.get());
SetParameter(CameraParameters::KEY_PICTURE_SIZE, s.get());
}
// Picture format -- need to keep it for the callback.
mFileFormat = aTakePicture->mFileFormat;
SetParameter(CameraParameters::KEY_PICTURE_FORMAT, NS_ConvertUTF16toUTF8(mFileFormat).get());
// Convert 'rotation' to a positive value from 0..270 degrees, in steps of 90.
PRUint32 r = static_cast<PRUint32>(aTakePicture->mRotation);
r %= 360;
r += 45;
r /= 90;
r *= 90;
DOM_CAMERA_LOGI("setting picture rotation to %d degrees (mapped from %d)\n", r, aTakePicture->mRotation);
SetParameter(CameraParameters::KEY_ROTATION, nsPrintfCString("%u", r).get());
// Add any specified positional information -- don't care if these fail.
if (!isnan(aTakePicture->mPosition.latitude)) {
DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aTakePicture->mPosition.latitude);
SetParameter(CameraParameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aTakePicture->mPosition.latitude).get());
}
if (!isnan(aTakePicture->mPosition.longitude)) {
DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aTakePicture->mPosition.longitude);
SetParameter(CameraParameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aTakePicture->mPosition.longitude).get());
}
if (!isnan(aTakePicture->mPosition.altitude)) {
DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aTakePicture->mPosition.altitude);
SetParameter(CameraParameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aTakePicture->mPosition.altitude).get());
}
if (!isnan(aTakePicture->mPosition.timestamp)) {
DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aTakePicture->mPosition.timestamp);
SetParameter(CameraParameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aTakePicture->mPosition.timestamp).get());
}
mDeferConfigUpdate = false;
PushParameters();
if (GonkCameraHardware::TakePicture(mHwHandle) != OK) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsGonkCameraControl::PushParametersImpl(PushParametersTask* aPushParameters)
{
RwAutoLockRead lock(mRwLock);
if (GonkCameraHardware::PushParameters(mHwHandle, mParams) != OK) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsGonkCameraControl::PullParametersImpl(PullParametersTask* aPullParameters)
{
RwAutoLockWrite lock(mRwLock);
GonkCameraHardware::PullParameters(mHwHandle, mParams);
return NS_OK;
}
nsresult
nsGonkCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
nsGonkCameraControl::ReceiveFrame(PRUint8* aData, PRUint32 aLength)
{
nsCOMPtr<CameraPreview> preview = mPreview;
if (preview) {
GonkCameraPreview* p = static_cast<GonkCameraPreview* >(preview.get());
MOZ_ASSERT(p);
p->ReceiveFrame(aData, aLength);
}
}
// Gonk callback handlers.
namespace mozilla {
void
ReceiveImage(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength)
{
gc->TakePictureComplete(aData, aLength);
}
void
AutoFocusComplete(nsGonkCameraControl* gc, bool success)
{
gc->AutoFocusComplete(success);
}
void
ReceiveFrame(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength)
{
gc->ReceiveFrame(aData, aLength);
}
} // namespace mozilla

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DOM_CAMERA_GONKCAMERACONTROL_H
#define DOM_CAMERA_GONKCAMERACONTROL_H
#include "prtypes.h"
#include "prrwlock.h"
#include "CameraControl.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
namespace mozilla {
class nsGonkCameraControl : public nsCameraControl
{
public:
nsGonkCameraControl(PRUint32 aCameraId, nsIThread* aCameraThread);
const char* GetParameter(const char* aKey);
const char* GetParameterConstChar(PRUint32 aKey);
double GetParameterDouble(PRUint32 aKey);
void GetParameter(PRUint32 aKey, nsTArray<dom::CameraRegion>& aRegions);
void SetParameter(const char* aKey, const char* aValue);
void SetParameter(PRUint32 aKey, const char* aValue);
void SetParameter(PRUint32 aKey, double aValue);
void SetParameter(PRUint32 aKey, const nsTArray<dom::CameraRegion>& aRegions);
void PushParameters();
void ReceiveFrame(PRUint8 *aData, PRUint32 aLength);
protected:
~nsGonkCameraControl();
nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
nsresult TakePictureImpl(TakePictureTask* aTakePicture);
nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
nsresult PushParametersImpl(PushParametersTask* aPushParameters);
nsresult PullParametersImpl(PullParametersTask* aPullParameters);
PRUint32 mHwHandle;
double mExposureCompensationMin;
double mExposureCompensationStep;
bool mDeferConfigUpdate;
PRRWLock* mRwLock;
android::CameraParameters mParams;
private:
nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
nsGonkCameraControl& operator=(const nsGonkCameraControl&) MOZ_DELETE;
};
// camera driver callbacks
void ReceiveImage(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength);
void AutoFocusComplete(nsGonkCameraControl* gc, bool success);
void ReceiveFrame(nsGonkCameraControl* gc, PRUint8* aData, PRUint32 aLength);
} // namespace mozilla
#endif // DOM_CAMERA_GONKCAMERACONTROL_H

View File

@ -0,0 +1,435 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsDebug.h"
#include "GonkCameraHwMgr.h"
#include "GonkNativeWindow.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
using namespace mozilla;
#if GIHM_TIMING_RECEIVEFRAME
#define INCLUDE_TIME_H 1
#endif
#if GIHM_TIMING_OVERALL
#define INCLUDE_TIME_H 1
#endif
#if INCLUDE_TIME_H
#include <time.h>
static __inline void timespecSubtract(struct timespec* a, struct timespec* b)
{
// a = b - a
if (b->tv_nsec < a->tv_nsec) {
b->tv_nsec += 1000000000;
b->tv_sec -= 1;
}
a->tv_nsec = b->tv_nsec - a->tv_nsec;
a->tv_sec = b->tv_sec - a->tv_sec;
}
#endif
GonkCameraHardware::GonkCameraHardware(GonkCamera* aTarget, PRUint32 aCamera)
: mCamera(aCamera)
, mFps(30)
, mPreviewFormat(PREVIEW_FORMAT_UNKNOWN)
, mClosing(false)
, mMonitor("GonkCameraHardware.Monitor")
, mNumFrames(0)
, mTarget(aTarget)
, mInitialized(false)
{
DOM_CAMERA_LOGI( "%s: this = %p (aTarget = %p)\n", __func__, (void* )this, (void* )aTarget );
init();
}
// Android data callback
void
GonkCameraHardware::DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser)
{
GonkCameraHardware* hw = GetHardware((PRUint32)aUser);
if (!hw) {
DOM_CAMERA_LOGW("%s:aUser = %d resolved to no camera hw\n", __func__, (PRUint32)aUser);
return;
}
if (hw->mClosing) {
return;
}
GonkCamera* camera = hw->mTarget;
if (camera) {
switch (aMsgType) {
case CAMERA_MSG_PREVIEW_FRAME:
ReceiveFrame(camera, (PRUint8*)aDataPtr->pointer(), aDataPtr->size());
break;
case CAMERA_MSG_COMPRESSED_IMAGE:
ReceiveImage(camera, (PRUint8*)aDataPtr->pointer(), aDataPtr->size());
break;
default:
DOM_CAMERA_LOGE("Unhandled data callback event %d\n", aMsgType);
break;
}
} else {
DOM_CAMERA_LOGW("%s: hw = %p (camera = NULL)\n", __func__, hw);
}
}
// Android notify callback
void
GonkCameraHardware::NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser)
{
bool bSuccess;
GonkCameraHardware* hw = GetHardware((PRUint32)aUser);
if (!hw) {
DOM_CAMERA_LOGW("%s:aUser = %d resolved to no camera hw\n", __func__, (PRUint32)aUser);
return;
}
if (hw->mClosing) {
return;
}
GonkCamera* camera = hw->mTarget;
if (!camera) {
return;
}
switch (aMsgType) {
case CAMERA_MSG_FOCUS:
if (ext1) {
DOM_CAMERA_LOGI("Autofocus complete");
bSuccess = true;
} else {
DOM_CAMERA_LOGW("Autofocus failed");
bSuccess = false;
}
AutoFocusComplete(camera, bSuccess);
break;
case CAMERA_MSG_SHUTTER:
DOM_CAMERA_LOGW("Shutter event not handled yet\n");
break;
default:
DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType);
break;
}
}
void
GonkCameraHardware::init()
{
DOM_CAMERA_LOGI("%s: this = %p\n", __func__, (void* )this);
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t**)&mModule) < 0) {
return;
}
char cameraDeviceName[4];
snprintf(cameraDeviceName, sizeof(cameraDeviceName), "%d", mCamera);
mHardware = new CameraHardwareInterface(cameraDeviceName);
if (mHardware->initialize(&mModule->common) != OK) {
mHardware.clear();
return;
}
mWindow = new android::GonkNativeWindow();
if (sHwHandle == 0) {
sHwHandle = 1; // don't use 0
}
mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, NULL, (void*)sHwHandle);
// initialize the local camera parameter database
mParams = mHardware->getParameters();
mHardware->setPreviewWindow(mWindow);
mInitialized = true;
}
GonkCameraHardware::~GonkCameraHardware()
{
DOM_CAMERA_LOGI( "%s:%d : this = %p\n", __func__, __LINE__, (void*)this );
sHw = nullptr;
}
GonkCameraHardware* GonkCameraHardware::sHw = nullptr;
PRUint32 GonkCameraHardware::sHwHandle = 0;
void
GonkCameraHardware::ReleaseHandle(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
DOM_CAMERA_LOGI("%s: aHwHandle = %d, hw = %p (sHwHandle = %d)\n", __func__, aHwHandle, (void*)hw, sHwHandle);
if (!hw) {
return;
}
DOM_CAMERA_LOGI("%s: before: sHwHandle = %d\n", __func__, sHwHandle);
sHwHandle += 1; // invalidate old handles before deleting
hw->mClosing = true;
hw->mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
hw->mHardware->stopPreview();
hw->mHardware->release();
DOM_CAMERA_LOGI("%s: after: sHwHandle = %d\n", __func__, sHwHandle);
delete hw; // destroy the camera hardware instance
}
PRUint32
GonkCameraHardware::GetHandle(GonkCamera* aTarget, PRUint32 aCamera)
{
ReleaseHandle(sHwHandle);
sHw = new GonkCameraHardware(aTarget, aCamera);
if (sHw->IsInitialized()) {
return sHwHandle;
}
DOM_CAMERA_LOGE("failed to initialize camera hardware\n");
delete sHw;
sHw = nullptr;
return 0;
}
PRUint32
GonkCameraHardware::GetFps(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (!hw) {
return 0;
}
return hw->mFps;
}
void
GonkCameraHardware::GetPreviewSize(PRUint32 aHwHandle, PRUint32* aWidth, PRUint32* aHeight)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (hw) {
*aWidth = hw->mWidth;
*aHeight = hw->mHeight;
} else {
*aWidth = 0;
*aHeight = 0;
}
}
void
GonkCameraHardware::SetPreviewSize(PRUint32 aWidth, PRUint32 aHeight)
{
Vector<Size> previewSizes;
PRUint32 bestWidth = aWidth;
PRUint32 bestHeight = aHeight;
PRUint32 minSizeDelta = PR_UINT32_MAX;
PRUint32 delta;
Size size;
mParams.getSupportedPreviewSizes(previewSizes);
if (!aWidth && !aHeight) {
// no size specified, take the first supported size
size = previewSizes[0];
bestWidth = size.width;
bestHeight = size.height;
} else if (aWidth && aHeight) {
// both height and width specified, find the supported size closest to requested size
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
Size size = previewSizes[i];
PRUint32 delta = abs((long int)(size.width * size.height - aWidth * aHeight));
if (delta < minSizeDelta) {
minSizeDelta = delta;
bestWidth = size.width;
bestHeight = size.height;
}
}
} else if (!aWidth) {
// width not specified, find closest height match
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
size = previewSizes[i];
delta = abs((long int)(size.height - aHeight));
if (delta < minSizeDelta) {
minSizeDelta = delta;
bestWidth = size.width;
bestHeight = size.height;
}
}
} else if (!aHeight) {
// height not specified, find closest width match
for (PRUint32 i = 0; i < previewSizes.size(); i++) {
size = previewSizes[i];
delta = abs((long int)(size.width - aWidth));
if (delta < minSizeDelta) {
minSizeDelta = delta;
bestWidth = size.width;
bestHeight = size.height;
}
}
}
mWidth = bestWidth;
mHeight = bestHeight;
mParams.setPreviewSize(mWidth, mHeight);
}
void
GonkCameraHardware::SetPreviewSize(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (hw) {
hw->SetPreviewSize(aWidth, aHeight);
}
}
int
GonkCameraHardware::AutoFocus(PRUint32 aHwHandle)
{
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (!hw) {
return DEAD_OBJECT;
}
hw->mHardware->enableMsgType(CAMERA_MSG_FOCUS);
return hw->mHardware->autoFocus();
}
void
GonkCameraHardware::CancelAutoFocus(PRUint32 aHwHandle)
{
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (hw) {
hw->mHardware->cancelAutoFocus();
}
}
int
GonkCameraHardware::TakePicture(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (!hw) {
return DEAD_OBJECT;
}
hw->mHardware->enableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
return hw->mHardware->takePicture();
}
void
GonkCameraHardware::CancelTakePicture(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (hw) {
hw->mHardware->cancelPicture();
}
}
int
GonkCameraHardware::PushParameters(PRUint32 aHwHandle, const CameraParameters& aParams)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (!hw) {
return DEAD_OBJECT;
}
return hw->mHardware->setParameters(aParams);
}
void
GonkCameraHardware::PullParameters(PRUint32 aHwHandle, CameraParameters& aParams)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (hw) {
aParams = hw->mHardware->getParameters();
}
}
int
GonkCameraHardware::StartPreview()
{
const char* format;
mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
DOM_CAMERA_LOGI("Preview formats: %s\n", mParams.get(mParams.KEY_SUPPORTED_PREVIEW_FORMATS));
// try to set preferred image format and frame rate
const char* const PREVIEW_FORMAT = "yuv420p";
const char* const BAD_PREVIEW_FORMAT = "yuv420sp";
mParams.setPreviewFormat(PREVIEW_FORMAT);
mParams.setPreviewFrameRate(mFps);
mHardware->setParameters(mParams);
// check that our settings stuck
mParams = mHardware->getParameters();
format = mParams.getPreviewFormat();
if (strcmp(format, PREVIEW_FORMAT) == 0) {
mPreviewFormat = PREVIEW_FORMAT_YUV420P; /* \o/ */
} else if (strcmp(format, BAD_PREVIEW_FORMAT) == 0) {
mPreviewFormat = PREVIEW_FORMAT_YUV420SP;
DOM_CAMERA_LOGA("Camera ignored our request for '%s' preview, will have to convert (from %d)\n", PREVIEW_FORMAT, mPreviewFormat);
} else {
mPreviewFormat = PREVIEW_FORMAT_UNKNOWN;
DOM_CAMERA_LOGE("Camera ignored our request for '%s' preview, returned UNSUPPORTED format '%s'\n", PREVIEW_FORMAT, format);
}
// Check the frame rate and log if the camera ignored our setting
PRUint32 fps = mParams.getPreviewFrameRate();
if (fps != mFps) {
DOM_CAMERA_LOGA("We asked for %d fps but camera returned %d fps, using it", mFps, fps);
mFps = fps;
}
return mHardware->startPreview();
}
int
GonkCameraHardware::StartPreview(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
DOM_CAMERA_LOGI("%s:%d : aHwHandle = %d, hw = %p\n", __func__, __LINE__, aHwHandle, hw);
if (!hw) {
return DEAD_OBJECT;
}
return hw->StartPreview();
}
void
GonkCameraHardware::StopPreview(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (hw) {
hw->mHardware->stopPreview();
}
}
PRUint32
GonkCameraHardware::GetPreviewFormat(PRUint32 aHwHandle)
{
GonkCameraHardware* hw = GetHardware(aHwHandle);
if (!hw) {
return PREVIEW_FORMAT_UNKNOWN;
}
return hw->mPreviewFormat;
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DOM_CAMERA_GONKCAMERAHWMGR_H
#define DOM_CAMERA_GONKCAMERAHWMGR_H
#include "libcameraservice/CameraHardwareInterface.h"
#include "binder/IMemory.h"
#include "mozilla/ReentrantMonitor.h"
#include "GonkCameraControl.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
// config
#define GIHM_TIMING_RECEIVEFRAME 0
#define GIHM_TIMING_OVERALL 1
using namespace mozilla;
using namespace android;
namespace mozilla {
typedef class nsGonkCameraControl GonkCamera;
class GonkCameraHardware
{
protected:
GonkCameraHardware(GonkCamera* aTarget, PRUint32 aCamera);
~GonkCameraHardware();
void init();
static void DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser);
static void NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser);
public:
static void ReleaseHandle(PRUint32 aHwHandle);
static PRUint32 GetHandle(GonkCamera* aTarget, PRUint32 aCamera);
static PRUint32 GetFps(PRUint32 aHwHandle);
static void GetPreviewSize(PRUint32 aHwHandle, PRUint32* aWidth, PRUint32* aHeight);
static void SetPreviewSize(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight);
static int AutoFocus(PRUint32 aHwHandle);
static void CancelAutoFocus(PRUint32 aHwHandle);
static int TakePicture(PRUint32 aHwHandle);
static void CancelTakePicture(PRUint32 aHwHandle);
static int StartPreview(PRUint32 aHwHandle);
static void StopPreview(PRUint32 aHwHandle);
static int PushParameters(PRUint32 aHwHandle, const CameraParameters& aParams);
static void PullParameters(PRUint32 aHwHandle, CameraParameters& aParams);
enum {
PREVIEW_FORMAT_UNKNOWN,
PREVIEW_FORMAT_YUV420P,
PREVIEW_FORMAT_YUV420SP
};
// GetPreviewFormat() MUST be called only after StartPreview().
static PRUint32 GetPreviewFormat(PRUint32 aHwHandle);
protected:
static GonkCameraHardware* sHw;
static PRUint32 sHwHandle;
static GonkCameraHardware* GetHardware(PRUint32 aHwHandle)
{
if (aHwHandle == sHwHandle) {
/**
* In the initial case, sHw will be null and sHwHandle will be 0,
* so even if this function is called with aHwHandle = 0, the
* result will still be null.
*/
return sHw;
}
return nullptr;
}
// Instance wrappers to make member function access easier.
void SetPreviewSize(PRUint32 aWidth, PRUint32 aHeight);
int StartPreview();
PRUint32 mCamera;
PRUint32 mWidth;
PRUint32 mHeight;
PRUint32 mFps;
PRUint32 mPreviewFormat;
bool mClosing;
mozilla::ReentrantMonitor mMonitor;
PRUint32 mNumFrames;
sp<CameraHardwareInterface> mHardware;
GonkCamera* mTarget;
camera_module_t* mModule;
sp<ANativeWindow> mWindow;
CameraParameters mParams;
#if GIHM_TIMING_OVERALL
struct timespec mStart;
struct timespec mAutoFocusStart;
#endif
bool mInitialized;
bool IsInitialized()
{
return mInitialized;
}
private:
GonkCameraHardware(const GonkCameraHardware&) MOZ_DELETE;
GonkCameraHardware& operator=(const GonkCameraHardware&) MOZ_DELETE;
};
} // namespace mozilla
#endif // GONK_IMPL_HW_MGR_H

View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "jsapi.h"
#include "libcameraservice/CameraHardwareInterface.h"
#include "GonkCameraControl.h"
#include "DOMCameraManager.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
// From nsDOMCameraManager, but gonk-specific!
/* [implicit_jscontext] jsval getListOfCameras (); */
NS_IMETHODIMP
nsDOMCameraManager::GetListOfCameras(JSContext* cx, JS::Value* _retval)
{
JSObject* a = JS_NewArrayObject(cx, 0, nullptr);
camera_module_t* module;
PRUint32 index = 0;
PRUint32 count;
if (!a) {
DOM_CAMERA_LOGE("getListOfCameras : Could not create array object");
return NS_ERROR_OUT_OF_MEMORY;
}
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t**)&module) < 0) {
DOM_CAMERA_LOGE("getListOfCameras : Could not load camera HAL module");
return NS_ERROR_NOT_AVAILABLE;
}
count = module->get_number_of_cameras();
DOM_CAMERA_LOGI("getListOfCameras : get_number_of_cameras() returned %d\n", count);
while (count--) {
struct camera_info info;
int rv = module->get_camera_info(count, &info);
if (rv != 0) {
DOM_CAMERA_LOGE("getListOfCameras : get_camera_info(%d) failed: %d\n", count, rv);
continue;
}
JSString* v;
jsval jv;
switch (info.facing) {
case CAMERA_FACING_BACK:
v = JS_NewStringCopyZ(cx, "back");
index = 0;
break;
case CAMERA_FACING_FRONT:
v = JS_NewStringCopyZ(cx, "front");
index = 1;
break;
default:
// TODO: handle extra cameras in getCamera().
{
static PRUint32 extraIndex = 2;
nsCString s;
s.AppendPrintf("extra-camera-%d", count);
v = JS_NewStringCopyZ(cx, s.get());
index = extraIndex++;
}
break;
}
if (!v) {
DOM_CAMERA_LOGE("getListOfCameras : out of memory populating camera list");
delete a;
return NS_ERROR_NOT_AVAILABLE;
}
jv = STRING_TO_JSVAL(v);
if (!JS_SetElement(cx, a, index, &jv)) {
DOM_CAMERA_LOGE("getListOfCameras : failed building list of cameras");
delete a;
return NS_ERROR_NOT_AVAILABLE;
}
}
*_retval = OBJECT_TO_JSVAL(a);
return NS_OK;
}
using namespace mozilla;
NS_IMETHODIMP
GetCameraTask::Run()
{
nsCOMPtr<nsICameraControl> cameraControl = new nsGonkCameraControl(mCameraId, mCameraThread);
DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
return NS_DispatchToMainThread(new GetCameraResult(cameraControl, mOnSuccessCb));
}

View File

@ -0,0 +1,197 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VideoUtils.h"
#include "GonkCameraHwMgr.h"
#include "GonkCameraPreview.h"
#define DOM_CAMERA_LOG_LEVEL 2
#include "CameraCommon.h"
using namespace mozilla;
/**
* This big macro takes two 32-bit input blocks of interlaced u and
* v data (from a yuv420sp frame) in 's0' and 's1', and deinterlaces
* them into pairs of contiguous 32-bit blocks, the u plane data in
* 'u', and the v plane data in 'v' (i.e. for a yuv420p frame).
*
* yuv420sp:
* [ y-data ][ uv-data ]
* [ uv-data ]: [u0][v0][u1][v1][u2][v2]...
*
* yuv420p:
* [ y-data ][ u-data ][ v-data ]
* [ u-data ]: [u0][u1][u2]...
* [ v-data ]: [v0][v1][v2]...
*
* Doing this in 32-bit blocks is significantly faster than using
* byte-wise operations on ARM. (In some cases, the byte-wise
* de-interlacing can be too slow to keep up with the preview frames
* coming from the driver.
*/
#define DEINTERLACE( u, v, s0, s1 ) \
u = ( (s0) & 0xFF00UL ) >> 8 | ( (s0) & 0xFF000000UL ) >> 16; \
u |= ( (s1) & 0xFF00UL ) << 8 | ( (s1) & 0xFF000000UL ); \
v = ( (s0) & 0xFFUL ) | ( (s0) & 0xFF0000UL ) >> 8; \
v |= ( (s1) & 0xFFUL ) << 16 | ( (s1) & 0xFF0000UL ) << 8;
void
GonkCameraPreview::ReceiveFrame(PRUint8 *aData, PRUint32 aLength)
{
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mInput->HaveEnoughBuffered(TRACK_VIDEO)) {
if (mDiscardedFrameCount == 0) {
DOM_CAMERA_LOGI("mInput has enough data buffered, starting to discard\n");
}
++mDiscardedFrameCount;
return;
} else if (mDiscardedFrameCount) {
DOM_CAMERA_LOGI("mInput needs more data again; discarded %d frames in a row\n", mDiscardedFrameCount);
mDiscardedFrameCount = 0;
}
switch (mFormat) {
case GonkCameraHardware::PREVIEW_FORMAT_YUV420SP:
{
// de-interlace the u and v planes
uint8_t* y = aData;
uint32_t yN = mWidth * mHeight;
NS_ASSERTION(yN & 0x3 == 0, "Invalid image dimensions!");
uint32_t uvN = yN / 4;
uint32_t* src = (uint32_t*)( y + yN );
uint32_t* d = new uint32_t[ uvN / 2 ];
uint32_t* u = d;
uint32_t* v = u + uvN / 4;
// we're handling pairs of 32-bit words, so divide by 8
NS_ASSERTION(uvN & 0x7 == 0, "Invalid image dimensions!");
uvN /= 8;
while (uvN--) {
uint32_t src0 = *src++;
uint32_t src1 = *src++;
uint32_t u0;
uint32_t v0;
uint32_t u1;
uint32_t v1;
DEINTERLACE( u0, v0, src0, src1 );
src0 = *src++;
src1 = *src++;
DEINTERLACE( u1, v1, src0, src1 );
*u++ = u0;
*u++ = u1;
*v++ = v0;
*v++ = v1;
}
memcpy(y + yN, d, yN / 2);
delete[] d;
}
break;
case GonkCameraHardware::PREVIEW_FORMAT_YUV420P:
// no transformating required
break;
default:
// in a format we don't handle, get out of here
return;
}
Image::Format format = Image::PLANAR_YCBCR;
nsRefPtr<Image> image = mImageContainer->CreateImage(&format, 1);
image->AddRef();
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(image.get());
/**
* If you change either lumaBpp or chromaBpp, make sure the
* assertions below still hold.
*/
const PRUint8 lumaBpp = 8;
const PRUint8 chromaBpp = 4;
PlanarYCbCrImage::Data data;
data.mYChannel = aData;
data.mYSize = gfxIntSize(mWidth, mHeight);
data.mYStride = mWidth * lumaBpp;
NS_ASSERTION(data.mYStride & 0x7 == 0, "Invalid image dimensions!");
data.mYStride /= 8;
data.mCbCrStride = mWidth * chromaBpp;
NS_ASSERTION(data.mCbCrStride & 0x7 == 0, "Invalid image dimensions!");
data.mCbCrStride /= 8;
data.mCbChannel = aData + mHeight * data.mYStride;
data.mCrChannel = data.mCbChannel + mHeight * data.mCbCrStride / 2;
data.mCbCrSize = gfxIntSize(mWidth / 2, mHeight / 2);
data.mPicX = 0;
data.mPicY = 0;
data.mPicSize = gfxIntSize(mWidth, mHeight);
data.mStereoMode = mozilla::layers::STEREO_MODE_MONO;
videoImage->SetData(data); // copies buffer
mVideoSegment.AppendFrame(videoImage, 1, gfxIntSize(mWidth, mHeight));
mInput->AppendToTrack(TRACK_VIDEO, &mVideoSegment);
mFrameCount += 1;
if ((mFrameCount % 10) == 0) {
DOM_CAMERA_LOGI("%s:%d : mFrameCount = %d\n", __func__, __LINE__, mFrameCount);
}
}
void
GonkCameraPreview::Start()
{
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
/**
* We set and then immediately get the preview size, in case the camera
* driver has decided to ignore our given dimensions. We need to know
* the dimensions the driver is using so that, if needed, we can properly
* de-interlace the yuv420sp format in ReceiveFrame() above.
*/
GonkCameraHardware::SetPreviewSize(mHwHandle, mWidth, mHeight);
GonkCameraHardware::GetPreviewSize(mHwHandle, &mWidth, &mHeight);
SetFrameRate(GonkCameraHardware::GetFps(mHwHandle));
if (GonkCameraHardware::StartPreview(mHwHandle) == OK) {
// GetPreviewFormat() must be called after StartPreview().
mFormat = GonkCameraHardware::GetPreviewFormat(mHwHandle);
DOM_CAMERA_LOGI("preview stream is (actually!) %d x %d (w x h), %d frames per second, format %d\n", mWidth, mHeight, mFramesPerSecond, mFormat);
} else {
DOM_CAMERA_LOGE("%s: failed to start preview\n", __func__);
}
}
void
GonkCameraPreview::Stop()
{
DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
GonkCameraHardware::StopPreview(mHwHandle);
mInput->EndTrack(TRACK_VIDEO);
mInput->Finish();
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DOM_CAMERA_GONKCAMERAPREVIEW_H
#define DOM_CAMERA_GONKCAMERAPREVIEW_H
#include "CameraPreview.h"
#define DOM_CAMERA_LOG_LEVEL 3
#include "CameraCommon.h"
namespace mozilla {
class GonkCameraPreview : public CameraPreview
{
public:
GonkCameraPreview(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
: CameraPreview(aWidth, aHeight)
, mHwHandle(aHwHandle)
, mDiscardedFrameCount(0)
, mFormat(GonkCameraHardware::PREVIEW_FORMAT_UNKNOWN)
{ }
void ReceiveFrame(PRUint8 *aData, PRUint32 aLength);
void Start();
void Stop();
protected:
~GonkCameraPreview()
{
Stop();
}
PRUint32 mHwHandle;
PRUint32 mDiscardedFrameCount;
PRUint32 mFormat;
private:
GonkCameraPreview(const GonkCameraPreview&) MOZ_DELETE;
GonkCameraPreview& operator=(const GonkCameraPreview&) MOZ_DELETE;
};
} // namespace mozilla
#endif // DOM_CAMERA_GONKCAMERAPREVIEW_H

View File

@ -0,0 +1,475 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "GonkNativeWindow.h"
#include "nsDebug.h"
// enable debug logging by setting to 1
#define CNW_DEBUG 0
#if CNW_DEBUG
#define CNW_LOGD(...) {(void)printf_stderr(__VA_ARGS__);}
#else
#define CNW_LOGD(...) ((void)0)
#endif
#define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);}
using namespace android;
GonkNativeWindow::GonkNativeWindow()
{
GonkNativeWindow::init();
}
GonkNativeWindow::~GonkNativeWindow()
{
freeAllBuffersLocked();
}
void GonkNativeWindow::init()
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::lockBuffer = hook_lockBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
mDefaultWidth = 0;
mDefaultHeight = 0;
mPixelFormat = 0;
mUsage = 0;
mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
mBufferCount = MIN_BUFFER_SLOTS;
mFrameCounter = 0;
}
int GonkNativeWindow::hook_setSwapInterval(ANativeWindow* window, int interval)
{
GonkNativeWindow* c = getSelf(window);
return c->setSwapInterval(interval);
}
int GonkNativeWindow::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer)
{
GonkNativeWindow* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
int GonkNativeWindow::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
GonkNativeWindow* c = getSelf(window);
return c->cancelBuffer(buffer);
}
int GonkNativeWindow::hook_lockBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
GonkNativeWindow* c = getSelf(window);
return c->lockBuffer(buffer);
}
int GonkNativeWindow::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
GonkNativeWindow* c = getSelf(window);
return c->queueBuffer(buffer);
}
int GonkNativeWindow::hook_query(const ANativeWindow* window,
int what, int* value)
{
const GonkNativeWindow* c = getSelf(window);
return c->query(what, value);
}
int GonkNativeWindow::hook_perform(ANativeWindow* window, int operation, ...)
{
va_list args;
va_start(args, operation);
GonkNativeWindow* c = getSelf(window);
return c->perform(operation, args);
}
void GonkNativeWindow::freeBufferLocked(int i)
{
if (mSlots[i].mGraphicBuffer != NULL) {
mSlots[i].mGraphicBuffer.clear();
mSlots[i].mGraphicBuffer = NULL;
}
mSlots[i].mBufferState = BufferSlot::FREE;
}
void GonkNativeWindow::freeAllBuffersLocked()
{
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
freeBufferLocked(i);
}
}
int GonkNativeWindow::setBufferCount(int bufferCount) {
CNW_LOGD("setBufferCount: count=%d", bufferCount);
Mutex::Autolock lock(mMutex);
if (bufferCount > NUM_BUFFER_SLOTS) {
CNW_LOGE("setBufferCount: bufferCount larger than slots available");
return BAD_VALUE;
}
// special-case, nothing to do
if (bufferCount == mBufferCount) {
return OK;
}
if (bufferCount < MIN_BUFFER_SLOTS) {
CNW_LOGE("setBufferCount: requested buffer count (%d) is less than "
"minimum (%d)", bufferCount, MIN_BUFFER_SLOTS);
return BAD_VALUE;
}
// Error out if the user has dequeued buffers
for (int i=0 ; i<mBufferCount ; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
CNW_LOGE("setBufferCount: client owns some buffers");
return -EINVAL;
}
}
if (bufferCount > mBufferCount) {
// easy, we just have more buffers
mBufferCount = bufferCount;
mDequeueCondition.signal();
return OK;
}
// reducing the number of buffers
// here we're guaranteed that the client doesn't have dequeued buffers
// and will release all of its buffer references.
freeAllBuffersLocked();
mBufferCount = bufferCount;
mDequeueCondition.signal();
return OK;
}
int GonkNativeWindow::dequeueBuffer(android_native_buffer_t** buffer)
{
Mutex::Autolock lock(mMutex);
int found = -1;
int dequeuedCount = 0;
bool tryAgain = true;
CNW_LOGD("dequeueBuffer: E");
while (tryAgain) {
// look for a free buffer to give to the client
found = INVALID_BUFFER_SLOT;
dequeuedCount = 0;
for (int i = 0; i < mBufferCount; i++) {
const int state = mSlots[i].mBufferState;
if (state == BufferSlot::DEQUEUED) {
dequeuedCount++;
}
else if (state == BufferSlot::FREE) {
/* We return the oldest of the free buffers to avoid
* stalling the producer if possible. This is because
* the consumer may still have pending reads of the
* buffers in flight.
*/
bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber;
if (found < 0 || isOlder) {
found = i;
}
}
}
// we're in synchronous mode and didn't find a buffer, we need to
// wait for some buffers to be consumed
tryAgain = (found == INVALID_BUFFER_SLOT);
if (tryAgain) {
mDequeueCondition.wait(mMutex);
}
}
if (found == INVALID_BUFFER_SLOT) {
// This should not happen.
CNW_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const int buf = found;
// buffer is now in DEQUEUED
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer);
if (gbuf == NULL) {
status_t error;
sp<GraphicBuffer> graphicBuffer( new GraphicBuffer( mDefaultWidth, mDefaultHeight, mPixelFormat, mUsage));
error = graphicBuffer->initCheck();
if (error != NO_ERROR) {
CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d",error);
return error;
}
mSlots[buf].mGraphicBuffer = graphicBuffer;
}
*buffer = mSlots[buf].mGraphicBuffer.get();
CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
mSlots[buf].mGraphicBuffer->handle );
CNW_LOGD("dequeueBuffer: X");
return NO_ERROR;
}
int GonkNativeWindow::getSlotFromBufferLocked(
android_native_buffer_t* buffer) const
{
if (buffer == NULL) {
CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
return BAD_VALUE;
}
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
return i;
}
}
CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
return BAD_VALUE;
}
int GonkNativeWindow::queueBuffer(ANativeWindowBuffer* buffer)
{
Mutex::Autolock lock(mMutex);
CNW_LOGD("queueBuffer: E");
int buf = getSlotFromBufferLocked(buffer);
if (buf < 0 || buf >= mBufferCount) {
CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
return -EINVAL;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
CNW_LOGE("queueBuffer: slot %d is not owned by the client "
"(state=%d)", buf, mSlots[buf].mBufferState);
return -EINVAL;
}
int64_t timestamp;
if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
} else {
timestamp = mTimestamp;
}
// Set the state to FREE as there are no operations on the queued buffer
// And, so that the buffer can be dequeued when needed.
mSlots[buf].mBufferState = BufferSlot::FREE;
mSlots[buf].mTimestamp = timestamp;
mFrameCounter++;
mSlots[buf].mFrameNumber = mFrameCounter;
mDequeueCondition.signal();
CNW_LOGD("queueBuffer: X");
return OK;
}
int GonkNativeWindow::lockBuffer(ANativeWindowBuffer* buffer)
{
CNW_LOGD("GonkNativeWindow::lockBuffer");
Mutex::Autolock lock(mMutex);
return OK;
}
int GonkNativeWindow::cancelBuffer(ANativeWindowBuffer* buffer)
{
Mutex::Autolock lock(mMutex);
int buf = getSlotFromBufferLocked(buffer);
CNW_LOGD("cancelBuffer: slot=%d", buf);
if (buf < 0 || buf >= mBufferCount) {
CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
return -EINVAL;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
buf, mSlots[buf].mBufferState);
return -EINVAL;
}
mSlots[buf].mBufferState = BufferSlot::FREE;
mSlots[buf].mFrameNumber = 0;
mDequeueCondition.signal();
return OK;
}
int GonkNativeWindow::perform(int operation, va_list args)
{
switch (operation) {
case NATIVE_WINDOW_CONNECT:
// deprecated. must return NO_ERROR.
return NO_ERROR;
case NATIVE_WINDOW_DISCONNECT:
// deprecated. must return NO_ERROR.
return NO_ERROR;
case NATIVE_WINDOW_SET_USAGE:
return dispatchSetUsage(args);
case NATIVE_WINDOW_SET_BUFFER_COUNT:
return dispatchSetBufferCount(args);
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
return dispatchSetBuffersGeometry(args);
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
return dispatchSetBuffersTimestamp(args);
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
return dispatchSetBuffersDimensions(args);
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
return dispatchSetBuffersFormat(args);
case NATIVE_WINDOW_SET_CROP:
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
case NATIVE_WINDOW_SET_SCALING_MODE:
case NATIVE_WINDOW_LOCK:
case NATIVE_WINDOW_UNLOCK_AND_POST:
case NATIVE_WINDOW_API_CONNECT:
case NATIVE_WINDOW_API_DISCONNECT:
default:
return INVALID_OPERATION;
}
}
int GonkNativeWindow::query(int what, int* outValue) const
{
Mutex::Autolock lock(mMutex);
int value;
switch (what) {
case NATIVE_WINDOW_WIDTH:
value = mDefaultWidth;
break;
case NATIVE_WINDOW_HEIGHT:
value = mDefaultHeight;
break;
case NATIVE_WINDOW_FORMAT:
value = mPixelFormat;
break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
value = MIN_UNDEQUEUED_BUFFERS;
break;
default:
return BAD_VALUE;
}
outValue[0] = value;
return NO_ERROR;
}
int GonkNativeWindow::setSwapInterval(int interval)
{
return NO_ERROR;
}
int GonkNativeWindow::dispatchSetUsage(va_list args)
{
int usage = va_arg(args, int);
return setUsage(usage);
}
int GonkNativeWindow::dispatchSetBufferCount(va_list args)
{
size_t bufferCount = va_arg(args, size_t);
return setBufferCount(bufferCount);
}
int GonkNativeWindow::dispatchSetBuffersGeometry(va_list args)
{
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
int err = setBuffersDimensions(w, h);
if (err != 0) {
return err;
}
return setBuffersFormat(f);
}
int GonkNativeWindow::dispatchSetBuffersDimensions(va_list args)
{
int w = va_arg(args, int);
int h = va_arg(args, int);
return setBuffersDimensions(w, h);
}
int GonkNativeWindow::dispatchSetBuffersFormat(va_list args)
{
int f = va_arg(args, int);
return setBuffersFormat(f);
}
int GonkNativeWindow::dispatchSetBuffersTimestamp(va_list args)
{
int64_t timestamp = va_arg(args, int64_t);
return setBuffersTimestamp(timestamp);
}
int GonkNativeWindow::setUsage(uint32_t reqUsage)
{
CNW_LOGD("GonkNativeWindow::setUsage");
Mutex::Autolock lock(mMutex);
mUsage = reqUsage;
return OK;
}
int GonkNativeWindow::setBuffersDimensions(int w, int h)
{
CNW_LOGD("GonkNativeWindow::setBuffersDimensions");
Mutex::Autolock lock(mMutex);
if (w<0 || h<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
return BAD_VALUE;
mDefaultWidth = w;
mDefaultHeight = h;
return OK;
}
int GonkNativeWindow::setBuffersFormat(int format)
{
CNW_LOGD("GonkNativeWindow::setBuffersFormat");
Mutex::Autolock lock(mMutex);
if (format<0)
return BAD_VALUE;
mPixelFormat = format;
return NO_ERROR;
}
int GonkNativeWindow::setBuffersTimestamp(int64_t timestamp)
{
CNW_LOGD("GonkNativeWindow::setBuffersTimestamp");
Mutex::Autolock lock(mMutex);
mTimestamp = timestamp;
return OK;
}

View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012 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
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DOM_CAMERA_GONKNATIVEWINDOW_H
#define DOM_CAMERA_GONKNATIVEWINDOW_H
#include <stdint.h>
#include <sys/types.h>
#include <ui/egl/android_natives.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <utils/threads.h>
namespace android {
class GonkNativeWindow : public EGLNativeBase<ANativeWindow, GonkNativeWindow, RefBase>
{
public:
enum { MIN_UNDEQUEUED_BUFFERS = 2 };
enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS };
enum { NUM_BUFFER_SLOTS = 32 };
GonkNativeWindow();
~GonkNativeWindow(); // this class cannot be overloaded
// ANativeWindow hooks
static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int hook_perform(ANativeWindow* window, int operation, ...);
static int hook_query(const ANativeWindow* window, int what, int* value);
static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int hook_setSwapInterval(ANativeWindow* window, int interval);
protected:
virtual int cancelBuffer(ANativeWindowBuffer* buffer);
virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
virtual int lockBuffer(ANativeWindowBuffer* buffer);
virtual int perform(int operation, va_list args);
virtual int query(int what, int* value) const;
virtual int queueBuffer(ANativeWindowBuffer* buffer);
virtual int setSwapInterval(int interval);
virtual int setBufferCount(int bufferCount);
virtual int setBuffersDimensions(int w, int h);
virtual int setBuffersFormat(int format);
virtual int setBuffersTimestamp(int64_t timestamp);
virtual int setUsage(uint32_t reqUsage);
// freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
// for the given slot.
void freeBufferLocked(int index);
// freeAllBuffersLocked frees the resources (both GraphicBuffer and
// EGLImage) for all slots.
void freeAllBuffersLocked();
private:
void init();
int dispatchSetBufferCount(va_list args);
int dispatchSetBuffersGeometry(va_list args);
int dispatchSetBuffersDimensions(va_list args);
int dispatchSetBuffersFormat(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetUsage(va_list args);
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
private:
enum { INVALID_BUFFER_SLOT = -1 };
struct BufferSlot {
BufferSlot()
: mGraphicBuffer(0),
mBufferState(BufferSlot::FREE),
mTimestamp(0),
mFrameNumber(0){
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
// if no buffer has been allocated.
sp<GraphicBuffer> mGraphicBuffer;
// BufferState represents the different states in which a buffer slot
// can be.
enum BufferState {
// FREE indicates that the buffer is not currently being used and
// will not be used in the future until it gets dequeued and
// subsequently queued by the client.
FREE = 0,
// DEQUEUED indicates that the buffer has been dequeued by the
// client, but has not yet been queued or canceled. The buffer is
// considered 'owned' by the client, and the server should not use
// it for anything.
//
// Note that when in synchronous-mode (mSynchronousMode == true),
// the buffer that's currently attached to the texture may be
// dequeued by the client. That means that the current buffer can
// be in either the DEQUEUED or QUEUED state. In asynchronous mode,
// however, the current buffer is always in the QUEUED state.
DEQUEUED = 1,
// QUEUED indicates that the buffer has been queued by the client,
// and has not since been made available for the client to dequeue.
// Attaching the buffer to the texture does NOT transition the
// buffer away from the QUEUED state. However, in Synchronous mode
// the current buffer may be dequeued by the client under some
// circumstances. See the note about the current buffer in the
// documentation for DEQUEUED.
QUEUED = 2,
};
// mBufferState is the current state of this buffer slot.
BufferState mBufferState;
// mTimestamp is the current timestamp for this buffer slot. This gets
// to set by queueBuffer each time this slot is queued.
int64_t mTimestamp;
// mFrameNumber is the number of the queued frame for this slot.
uint64_t mFrameNumber;
};
// mSlots is the array of buffer slots that must be mirrored on the client
// side. This allows buffer ownership to be transferred between the client
// and server without sending a GraphicBuffer over binder. The entire array
// is initialized to NULL at construction time, and buffers are allocated
// for a slot when requestBuffer is called with that slot's index.
BufferSlot mSlots[NUM_BUFFER_SLOTS];
// mDequeueCondition condition used for dequeueBuffer in synchronous mode
mutable Condition mDequeueCondition;
// mTimestamp is the timestamp that will be used for the next buffer queue
// operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
// a timestamp is auto-generated when queueBuffer is called.
int64_t mTimestamp;
// mDefaultWidth holds the default width of allocated buffers. It is used
// in requestBuffers() if a width and height of zero is specified.
uint32_t mDefaultWidth;
// mDefaultHeight holds the default height of allocated buffers. It is used
// in requestBuffers() if a width and height of zero is specified.
uint32_t mDefaultHeight;
// mPixelFormat holds the pixel format of allocated buffers. It is used
// in requestBuffers() if a format of zero is specified.
uint32_t mPixelFormat;
// usage flag
uint32_t mUsage;
// mBufferCount is the number of buffer slots that the client and server
// must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
// by calling setBufferCount or setBufferCountServer
int mBufferCount;
// mMutex is the mutex used to prevent concurrent access to the member
// variables. It must be locked whenever the member variables are accessed.
mutable Mutex mMutex;
// mFrameCounter is the free running counter, incremented for every buffer queued
uint64_t mFrameCounter;
};
}; // namespace android
#endif // DOM_CAMERA_GONKNATIVEWINDOW_H

52
dom/camera/Makefile.in Normal file
View File

@ -0,0 +1,52 @@
# 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/.
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
LIBRARY_NAME = domcamera_s
XPIDL_MODULE = dom_camera
LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1
include $(topsrcdir)/dom/dom-config.mk
CPPSRCS = \
DOMCameraManager.cpp \
CameraControl.cpp \
CameraPreview.cpp \
$(NULL)
ifeq ($(MOZ_B2G_CAMERA),1)
CPPSRCS += \
GonkCameraManager.cpp \
GonkCameraControl.cpp \
GonkCameraHwMgr.cpp \
GonkCameraPreview.cpp \
GonkNativeWindow.cpp \
GonkCameraCapabilities.cpp \
$(NULL)
else
CPPSRCS += \
FallbackCameraManager.cpp \
FallbackCameraControl.cpp \
FallbackCameraCapabilities.cpp \
$(NULL)
endif
XPIDLSRCS = \
nsIDOMNavigatorCamera.idl \
nsIDOMCameraManager.idl \
$(NULL)
EXPORTS = \
DOMCameraManager.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,341 @@
#include "domstubs.idl"
#include "nsIDOMMediaStream.idl"
#include "nsIDOMDOMRequest.idl"
interface nsIDOMBlob;
/* Used to set the dimensions of a captured picture,
a preview stream, a video capture stream, etc. */
dictionary CameraSize {
unsigned long width;
unsigned long height;
};
/* Camera regions are used to set focus and metering areas;
the coordinates are referenced to the sensor:
(-1000, -1000) is the top left corner
(1000, 1000) is the bottom left corner
The weight of the region can range from 0 to 1000. */
dictionary CameraRegion {
long top;
long left;
long bottom;
long right;
unsigned long weight;
};
/* The position information to record in the image header.
'NaN' indicates the information is not available. */
dictionary CameraPosition {
double latitude;
double longitude;
double altitude;
double timestamp;
};
/* Select a camera to use. */
dictionary CameraSelector {
DOMString camera = "back";
};
[scriptable, uuid(64196840-0d03-4b65-a955-790f43a4b810)]
interface nsICameraCapabilities : nsISupports
{
/* an array of objects with 'height' and 'width' properties
supported for the preview stream */
[implicit_jscontext]
readonly attribute jsval previewSizes;
/* an array of objects with 'height' and 'width' properties
supported for picture taking */
[implicit_jscontext]
readonly attribute jsval pictureSizes;
/* an array of strings, e.g. [ "jpeg", "rgb565" ] */
[implicit_jscontext]
readonly attribute jsval fileFormats;
/* an array of strings, e.g. [ "auto", "fluorescent", etc. ] */
[implicit_jscontext]
readonly attribute jsval whiteBalanceModes;
/* an array of strings, e.g. [ "auto", "night", "beach", etc. ] */
[implicit_jscontext]
readonly attribute jsval sceneModes;
/* an array of strings, e.g. [ "normal", "sepia", "mono", etc. ] */
[implicit_jscontext]
readonly attribute jsval effects;
/* an array of strings, e.g. [ "auto", "off", "on", etc. ] */
[implicit_jscontext]
readonly attribute jsval flashModes;
/* an array of strings, e.g. [ "auto", "fixed", "macro", etc. ] */
[implicit_jscontext]
readonly attribute jsval focusModes;
/* the maximum number of focus areas supported by the camera */
[implicit_jscontext]
readonly attribute long maxFocusAreas;
/* the minimum supported exposure compensation value */
[implicit_jscontext]
readonly attribute double minExposureCompensation;
/* the maximum supported exposure compensation value */
[implicit_jscontext]
readonly attribute double maxExposureCompensation;
/* exposure compensation minimum step-size */
[implicit_jscontext]
readonly attribute double stepExposureCompensation;
/* the maximum number of metering areas supported by the camera */
[implicit_jscontext]
readonly attribute long maxMeteringAreas;
/* an array of doubles, e.g. [ 1.0, 1.2, 1.5, 2.0, 3.0, etc. ],
or null if zooming is not supported */
[implicit_jscontext]
readonly attribute jsval zoomRatios;
/* an array of objects with 'height' and 'width' properties
supported for video recording */
[implicit_jscontext]
readonly attribute jsval videoSizes;
};
/*
These properties only affect the captured image;
invalid property settings are ignored.
*/
dictionary CameraPictureOptions
{
/* an object with a combination of 'height' and 'width' properties
chosen from nsICameraCapabilities.pictureSizes */
jsval pictureSize;
/* one of the file formats chosen from
nsICameraCapabilities.fileFormats */
DOMString fileFormat;
/* the rotation of the image in degrees, from 0 to 270 in
steps of 90; this doesn't affect the image, only the
rotation recorded in the image header.*/
long rotation;
/* an object containing any or all of 'latitude', 'longitude',
'altitude', and 'timestamp', used to record when and where
the image was taken. e.g.
{
latitude: 43.647118,
longitude: -79.3943,
altitude: 500
// timestamp not specified, in this case, and
// won't be included in the image header
}
can be null in the case where position information isn't
available/desired.
'altitude' is in metres; 'timestamp' is UTC, in seconds from
January 1, 1970.
*/
jsval position;
};
[scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
interface nsICameraPreviewStreamCallback : nsISupports
{
void handleEvent(in nsIDOMMediaStream stream);
};
[scriptable, function, uuid(6baa4ac7-9c25-4c48-9bb0-5193b38b9b0a)]
interface nsICameraAutoFocusCallback : nsISupports
{
void handleEvent(in boolean success);
};
[scriptable, function, uuid(17af779e-cb6f-4ca5-890c-06468ff82e4f)]
interface nsICameraTakePictureCallback : nsISupports
{
void handleEvent(in nsIDOMBlob picture);
};
[scriptable, function, uuid(ac43f123-529c-48d3-84dd-ad206b7aca9b)]
interface nsICameraStartRecordingCallback : nsISupports
{
void handleEvent(in nsIDOMMediaStream stream);
};
[scriptable, function, uuid(fb80db71-e315-42f0-9ea9-dd3dd312ed70)]
interface nsICameraShutterCallback : nsISupports
{
void handleEvent();
};
[scriptable, function, uuid(a302c6c9-3776-4d1d-a395-f4105d47c3d3)]
interface nsICameraErrorCallback : nsISupports
{
void handleEvent(in DOMString error);
};
/*
attributes here affect the preview, any pictures taken, and/or
any video recorded by the camera.
*/
[scriptable, uuid(3066c884-d2c3-4477-847d-08ea1c2d188a)]
interface nsICameraControl : nsISupports
{
readonly attribute nsICameraCapabilities capabilities;
/* one of the vales chosen from capabilities.effects;
default is "none" */
attribute DOMString effect;
/* one of the values chosen from capabilities.whiteBalanceModes;
default is "auto" */
attribute DOMString whiteBalanceMode;
/* one of the valus chosen from capabilities.sceneModes;
default is "auto" */
attribute DOMString sceneMode;
/* one of the values chosen from capabilities.flashModes;
default is "auto" */
attribute DOMString flashMode;
/* one of the values chosen from capabilities.focusModes;
default is "auto", if supported, or "fixed" */
attribute DOMString focusMode;
/* one of the values chosen from capabilities.zoomRatios; other
values will be rounded to the nearest supported value;
default is 1.0 */
attribute double zoom;
/* an array of one or more objects that define where the
camera will perform light metering, each defining the properties:
{
top: -1000,
left: -1000,
bottom: 1000,
right: 1000,
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.
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. */
[implicit_jscontext]
attribute jsval meteringAreas;
/* an array of one or more objects that define where the camera will
perform auto-focusing, with the same definition as meteringAreas.
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. */
[implicit_jscontext]
attribute jsval focusAreas;
/* focal length in millimetres */
readonly attribute double focalLength;
/* the distances in metres to where the image subject appears to be
in focus. 'focusDistanceOptimum' is where the subject will appear
sharpest; the difference between 'focusDistanceFar' and
'focusDistanceNear' is the image's depth of field.
'focusDistanceFar' may be infinity. */
readonly attribute double focusDistanceNear;
readonly attribute double focusDistanceOptimum;
readonly attribute double focusDistanceFar;
/* 'compensation' is optional, and if missing, will
set the camera to use automatic exposure compensation.
acceptable values must range from minExposureCompensation
to maxExposureCompensation in steps of stepExposureCompensation;
invalid values will be rounded to the nearest valid value. */
[implicit_jscontext]
void setExposureCompensation([optional] in jsval compensation);
readonly attribute double exposureCompensation;
/* the function to call on the camera's shutter event, to trigger
a shutter sound and/or a visual shutter indicator. */
attribute nsICameraShutterCallback onShutter;
/* tell the camera to attempt to focus the image */
void autoFocus(in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* capture an image and return it as a blob to the 'onSuccess' callback;
if the camera supports it, this may be invoked while the camera is
already recording video.
invoking this function will stop the preview stream, which must be
manually restarted (e.g. by calling .play() on it). */
[implicit_jscontext]
void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* start recording video; 'aOptions' define the frame size of to
capture, chosen from capabilities.videoSizes, e.g.:
{
width: 640,
height: 480
}
*/
[implicit_jscontext]
void startRecording(in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* stop precording video. */
void stopRecording();
/* get a media stream to be used as a camera viewfinder; the options
define the desired frame size of the preview, chosen from
capabilities.previewSizes, e.g.:
{
height: 640,
width: 480,
}
*/
[implicit_jscontext]
void getPreviewStream(in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError);
};
[scriptable, function, uuid(a267afbc-d91c-413a-8de5-0b94aecffa3e)]
interface nsICameraGetCameraCallback : nsISupports
{
void handleEvent(in nsICameraControl camera);
};
[scriptable, uuid(671ee624-0336-441a-a24e-26b5319f14fe)]
interface nsIDOMCameraManager : nsISupports
{
/* get a camera instance; options will be used to specify which
camera to get from the list returned by getListOfCameras(), e.g.:
{
camera: front
}
*/
[implicit_jscontext]
void getCamera([optional] in jsval aOptions, in nsICameraGetCameraCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* return a JSON array of camera identifiers, e.g.
[ "front", "back" ]
*/
[implicit_jscontext]
jsval getListOfCameras();
};

View File

@ -0,0 +1,15 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* 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 "nsISupports.idl"
interface nsIDOMCameraManager;
[scriptable, uuid(bbb2456a-a6c8-42c8-8f52-6de071097e4b)]
interface nsIDOMNavigatorCamera : nsISupports
{
readonly attribute nsIDOMCameraManager mozCameras;
};

View File

@ -30,6 +30,7 @@ DOM_SRCDIRS = \
layout/style \
layout/xul/base/src \
layout/xul/base/src/tree/src \
dom/camera \
$(NULL)
ifdef MOZ_B2G_RIL

View File

@ -523,7 +523,11 @@ var interfaceNamesInGlobalScope =
"ContactTelephone",
"ContactEmail",
"SVGFitToViewBox",
"SVGAElement"
"SVGAElement",
"NavigatorCamera",
"CameraControl",
"CameraCapabilities",
"CameraManager"
]
for (var i in Components.interfaces) {

View File

@ -1450,6 +1450,27 @@ private:
JSObject* mPreservedWrapper;
};
// Dynamically ensure that two objects don't end up with the same private.
class AutoClonePrivateGuard NS_STACK_CLASS {
public:
AutoClonePrivateGuard(JSObject *aOld, JSObject *aNew)
: mOldReflector(aOld), mNewReflector(aNew)
{
MOZ_ASSERT(JS_GetPrivate(aOld) == JS_GetPrivate(aNew));
}
~AutoClonePrivateGuard()
{
if (JS_GetPrivate(mOldReflector)) {
JS_SetPrivate(mNewReflector, nullptr);
}
}
private:
JSObject* mOldReflector;
JSObject* mNewReflector;
};
// static
nsresult
XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
@ -1540,10 +1561,66 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
}
if (wrapper) {
Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
// First, the clone of the reflector, get a copy of its
// properties and clone its expando chain. The only part that is
// dangerous here if we have to return early is that we must avoid
// ending up with two reflectors pointing to the same WN. Other than
// that, the objects we create will just go away if we return early.
JSObject *newobj = JS_CloneObject(ccx, flat,
newProto->GetJSProtoObject(),
aNewParent);
if (!newobj)
return NS_ERROR_FAILURE;
// At this point, both |flat| and |newobj| point to the same wrapped
// native, which is bad, because one of them will end up finalizing
// a wrapped native it does not own. |cloneGuard| ensures that if we
// exit before calling clearing |flat|'s private the private of
// |newobj| will be set to NULL. |flat| will go away soon, because
// we swap it with another object during the transplant and let that
// object die.
JSObject *propertyHolder;
{
AutoClonePrivateGuard cloneGuard(flat, newobj);
propertyHolder = JS_NewObjectWithGivenProto(ccx, NULL, NULL, aNewParent);
if (!propertyHolder)
return NS_ERROR_OUT_OF_MEMORY;
if (!JS_CopyPropertiesFrom(ccx, propertyHolder, flat))
return NS_ERROR_FAILURE;
// Expandos from other compartments are attached to the target JS object.
// Copy them over, and let the old ones die a natural death.
SetExpandoChain(newobj, nullptr);
if (!XrayUtils::CloneExpandoChain(ccx, newobj, flat))
return NS_ERROR_FAILURE;
// We've set up |newobj|, so we make it own the WN by nulling out
// the private of |flat|.
//
// NB: It's important to do this _after_ copying the properties to
// propertyHolder. Otherwise, an object with |foo.x === foo| will
// crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
JS_SetPrivate(flat, nullptr);
}
// Before proceeding, eagerly create any same-compartment security wrappers
// that the object might have. This forces us to take the 'WithWrapper' path
// while transplanting that handles this stuff correctly.
{
JSAutoEnterCompartment innerAC;
if (!innerAC.enter(ccx, aOldScope->GetGlobalJSObject()) ||
!wrapper->GetSameCompartmentSecurityWrapper(ccx))
return NS_ERROR_FAILURE;
}
// Update scope maps. This section modifies global state, so from
// here on out we crash if anything fails.
{ // scoped lock
Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock());
oldMap->Remove(wrapper);
@ -1573,47 +1650,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
NS_ASSERTION(!newMap->Find(wrapper->GetIdentityObject()),
"wrapper already in new scope!");
(void) newMap->Add(wrapper);
if (!newMap->Add(wrapper))
MOZ_CRASH();
}
JSObject *newobj = JS_CloneObject(ccx, flat,
newProto->GetJSProtoObject(),
aNewParent);
if (!newobj)
return NS_ERROR_FAILURE;
JSObject *propertyHolder =
JS_NewObjectWithGivenProto(ccx, NULL, NULL, aNewParent);
if (!propertyHolder || !JS_CopyPropertiesFrom(ccx, propertyHolder, flat))
return NS_ERROR_OUT_OF_MEMORY;
// Expandos from other compartments are attached to the target JS object.
// Copy them over, and let the old ones die a natural death.
SetExpandoChain(newobj, nullptr);
if (!XrayUtils::CloneExpandoChain(ccx, newobj, flat))
return NS_ERROR_FAILURE;
// Before proceeding, eagerly create any same-compartment security wrappers
// that the object might have. This forces us to take the 'WithWrapper' path
// while transplanting that handles this stuff correctly.
{
JSAutoEnterCompartment innerAC;
if (!innerAC.enter(ccx, aOldScope->GetGlobalJSObject()) ||
!wrapper->GetSameCompartmentSecurityWrapper(ccx))
return NS_ERROR_FAILURE;
}
// Null out the private of the JS reflector. If we don't, we'll end up
// with two JS objects with the same WN in their private slot, and both
// will try to delete it during finalization. The one in this
// compartment will actually go away quite soon, because we swap() it
// with another object during the transplant and let that object die.
//
// NB: It's important to do this _after_ copying the properties to
// propertyHolder. Otherwise, an object with |foo.x === foo| will
// crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
JS_SetPrivate(flat, nullptr);
JSObject *ww = wrapper->GetWrapper();
if (ww) {
JSObject *newwrapper;
@ -1622,41 +1662,37 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
if (xpc::WrapperFactory::IsLocationObject(flat)) {
newwrapper = xpc::WrapperFactory::WrapLocationObject(ccx, newobj);
if (!newwrapper)
return NS_ERROR_FAILURE;
MOZ_CRASH();
} else {
NS_ASSERTION(wrapper->NeedsSOW(), "weird wrapper wrapper");
newwrapper = xpc::WrapperFactory::WrapSOWObject(ccx, newobj);
if (!newwrapper)
return NS_ERROR_FAILURE;
MOZ_CRASH();
}
// Ok, now we do the special object-plus-wrapper transplant.
ww = xpc::TransplantObjectWithWrapper(ccx, flat, ww, newobj,
newwrapper);
if (!ww)
return NS_ERROR_FAILURE;
MOZ_CRASH();
flat = newobj;
wrapper->SetWrapper(ww);
} else {
flat = xpc::TransplantObject(ccx, flat, newobj);
if (!flat)
return NS_ERROR_FAILURE;
MOZ_CRASH();
}
wrapper->mFlatJSObject = flat;
if (cache)
cache->SetWrapper(flat);
if (!JS_CopyPropertiesFrom(ccx, flat, propertyHolder))
return NS_ERROR_FAILURE;
MOZ_CRASH();
} else {
SetSlimWrapperProto(flat, newProto.get());
if (!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject())) {
// this is bad, very bad
SetSlimWrapperProto(flat, nullptr);
NS_ERROR("JS_SetPrototype failed");
return NS_ERROR_FAILURE;
}
if (!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject()))
MOZ_CRASH(); // this is bad, very bad
}
// Call the scriptable hook to indicate that we transplanted.
@ -1669,13 +1705,13 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
if (aNewParent) {
if (!JS_SetParent(ccx, flat, aNewParent))
return NS_ERROR_FAILURE;
MOZ_CRASH();
JSObject *nw;
if (wrapper &&
(nw = wrapper->GetWrapper()) &&
!JS_SetParent(ccx, nw, JS_GetGlobalForObject(ccx, aNewParent))) {
return NS_ERROR_FAILURE;
MOZ_CRASH();
}
}

View File

@ -18,7 +18,12 @@ dictionaries = [
[ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
[ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
[ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
[ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ]
[ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ],
[ 'CameraSize', 'nsIDOMCameraManager.idl' ],
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ]
]
# include file names

View File

@ -121,6 +121,8 @@ ifdef MOZ_B2G_BT #{
SHARED_LIBRARY_LIBS += $(DEPTH)/dom/bluetooth/$(LIB_PREFIX)dombluetooth_s.$(LIB_SUFFIX)
endif #}
SHARED_LIBRARY_LIBS += $(DEPTH)/dom/camera/$(LIB_PREFIX)domcamera_s.$(LIB_SUFFIX)
ifdef MOZ_B2G_RIL #{
SHARED_LIBRARY_LIBS += \
$(DEPTH)/dom/system/gonk/$(LIB_PREFIX)domsystemgonk_s.$(LIB_SUFFIX) \
@ -273,4 +275,6 @@ ifdef MOZ_B2G_BT #{
LOCAL_INCLUDES += -I$(topsrcdir)/dom/bluetooth
endif #}
LOCAL_INCLUDES += -I$(topsrcdir)/dom/camera
DEFINES += -D_IMPL_NS_LAYOUT

View File

@ -1 +1,2 @@
Matthew Gregan <kinetik@flim.org>
Alexandre Ratchov <alex@caoua.org>

View File

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
The git commit ID used was 21d9678eb9755761f7a9d26253189b926258de7c.
The git commit ID used was f3116936eba69aced240df7db77264269f3f95ae.

View File

@ -40,8 +40,8 @@ extern "C" {
cubeb_stream_start(stm);
for (;;) {
cubeb_get_time(stm, &ts);
printf("time=%lu\n", ts);
cubeb_stream_get_position(stm, &ts);
printf("time=%llu\n", ts);
sleep(1);
}
cubeb_stream_stop(stm);
@ -64,10 +64,9 @@ extern "C" {
@endcode
@code
int state_cb(cubeb_stream * stm, void * user, cubeb_state state)
void state_cb(cubeb_stream * stm, void * user, cubeb_state state)
{
printf("state=%d\n", state);
return CUBEB_OK;
}
@endcode
*/
@ -141,12 +140,10 @@ typedef long (* cubeb_data_callback)(cubeb_stream * stream,
/** User supplied state callback.
@param stream
@param user_ptr
@param state
@retval CUBEB_OK
@retval CUBEB_ERROR */
typedef int (* cubeb_state_callback)(cubeb_stream * stream,
void * user_ptr,
cubeb_state state);
@param state */
typedef void (* cubeb_state_callback)(cubeb_stream * stream,
void * user_ptr,
cubeb_state state);
/** Initialize an application context. This will perform any library or
application scoped initialization.
@ -156,6 +153,11 @@ typedef int (* cubeb_state_callback)(cubeb_stream * stream,
@retval CUBEB_ERROR */
int cubeb_init(cubeb ** context, char const * context_name);
/** Get a read-only string identifying this context's current backend.
@param context
@retval Read-only string identifying current backend. */
char const * cubeb_get_backend_id(cubeb * context);
/** Destroy an application context.
@param context */
void cubeb_destroy(cubeb * context);

View File

@ -20,6 +20,8 @@
#define CUBEB_WATCHDOG_MS 10000
#define UNUSED __attribute__ ((__unused__))
#define ALSA_PA_PLUGIN "ALSA <-> PulseAudio PCM I/O Plugin"
/* ALSA is not thread-safe. snd_pcm_t instances are individually protected
by the owning cubeb_stream's mutex. snd_pcm_t creation and destruction
is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1),
@ -474,6 +476,24 @@ silent_error_handler(char const * file UNUSED, int line UNUSED, char const * fun
{
}
static int
pcm_uses_pulseaudio_plugin(snd_pcm_t * pcm)
{
snd_output_t * out;
char * buf;
size_t bufsz;
int r;
snd_output_buffer_open(&out);
snd_pcm_dump(pcm, out);
bufsz = snd_output_buffer_string(out, &buf);
r = bufsz >= strlen(ALSA_PA_PLUGIN) &&
strncmp(buf, ALSA_PA_PLUGIN, strlen(ALSA_PA_PLUGIN)) == 0;
snd_output_close(out);
return r;
}
int
cubeb_init(cubeb ** context, char const * context_name UNUSED)
{
@ -531,6 +551,12 @@ cubeb_init(cubeb ** context, char const * context_name UNUSED)
return CUBEB_OK;
}
char const *
cubeb_get_backend_id(cubeb * ctx UNUSED)
{
return "alsa";
}
void
cubeb_destroy(cubeb * ctx)
{
@ -621,6 +647,12 @@ cubeb_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
r = snd_pcm_nonblock(stm->pcm, 1);
assert(r == 0);
/* Ugly hack: the PA ALSA plugin allows buffer configurations that can't
possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274 */
if (pcm_uses_pulseaudio_plugin(stm->pcm)) {
latency = latency < 200 ? 200 : latency;
}
r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED,
stm->params.channels, stm->params.rate, 1,
latency * 1000);

View File

@ -87,6 +87,12 @@ cubeb_init(cubeb ** context, char const * context_name)
return CUBEB_OK;
}
char const *
cubeb_get_backend_id(cubeb * ctx)
{
return "audiounit";
}
void
cubeb_destroy(cubeb * ctx)
{

View File

@ -116,9 +116,9 @@ stream_request_callback(pa_stream * s, size_t nbytes, void * u)
if ((size_t) got < size / frame_size) {
size_t buffer_fill = pa_stream_get_buffer_attr(s)->maxlength - pa_stream_writable_size(s);
double buffer_time = (double) buffer_fill / stm->sample_spec.rate;
pa_usec_t buffer_time = pa_bytes_to_usec(buffer_fill, &stm->sample_spec);
/* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */
stm->drain_timer = pa_context_rttime_new(stm->context->context, pa_rtclock_now() + buffer_time * 1e6, stream_drain_callback, stm);
stm->drain_timer = pa_context_rttime_new(stm->context->context, pa_rtclock_now() + buffer_time, stream_drain_callback, stm);
stm->shutdown = 1;
return;
}
@ -211,6 +211,12 @@ cubeb_init(cubeb ** context, char const * context_name)
return CUBEB_OK;
}
char const *
cubeb_get_backend_id(cubeb * ctx)
{
return "pulse";
}
void
cubeb_destroy(cubeb * ctx)
{
@ -295,7 +301,7 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
battr.maxlength = -1;
battr.tlength = pa_usec_to_bytes(latency * PA_USEC_PER_MSEC, &stm->sample_spec);
battr.prebuf = -1;
battr.minreq = battr.tlength / 2;
battr.minreq = battr.tlength / 4;
battr.fragsize = -1;
pa_threaded_mainloop_lock(stm->context->mainloop);

View File

@ -1,5 +1,5 @@
/*
* Copyright <EFBFBD>Â<EFBFBD>© 2011 Mozilla Foundation
* Copyright © 2011 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
@ -123,6 +123,7 @@ cubeb_refill_stream(cubeb_stream * stm)
got = stm->data_callback(stm, stm->user_ptr, hdr->lpData, wanted);
EnterCriticalSection(&stm->lock);
if (got < 0) {
LeaveCriticalSection(&stm->lock);
/* XXX handle this case */
assert(0);
return;
@ -226,6 +227,12 @@ cubeb_init(cubeb ** context, char const * context_name)
return CUBEB_OK;
}
char const *
cubeb_get_backend_id(cubeb * ctx)
{
return "winmm";
}
void
cubeb_destroy(cubeb * ctx)
{

View File

@ -1960,13 +1960,6 @@ var UserAgent = {
if (tab == null)
break;
if (channel.URI.host.indexOf("youtube") != -1) {
let ua = Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).userAgent;
#expand let version = "__MOZ_APP_VERSION__";
ua += " Fennec/" + version;
channel.setRequestHeader("User-Agent", ua, false);
}
// Send desktop UA if "Request Desktop Site" is enabled
if (tab.desktopMode)
channel.setRequestHeader("User-Agent", this.DESKTOP_UA, false);

View File

@ -164,6 +164,7 @@
#ifdef MOZ_B2G_BT
@BINPATH@/components/dom_bluetooth.xpt
#endif
@BINPATH@/components/dom_camera.xpt
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_core.xpt
@BINPATH@/components/dom_css.xpt

View File

@ -201,20 +201,6 @@ SocialProvider.prototype = {
updateUserProfile: function(profile) {
this.profile = profile;
// Sanitize the portrait from any potential script-injection.
if (profile.portrait) {
try {
let portraitUri = Services.io.newURI(profile.portrait, null, null);
let scheme = portraitUri ? portraitUri.scheme : "";
if (scheme != "data" && scheme != "http" && scheme != "https") {
profile.portrait = "";
}
} catch (ex) {
profile.portrait = "";
}
}
if (profile.iconURL)
this.iconURL = profile.iconURL;