mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team
This commit is contained in:
commit
acba6fe86f
@ -474,7 +474,7 @@ HTMLTextFieldAccessible::GetEditor() const
|
||||
// nsGenericHTMLElement::GetEditor has a security check.
|
||||
// Make sure we're not restricted by the permissions of
|
||||
// whatever script is currently running.
|
||||
mozilla::dom::AutoSystemCaller asc;
|
||||
mozilla::dom::AutoNoJSAPI nojsapi;
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editableElt->GetEditor(getter_AddRefs(editor));
|
||||
|
@ -274,6 +274,7 @@ pref("ui.dragThresholdY", 25);
|
||||
pref("layers.offmainthreadcomposition.enabled", true);
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
pref("dom.ipc.tabs.disabled", true);
|
||||
pref("layers.acceleration.disabled", true);
|
||||
pref("layers.offmainthreadcomposition.async-animations", false);
|
||||
pref("layers.async-video.enabled", false);
|
||||
#else
|
||||
|
@ -52,6 +52,10 @@ function checkDebuggerPort() {
|
||||
// DebuggerServer.openListener detects that it isn't a file path (string),
|
||||
// and starts listening on the tcp port given here as command line argument.
|
||||
|
||||
if (!window.arguments) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the command line arguments that were passed to the b2g client
|
||||
let args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
let runAppObj;
|
||||
window.addEventListener('load', function() {
|
||||
if (!window.arguments) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the command line arguments that were passed to the b2g client
|
||||
let args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
let appname;
|
||||
|
@ -57,12 +57,19 @@ window.addEventListener('ContentStart', function() {
|
||||
};
|
||||
|
||||
// Get the command line arguments that were passed to the b2g client
|
||||
let args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
let screenarg;
|
||||
let args;
|
||||
try {
|
||||
// On Firefox Mulet, we don't always have a command line argument
|
||||
args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
|
||||
} catch(e) {}
|
||||
|
||||
let screenarg = null;
|
||||
|
||||
// Get the --screen argument from the command line
|
||||
try {
|
||||
screenarg = args.handleFlagWithParam('screen', false);
|
||||
if (args) {
|
||||
screenarg = args.handleFlagWithParam('screen', false);
|
||||
}
|
||||
|
||||
// If there isn't one, use the default screen
|
||||
if (screenarg === null)
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "a54e097e9e3384d885c0116d9c4ca15c1e1cd75e",
|
||||
"revision": "c766bc0d49af19f18788ad8ed0542b82db81f1d8",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553da99ab09b6b894d9f95bb06b16b6e1ddbf0a1"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3d47c0627017ef77b1adf179792c6543a349af72"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -183,7 +183,6 @@
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
@BINPATH@/components/dom_html.xpt
|
||||
@BINPATH@/components/dom_indexeddb.xpt
|
||||
@BINPATH@/components/dom_inputmethod.xpt
|
||||
@BINPATH@/components/dom_offline.xpt
|
||||
@BINPATH@/components/dom_payment.xpt
|
||||
@BINPATH@/components/dom_json.xpt
|
||||
|
@ -60,6 +60,7 @@ whitelist['nightly']['macosx-universal'] += [
|
||||
whitelist['nightly']['win32'] += [
|
||||
'. $topsrcdir/configs/mozilla2/win32/include/choose-make-flags',
|
||||
'mk_add_options MOZ_MAKE_FLAGS=-j1',
|
||||
'. "$topsrcdir/build/mozconfig.cache"',
|
||||
'if test "$IS_NIGHTLY" != ""; then',
|
||||
'ac_add_options --disable-auto-deps',
|
||||
'fi',
|
||||
|
@ -19,4 +19,6 @@ ac_add_options --enable-warnings-as-errors
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
|
@ -6,4 +6,6 @@ ac_add_options --enable-profiling
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
|
@ -4,5 +4,17 @@
|
||||
"digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
|
||||
"algorithm": "sha512",
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"size": 95,
|
||||
"digest": "258c35efc786841267f8d377943274bd3eb4bd81bed2186db57b98c1543f4c513faf4f7845daf66821ef3b555ea3c2133e0d980a5ef10154f6d24596ff3a5de5",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 160232,
|
||||
"digest": "8656c3fc2daa66839ec81a0edbd9759040a83c7a41c3e472d7f90508b80eefd008b87305dc8549b4ff6098dc33fe17fedc9b4eb76cf5307d5f22dae925c033db",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.xz"
|
||||
}
|
||||
]
|
||||
|
@ -203,7 +203,6 @@
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
@BINPATH@/components/dom_html.xpt
|
||||
@BINPATH@/components/dom_indexeddb.xpt
|
||||
@BINPATH@/components/dom_inputmethod.xpt
|
||||
@BINPATH@/components/dom_offline.xpt
|
||||
@BINPATH@/components/dom_json.xpt
|
||||
@BINPATH@/components/dom_power.xpt
|
||||
|
@ -11,6 +11,10 @@ EOF
|
||||
bucket=
|
||||
if test -z "$SCCACHE_DISABLE" -a -z "$no_tooltool"; then
|
||||
case "${branch}_${master}" in
|
||||
try_*scl1.mozilla.com*|try_*.scl3.mozilla.com*)
|
||||
bucket=mozilla-releng-ceph-cache-scl3-try
|
||||
mk_add_options "export SCCACHE_NO_HTTPS=1"
|
||||
;;
|
||||
try_*use1.mozilla.com*)
|
||||
bucket=mozilla-releng-s3-cache-us-east-1-try
|
||||
;;
|
||||
@ -36,4 +40,18 @@ else
|
||||
ac_add_options "--with-compiler-wrapper=python2.7 $topsrcdir/sccache/sccache.py"
|
||||
mk_add_options MOZ_PREFLIGHT+=build/sccache.mk
|
||||
mk_add_options MOZ_POSTFLIGHT+=build/sccache.mk
|
||||
case "$platform" in
|
||||
win*)
|
||||
# sccache supports a special flag to create depfiles.
|
||||
export _DEPEND_CFLAGS='-deps$(MDDEPDIR)/$(@F).pp'
|
||||
# Windows builds have a default wrapper that needs to be overridden
|
||||
mk_add_options "export CC_WRAPPER="
|
||||
mk_add_options "export CXX_WRAPPER="
|
||||
# For now, sccache doesn't support separate PDBs so force debug info to be
|
||||
# in object files.
|
||||
mk_add_options "export COMPILE_PDB_FLAG="
|
||||
mk_add_options "export HOST_PDB_FLAG="
|
||||
mk_add_options "export MOZ_DEBUG_FLAGS=-Z7"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
@ -82,6 +82,7 @@ included_inclnames_to_ignore = set([
|
||||
'unicode/udat.h', # ICU
|
||||
'unicode/udatpg.h', # ICU
|
||||
'unicode/uenum.h', # ICU
|
||||
'unicode/unorm.h', # ICU
|
||||
'unicode/unum.h', # ICU
|
||||
'unicode/ustring.h', # ICU
|
||||
'unicode/utypes.h', # ICU
|
||||
@ -200,7 +201,7 @@ class FileKind(object):
|
||||
if filename.endswith('.cpp'):
|
||||
return FileKind.CPP
|
||||
|
||||
if filename.endswith(('inlines.h', '-inl.h', 'Inlines.h')):
|
||||
if filename.endswith(('inlines.h', '-inl.h')):
|
||||
return FileKind.INL_H
|
||||
|
||||
if filename.endswith('.h'):
|
||||
|
@ -415,7 +415,7 @@ protected:
|
||||
mozilla::dom::ParentObject p(aNativeParent);
|
||||
// Note that mUseXBLScope is a no-op for chrome, and other places where we
|
||||
// don't use XBL scopes.
|
||||
p.mUseXBLScope = IsInAnonymousSubtree();
|
||||
p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -1012,6 +1012,9 @@ public:
|
||||
|
||||
bool IsInAnonymousSubtree() const;
|
||||
|
||||
// Note: This asserts |IsInAnonymousSubtree()|.
|
||||
bool IsAnonymousContentInSVGUseSubtree() const;
|
||||
|
||||
// True for native anonymous content and for XBL content if the binging
|
||||
// has chromeOnlyContent="true".
|
||||
bool ChromeOnlyAccess() const
|
||||
|
@ -375,6 +375,15 @@ nsINode::IsInAnonymousSubtree() const
|
||||
return AsContent()->IsInAnonymousSubtree();
|
||||
}
|
||||
|
||||
bool
|
||||
nsINode::IsAnonymousContentInSVGUseSubtree() const
|
||||
{
|
||||
MOZ_ASSERT(IsInAnonymousSubtree());
|
||||
nsIContent* parent = AsContent()->GetBindingParent();
|
||||
// Watch out for parentless native-anonymous subtrees.
|
||||
return parent && parent->IsSVG(nsGkAtoms::use);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsINode::GetParentNode(nsIDOMNode** aParentNode)
|
||||
{
|
||||
|
@ -466,14 +466,15 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
|
||||
mFrameCreateCalled = false;
|
||||
|
||||
// We need to make sure that our image request is deregistered.
|
||||
nsPresContext* presContext = GetFramePresContext();
|
||||
if (mCurrentRequest) {
|
||||
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
|
||||
nsLayoutUtils::DeregisterImageRequest(presContext,
|
||||
mCurrentRequest,
|
||||
&mCurrentRequestRegistered);
|
||||
}
|
||||
|
||||
if (mPendingRequest) {
|
||||
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
|
||||
nsLayoutUtils::DeregisterImageRequest(presContext,
|
||||
mPendingRequest,
|
||||
&mPendingRequestRegistered);
|
||||
}
|
||||
@ -481,6 +482,11 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
|
||||
UntrackImage(mCurrentRequest);
|
||||
UntrackImage(mPendingRequest);
|
||||
|
||||
nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
|
||||
if (presShell) {
|
||||
presShell->RemoveImageFromVisibleList(this);
|
||||
}
|
||||
|
||||
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
|
||||
// We assume all images in popups are visible, so this decrement balances
|
||||
// out the increment in FrameCreated above.
|
||||
|
@ -3635,7 +3635,6 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
|
||||
return;
|
||||
}
|
||||
nsRefPtr<gfxContext> thebes;
|
||||
nsRefPtr<gfxASurface> drawSurf;
|
||||
RefPtr<DrawTarget> drawDT;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget)) {
|
||||
thebes = new gfxContext(mTarget);
|
||||
@ -3656,34 +3655,15 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
|
||||
unused << shell->RenderDocument(r, renderDocFlags, backgroundColor, thebes);
|
||||
if (drawSurf || drawDT) {
|
||||
RefPtr<SourceSurface> source;
|
||||
if (drawDT) {
|
||||
RefPtr<SourceSurface> snapshot = drawDT->Snapshot();
|
||||
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
|
||||
|
||||
if (drawSurf) {
|
||||
gfxIntSize size = drawSurf->GetSize();
|
||||
|
||||
drawSurf->SetDeviceOffset(gfxPoint(0, 0));
|
||||
nsRefPtr<gfxImageSurface> img = drawSurf->GetAsReadableARGB32ImageSurface();
|
||||
if (!img || !img->Data()) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
source =
|
||||
mTarget->CreateSourceSurfaceFromData(img->Data(),
|
||||
IntSize(size.width, size.height),
|
||||
img->Stride(),
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
} else {
|
||||
RefPtr<SourceSurface> snapshot = drawDT->Snapshot();
|
||||
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
|
||||
|
||||
source =
|
||||
mTarget->CreateSourceSurfaceFromData(data->GetData(),
|
||||
data->GetSize(),
|
||||
data->Stride(),
|
||||
data->GetFormat());
|
||||
}
|
||||
RefPtr<SourceSurface> source =
|
||||
mTarget->CreateSourceSurfaceFromData(data->GetData(),
|
||||
data->GetSize(),
|
||||
data->Stride(),
|
||||
data->GetFormat());
|
||||
|
||||
if (!source) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
@ -3694,7 +3674,8 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
|
||||
mgfx::Rect sourceRect(0, 0, sw, sh);
|
||||
mTarget->DrawSurface(source, destRect, sourceRect,
|
||||
DrawSurfaceOptions(mgfx::Filter::POINT),
|
||||
DrawOptions(1.0f, CompositionOp::OP_SOURCE, AntialiasMode::NONE));
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER,
|
||||
AntialiasMode::NONE));
|
||||
mTarget->Flush();
|
||||
} else {
|
||||
mTarget->SetTransform(matrix);
|
||||
|
@ -2,3 +2,5 @@
|
||||
support-files = nonchrome_webgl_debug_renderer_info.html
|
||||
|
||||
[test_webgl_debug_renderer_info.html]
|
||||
[test_drawWindow_widget_layers.html]
|
||||
support-files = ../file_drawWindow_source.html ../file_drawWindow_common.js
|
||||
|
@ -0,0 +1,50 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for canvas drawWindow</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<script type="application/javascript" src="file_drawWindow_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.addEventListener("load", openSourceWindow, false);
|
||||
|
||||
var sourceWindow;
|
||||
|
||||
function openSourceWindow(event) {
|
||||
if (event.target != document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to open as a toplevel chrome window so that
|
||||
// DRAWWINDOW_USE_WIDGET_LAYERS is honored.
|
||||
sourceWindow = window.open("file_drawWindow_source.html", "",
|
||||
"chrome,width=200,height=100");
|
||||
sourceWindow.addEventListener("load", runTests, false);
|
||||
}
|
||||
|
||||
function runTests(event) {
|
||||
if (event.target != sourceWindow.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cxInterfaceWrap = SpecialPowers.wrap(CanvasRenderingContext2D);
|
||||
var flags = cxInterfaceWrap.DRAWWINDOW_USE_WIDGET_LAYERS |
|
||||
cxInterfaceWrap.DRAWWINDOW_DRAW_CARET |
|
||||
cxInterfaceWrap.DRAWWINDOW_DRAW_VIEW;
|
||||
runDrawWindowTests(sourceWindow, flags, true);
|
||||
|
||||
sourceWindow.close();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
|
||||
</body>
|
||||
</html>
|
157
content/canvas/test/file_drawWindow_common.js
Normal file
157
content/canvas/test/file_drawWindow_common.js
Normal file
@ -0,0 +1,157 @@
|
||||
function runDrawWindowTests(win, drawWindowFlags, transparentBackground) {
|
||||
const CANVAS_WIDTH = 200;
|
||||
const CANVAS_HEIGHT = 100;
|
||||
|
||||
function make_canvas() {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.setAttribute("height", CANVAS_HEIGHT);
|
||||
canvas.setAttribute("width", CANVAS_WIDTH);
|
||||
document.body.appendChild(canvas);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
var testCanvas = make_canvas();
|
||||
var refCanvas = make_canvas();
|
||||
|
||||
var testCx = testCanvas.getContext("2d");
|
||||
var refCx = refCanvas.getContext("2d");
|
||||
|
||||
var testWrapCx = SpecialPowers.wrap(testCx);
|
||||
var refWrapCx = SpecialPowers.wrap(refCx);
|
||||
|
||||
function clearRef(fillStyle) {
|
||||
refCx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
refCx.fillStyle = fillStyle;
|
||||
refCx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
||||
}
|
||||
function clearTest(fillStyle) {
|
||||
testCx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
testCx.fillStyle = fillStyle;
|
||||
testCx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
||||
}
|
||||
function clear(fillStyle) {
|
||||
clearRef(fillStyle);
|
||||
clearTest(fillStyle);
|
||||
}
|
||||
|
||||
// Basic tests of drawing the whole document on a background
|
||||
|
||||
clear("white");
|
||||
testWrapCx.drawWindow(win, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||
"rgb(255, 255, 255)", drawWindowFlags);
|
||||
refCx.fillStyle = "fuchsia";
|
||||
refCx.fillRect(10, 10, 20, 20);
|
||||
refCx.fillStyle = "aqua";
|
||||
refCx.fillRect(50, 10, 20, 20);
|
||||
refCx.fillStyle = "yellow";
|
||||
refCx.fillRect(90, 10, 20, 20);
|
||||
assertSnapshots(testCanvas, refCanvas, true /* equal */,
|
||||
"full draw of source on white background", "reference");
|
||||
|
||||
clearTest("white");
|
||||
testWrapCx.drawWindow(win, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||
"rgb(255, 255, 0)", drawWindowFlags);
|
||||
assertSnapshots(testCanvas, refCanvas,
|
||||
!transparentBackground /* not equal */,
|
||||
"full draw of source on yellow background", "reference");
|
||||
|
||||
clearRef("yellow");
|
||||
refCx.fillStyle = "fuchsia";
|
||||
refCx.fillRect(10, 10, 20, 20);
|
||||
refCx.fillStyle = "aqua";
|
||||
refCx.fillRect(50, 10, 20, 20);
|
||||
refCx.fillStyle = "yellow";
|
||||
refCx.fillRect(90, 10, 20, 20);
|
||||
|
||||
assertSnapshots(testCanvas, refCanvas, transparentBackground /* equal */,
|
||||
"full draw of source on yellow background", "reference");
|
||||
|
||||
// Test drawing a region within the document.
|
||||
|
||||
clear("white");
|
||||
|
||||
testCx.translate(17, 31);
|
||||
testWrapCx.drawWindow(win, 40, 0, 40, 40,
|
||||
"white", drawWindowFlags);
|
||||
|
||||
refCx.fillStyle = "aqua";
|
||||
refCx.fillRect(17 + 10, 31 + 10, 20, 20);
|
||||
|
||||
assertSnapshots(testCanvas, refCanvas, true /* equal */,
|
||||
"draw of subrect of source with matching background",
|
||||
"reference");
|
||||
|
||||
clear("blue");
|
||||
|
||||
testCx.translate(17, 31);
|
||||
testWrapCx.drawWindow(win, 40, 0, 35, 45,
|
||||
"green", drawWindowFlags);
|
||||
|
||||
if (transparentBackground) {
|
||||
refCx.fillStyle = "green";
|
||||
} else {
|
||||
refCx.fillStyle = "white";
|
||||
}
|
||||
refCx.fillRect(17, 31, 35, 45);
|
||||
refCx.fillStyle = "aqua";
|
||||
refCx.fillRect(17 + 10, 31 + 10, 20, 20);
|
||||
|
||||
assertSnapshots(testCanvas, refCanvas, true /* equal */,
|
||||
"draw of subrect of source with different background",
|
||||
"reference");
|
||||
|
||||
// Test transparency of background not disturbing what is behind
|
||||
clear("blue");
|
||||
|
||||
testCx.translate(17, 31);
|
||||
testWrapCx.drawWindow(win, 40, 0, 35, 45,
|
||||
"transparent", drawWindowFlags);
|
||||
|
||||
if (!transparentBackground) {
|
||||
refCx.fillStyle = "white";
|
||||
refCx.fillRect(17, 31, 35, 45);
|
||||
}
|
||||
refCx.fillStyle = "aqua";
|
||||
refCx.fillRect(17 + 10, 31 + 10, 20, 20);
|
||||
|
||||
assertSnapshots(testCanvas, refCanvas, true /* equal */,
|
||||
"draw of subrect of source with different background",
|
||||
"reference");
|
||||
|
||||
// Test that multiple drawWindow calls draw at correct positions.
|
||||
clear("blue");
|
||||
|
||||
testCx.translate(9, 3);
|
||||
// 5, 8 is 5, 2 from the corner of the fuchsia square
|
||||
testWrapCx.drawWindow(win, 5, 8, 30, 25,
|
||||
"maroon", drawWindowFlags);
|
||||
// 35, 0 is 15, 10 from the corner of the aqua square
|
||||
testWrapCx.drawWindow(win, 35, 0, 50, 40,
|
||||
"transparent", drawWindowFlags);
|
||||
testCx.translate(15, 0);
|
||||
// 85, 5 is 5, 5 from the corner of the yellow square
|
||||
testWrapCx.drawWindow(win, 85, 5, 30, 25,
|
||||
"transparent", drawWindowFlags);
|
||||
|
||||
if (transparentBackground) {
|
||||
refCx.fillStyle = "maroon";
|
||||
refCx.fillRect(9, 3, 30, 25);
|
||||
refCx.fillStyle = "fuchsia";
|
||||
refCx.fillRect(9 + 5, 3 + 2, 20, 20);
|
||||
} else {
|
||||
refCx.fillStyle = "white";
|
||||
refCx.fillRect(9, 3, 50, 40);
|
||||
}
|
||||
refCx.fillStyle = "aqua";
|
||||
refCx.fillRect(9 + 15, 3 + 10, 20, 20);
|
||||
if (!transparentBackground) {
|
||||
refCx.fillStyle = "white";
|
||||
refCx.fillRect(9 + 15, 3, 30, 25);
|
||||
}
|
||||
refCx.fillStyle = "yellow";
|
||||
refCx.fillRect(9 + 15 + 5, 3 + 0 + 5, 20, 20);
|
||||
|
||||
assertSnapshots(testCanvas, refCanvas, true /* equal */,
|
||||
"multiple drawWindow calls on top of each other",
|
||||
"reference");
|
||||
}
|
10
content/canvas/test/file_drawWindow_source.html
Normal file
10
content/canvas/test/file_drawWindow_source.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<style>
|
||||
|
||||
html, body { margin: 0; padding: 0 }
|
||||
div { display: inline-block; margin: 10px; width: 20px; height: 20px }
|
||||
|
||||
</style
|
||||
><div style="background: fuchsia"></div
|
||||
><div style="background: aqua"></div
|
||||
><div style="background: yellow"></div>
|
@ -199,6 +199,9 @@ skip-if = os == "android" || appname == "b2g"
|
||||
[test_drawImageIncomplete.html]
|
||||
[test_drawImage_document_domain.html]
|
||||
[test_drawImage_edge_cases.html]
|
||||
[test_drawWindow.html]
|
||||
support-files = file_drawWindow_source.html file_drawWindow_common.js
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
|
||||
[test_ImageData_ctor.html]
|
||||
[test_isPointInStroke.html]
|
||||
[test_mozDashOffset.html]
|
||||
|
@ -33,7 +33,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -65,7 +65,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -60,7 +60,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -44,7 +44,7 @@ function runTest() {
|
||||
else
|
||||
renderBackup(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -42,7 +42,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -41,7 +41,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -41,7 +41,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
rAF(testComplete);
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -42,7 +42,7 @@ function runTest() {
|
||||
else
|
||||
renderFailure(canvas);
|
||||
|
||||
testComplete();
|
||||
waitForComposite(testComplete);
|
||||
}
|
||||
|
||||
function testComplete() {
|
||||
|
@ -66,3 +66,18 @@ function rAF(func) {
|
||||
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame;
|
||||
raf(func);
|
||||
}
|
||||
|
||||
var MAX_WAIT_FOR_COMPOSITE_DELAY_MS = 500;
|
||||
|
||||
function waitForComposite(func) {
|
||||
var isDone = false;
|
||||
var doneFunc = function () {
|
||||
if (isDone)
|
||||
return;
|
||||
isDone = true;
|
||||
func();
|
||||
};
|
||||
|
||||
rAF(doneFunc);
|
||||
setTimeout(doneFunc, MAX_WAIT_FOR_COMPOSITE_DELAY_MS);
|
||||
}
|
||||
|
55
content/canvas/test/test_drawWindow.html
Normal file
55
content/canvas/test/test_drawWindow.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for canvas drawWindow</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<script type="application/javascript" src="file_drawWindow_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.addEventListener("load", openSourceWindow, false);
|
||||
|
||||
var sourceWindow;
|
||||
|
||||
function openSourceWindow(event) {
|
||||
if (event.target != document) {
|
||||
return;
|
||||
}
|
||||
|
||||
sourceWindow = window.open("file_drawWindow_source.html", "",
|
||||
"width=200,height=100");
|
||||
sourceWindow.addEventListener("load", runTests, false);
|
||||
}
|
||||
|
||||
function runTests(event) {
|
||||
if (event.target != sourceWindow.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the tests with the source document in an <iframe> within this
|
||||
// page, which we expect to have transparency.
|
||||
runDrawWindowTests(document.getElementById("source").contentWindow,
|
||||
0, true);
|
||||
|
||||
// Run the tests on the same source document, but in a window opened
|
||||
// by window.open. We do not expect this to have transparency...
|
||||
// except on B2G. (This is *probably* a bug in B2G.)
|
||||
var isB2G = /Mobile|Tablet/.test(navigator.userAgent) &&
|
||||
!navigator.userAgent.contains("Android");
|
||||
runDrawWindowTests(sourceWindow, 0, isB2G);
|
||||
|
||||
sourceWindow.close();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
|
||||
<iframe id="source" src="file_drawWindow_source.html" width="200" height="100"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -1252,7 +1252,7 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
||||
// Note that any script that's directly trying to access our value
|
||||
// has to be going through some scriptable object to do that and that
|
||||
// already does the relevant security checks.
|
||||
AutoSystemCaller asc;
|
||||
AutoNoJSAPI nojsapi;
|
||||
|
||||
rv = newEditor->Init(domdoc, GetRootNode(), mSelCon, editorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -1740,8 +1740,8 @@ nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
|
||||
// XXXbz if we could just get the textContent of our anonymous content (eg
|
||||
// if plaintext editor didn't create <br> nodes all over), we wouldn't need
|
||||
// this.
|
||||
{ /* Scope for AutoSystemCaller. */
|
||||
AutoSystemCaller asc;
|
||||
{ /* Scope for AutoNoJSAPI. */
|
||||
AutoNoJSAPI nojsapi;
|
||||
|
||||
mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags,
|
||||
aValue);
|
||||
@ -1820,7 +1820,7 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
|
||||
// for why this is needed. Note that we have to do this up here, because
|
||||
// otherwise SelectAll() will fail.
|
||||
{
|
||||
AutoSystemCaller asc;
|
||||
AutoNoJSAPI nojsapi;
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv;
|
||||
|
@ -18,8 +18,16 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef LOG
|
||||
#undef LOG
|
||||
#endif
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gAudioStreamLog = nullptr;
|
||||
// For simple logs
|
||||
#define LOG(x) PR_LOG(gAudioStreamLog, PR_LOG_DEBUG, x)
|
||||
#else
|
||||
#define LOG(x)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -149,6 +157,7 @@ AudioStream::AudioStream()
|
||||
, mVolume(1.0)
|
||||
, mBytesPerFrame(0)
|
||||
, mState(INITIALIZED)
|
||||
, mNeedsStart(false)
|
||||
{
|
||||
// keep a ref in case we shut down later than nsLayoutStatics
|
||||
mLatencyLog = AsyncLatencyLogger::Get(true);
|
||||
@ -156,6 +165,7 @@ AudioStream::AudioStream()
|
||||
|
||||
AudioStream::~AudioStream()
|
||||
{
|
||||
LOG(("AudioStream: delete %p, state %d", this, mState));
|
||||
Shutdown();
|
||||
if (mDumpFile) {
|
||||
fclose(mDumpFile);
|
||||
@ -347,19 +357,19 @@ WriteDumpFile(FILE* aDumpFile, AudioStream* aStream, uint32_t aFrames,
|
||||
fflush(aDumpFile);
|
||||
}
|
||||
|
||||
// NOTE: this must not block a LowLatency stream for any significant amount
|
||||
// of time, or it will block the entirety of MSG
|
||||
nsresult
|
||||
AudioStream::Init(int32_t aNumChannels, int32_t aRate,
|
||||
const dom::AudioChannel aAudioChannel,
|
||||
LatencyRequest aLatencyRequest)
|
||||
{
|
||||
cubeb* cubebContext = GetCubebContext();
|
||||
|
||||
if (!cubebContext || aNumChannels < 0 || aRate < 0) {
|
||||
if (!GetCubebContext() || aNumChannels < 0 || aRate < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_DEBUG,
|
||||
("%s channels: %d, rate: %d", __FUNCTION__, aNumChannels, aRate));
|
||||
("%s channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
|
||||
mInRate = mOutRate = aRate;
|
||||
mChannels = aNumChannels;
|
||||
mOutChannels = (aNumChannels > 2) ? 2 : aNumChannels;
|
||||
@ -390,12 +400,49 @@ AudioStream::Init(int32_t aNumChannels, int32_t aRate,
|
||||
|
||||
mAudioClock.Init();
|
||||
|
||||
// Size mBuffer for one second of audio. This value is arbitrary, and was
|
||||
// selected based on the observed behaviour of the existing AudioStream
|
||||
// implementations.
|
||||
uint32_t bufferLimit = FramesToBytes(aRate);
|
||||
NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
|
||||
mBuffer.SetCapacity(bufferLimit);
|
||||
|
||||
if (aLatencyRequest == LowLatency) {
|
||||
// Don't block this thread to initialize a cubeb stream.
|
||||
// When this is done, it will start callbacks from Cubeb. Those will
|
||||
// cause us to move from INITIALIZED to RUNNING. Until then, we
|
||||
// can't access any cubeb functions.
|
||||
AudioInitTask *init = new AudioInitTask(this, aLatencyRequest, params);
|
||||
init->Dispatch();
|
||||
return NS_OK;
|
||||
}
|
||||
// High latency - open synchronously
|
||||
nsresult rv = OpenCubeb(params, aLatencyRequest);
|
||||
// See if we need to start() the stream, since we must do that from this
|
||||
// thread for now (cubeb API issue)
|
||||
CheckForStart();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// This code used to live inside AudioStream::Init(), but on Mac (others?)
|
||||
// it has been known to take 300-800 (or even 8500) ms to execute(!)
|
||||
nsresult
|
||||
AudioStream::OpenCubeb(cubeb_stream_params &aParams,
|
||||
LatencyRequest aLatencyRequest)
|
||||
{
|
||||
cubeb* cubebContext = GetCubebContext();
|
||||
if (!cubebContext) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mState = AudioStream::ERRORED;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the latency pref is set, use it. Otherwise, if this stream is intended
|
||||
// for low latency playback, try to get the lowest latency possible.
|
||||
// Otherwise, for normal streams, use 100ms.
|
||||
uint32_t latency;
|
||||
if (aLatencyRequest == LowLatency && !CubebLatencyPrefSet()) {
|
||||
if (cubeb_get_min_latency(cubebContext, params, &latency) != CUBEB_OK) {
|
||||
if (cubeb_get_min_latency(cubebContext, aParams, &latency) != CUBEB_OK) {
|
||||
latency = GetCubebLatency();
|
||||
}
|
||||
} else {
|
||||
@ -404,42 +451,67 @@ AudioStream::Init(int32_t aNumChannels, int32_t aRate,
|
||||
|
||||
{
|
||||
cubeb_stream* stream;
|
||||
if (cubeb_stream_init(cubebContext, &stream, "AudioStream", params,
|
||||
if (cubeb_stream_init(cubebContext, &stream, "AudioStream", aParams,
|
||||
latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mCubebStream.own(stream);
|
||||
// Make sure we weren't shut down while in flight!
|
||||
if (mState == SHUTDOWN) {
|
||||
mCubebStream.reset();
|
||||
LOG(("AudioStream::OpenCubeb() %p Shutdown while opening cubeb", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We can't cubeb_stream_start() the thread from a transient thread due to
|
||||
// cubeb API requirements (init can be called from another thread, but
|
||||
// not start/stop/destroy/etc)
|
||||
} else {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mState = ERRORED;
|
||||
LOG(("AudioStream::OpenCubeb() %p failed to init cubeb", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mCubebStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Size mBuffer for one second of audio. This value is arbitrary, and was
|
||||
// selected based on the observed behaviour of the existing AudioStream
|
||||
// implementations.
|
||||
uint32_t bufferLimit = FramesToBytes(aRate);
|
||||
NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
|
||||
mBuffer.SetCapacity(bufferLimit);
|
||||
|
||||
// Start the stream right away when low latency has been requested. This means
|
||||
// that the DataCallback will feed silence to cubeb, until the first frames
|
||||
// are writtent to this AudioStream.
|
||||
if (mLatencyRequest == LowLatency) {
|
||||
Start();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AudioStream::Shutdown()
|
||||
AudioStream::CheckForStart()
|
||||
{
|
||||
if (mState == STARTED) {
|
||||
Pause();
|
||||
if (mState == INITIALIZED) {
|
||||
// Start the stream right away when low latency has been requested. This means
|
||||
// that the DataCallback will feed silence to cubeb, until the first frames
|
||||
// are written to this AudioStream. Also start if a start has been queued.
|
||||
if (mLatencyRequest == LowLatency || mNeedsStart) {
|
||||
StartUnlocked(); // mState = STARTED or ERRORED
|
||||
mNeedsStart = false;
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING,
|
||||
("Started waiting %s-latency stream",
|
||||
mLatencyRequest == LowLatency ? "low" : "high"));
|
||||
} else {
|
||||
// high latency, not full - OR Pause() was called before we got here
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_DEBUG,
|
||||
("Not starting waiting %s-latency stream",
|
||||
mLatencyRequest == LowLatency ? "low" : "high"));
|
||||
}
|
||||
}
|
||||
if (mCubebStream) {
|
||||
mCubebStream.reset();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioInitTask::Run()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
mThread->Shutdown(); // can't Shutdown from the thread itself, darn
|
||||
mThread = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = mAudioStream->OpenCubeb(mParams, mLatencyRequest);
|
||||
|
||||
// and now kill this thread
|
||||
NS_DispatchToMainThread(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// aTime is the time in ms the samples were inserted into MediaStreamGraph
|
||||
@ -447,12 +519,15 @@ nsresult
|
||||
AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (!mCubebStream || mState == ERRORED) {
|
||||
if (mState == ERRORED) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NS_ASSERTION(mState == INITIALIZED || mState == STARTED,
|
||||
NS_ASSERTION(mState == INITIALIZED || mState == STARTED || mState == RUNNING,
|
||||
"Stream write in unexpected state.");
|
||||
|
||||
// See if we need to start() the stream, since we must do that from this thread
|
||||
CheckForStart();
|
||||
|
||||
// Downmix to Stereo.
|
||||
if (mChannels > 2 && mChannels <= 8) {
|
||||
DownmixAudioToStereo(const_cast<AudioDataValue*> (aBuf), mChannels, aFrames);
|
||||
@ -490,15 +565,33 @@ AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTim
|
||||
bytesToCopy -= available;
|
||||
|
||||
if (bytesToCopy > 0) {
|
||||
// If we are not playing, but our buffer is full, start playing to make
|
||||
// room for soon-to-be-decoded data.
|
||||
if (mState != STARTED) {
|
||||
StartUnlocked();
|
||||
if (mState != STARTED) {
|
||||
return NS_ERROR_FAILURE;
|
||||
// Careful - the CubebInit thread may not have gotten to STARTED yet
|
||||
if ((mState == INITIALIZED || mState == STARTED) && mLatencyRequest == LowLatency) {
|
||||
// don't ever block MediaStreamGraph low-latency streams
|
||||
uint32_t remains = 0; // we presume the buffer is full
|
||||
if (mBuffer.Length() > bytesToCopy) {
|
||||
remains = mBuffer.Length() - bytesToCopy; // Free up just enough space
|
||||
}
|
||||
// account for dropping samples
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING, ("Stream %p dropping %u bytes (%u frames)in Write()",
|
||||
this, mBuffer.Length() - remains, BytesToFrames(mBuffer.Length() - remains)));
|
||||
mReadPoint += BytesToFrames(mBuffer.Length() - remains);
|
||||
mBuffer.ContractTo(remains);
|
||||
} else { // RUNNING or high latency
|
||||
// If we are not playing, but our buffer is full, start playing to make
|
||||
// room for soon-to-be-decoded data.
|
||||
if (mState != STARTED && mState != RUNNING) {
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING, ("Starting stream %p in Write (%u waiting)",
|
||||
this, bytesToCopy));
|
||||
StartUnlocked();
|
||||
if (mState == ERRORED) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING, ("Stream %p waiting in Write() (%u waiting)",
|
||||
this, bytesToCopy));
|
||||
mon.Wait();
|
||||
}
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,8 +619,9 @@ void
|
||||
AudioStream::Drain()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mState != STARTED) {
|
||||
NS_ASSERTION(mBuffer.Available() == 0, "Draining with unplayed audio");
|
||||
LOG(("AudioStream::Drain() for %p, state %d, avail %u", this, mState, mBuffer.Available()));
|
||||
if (mState != STARTED && mState != RUNNING) {
|
||||
NS_ASSERTION(mState == ERRORED || mBuffer.Available() == 0, "Draining without full buffer of unplayed audio");
|
||||
return;
|
||||
}
|
||||
mState = DRAINING;
|
||||
@ -547,18 +641,15 @@ void
|
||||
AudioStream::StartUnlocked()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
if (!mCubebStream || mState != INITIALIZED) {
|
||||
if (!mCubebStream) {
|
||||
mNeedsStart = true;
|
||||
return;
|
||||
}
|
||||
if (mState != STARTED) {
|
||||
int r;
|
||||
{
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
r = cubeb_stream_start(mCubebStream);
|
||||
}
|
||||
if (mState != ERRORED) {
|
||||
mState = r == CUBEB_OK ? STARTED : ERRORED;
|
||||
}
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
if (mState == INITIALIZED) {
|
||||
int r = cubeb_stream_start(mCubebStream);
|
||||
mState = r == CUBEB_OK ? STARTED : ERRORED;
|
||||
LOG(("AudioStream: started %p, state %s", this, mState == STARTED ? "STARTED" : "ERRORED"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -566,7 +657,9 @@ void
|
||||
AudioStream::Pause()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (!mCubebStream || mState != STARTED) {
|
||||
if (!mCubebStream || (mState != STARTED && mState != RUNNING)) {
|
||||
mNeedsStart = false;
|
||||
mState = STOPPED; // which also tells async OpenCubeb not to start, just init
|
||||
return;
|
||||
}
|
||||
|
||||
@ -598,6 +691,26 @@ AudioStream::Resume()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioStream::Shutdown()
|
||||
{
|
||||
LOG(("AudioStream: Shutdown %p, state %d", this, mState));
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mState == STARTED || mState == RUNNING) {
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
Pause();
|
||||
}
|
||||
MOZ_ASSERT(mState != STARTED && mState != RUNNING); // paranoia
|
||||
mState = SHUTDOWN;
|
||||
}
|
||||
// Must not try to shut down cubeb from within the lock! wasapi may still
|
||||
// call our callback after Pause()/stop()!?! Bug 996162
|
||||
if (mCubebStream) {
|
||||
mCubebStream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
AudioStream::GetPosition()
|
||||
{
|
||||
@ -792,6 +905,42 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
|
||||
uint32_t servicedFrames = 0;
|
||||
int64_t insertTime;
|
||||
|
||||
// NOTE: wasapi (others?) can call us back *after* stop()/Shutdown() (mState == SHUTDOWN)
|
||||
// Bug 996162
|
||||
|
||||
// callback tells us cubeb succeeded initializing
|
||||
if (mState == STARTED) {
|
||||
// For low-latency streams, we want to minimize any built-up data when
|
||||
// we start getting callbacks.
|
||||
// Simple version - contract on first callback only.
|
||||
if (mLatencyRequest == LowLatency) {
|
||||
#ifdef PR_LOGGING
|
||||
uint32_t old_len = mBuffer.Length();
|
||||
#endif
|
||||
available = mBuffer.ContractTo(FramesToBytes(aFrames));
|
||||
#ifdef PR_LOGGING
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
if (!mStartTime.IsNull()) {
|
||||
int64_t timeMs = (now - mStartTime).ToMilliseconds();
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING,
|
||||
("Stream took %lldms to start after first Write() @ %u", timeMs, mOutRate));
|
||||
} else {
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING,
|
||||
("Stream started before Write() @ %u", mOutRate));
|
||||
}
|
||||
|
||||
if (old_len != available) {
|
||||
// Note that we may have dropped samples in Write() as well!
|
||||
PR_LOG(gAudioStreamLog, PR_LOG_WARNING,
|
||||
("AudioStream %p dropped %u + %u initial frames @ %u", this,
|
||||
mReadPoint, BytesToFrames(old_len - available), mOutRate));
|
||||
mReadPoint += BytesToFrames(old_len - available);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
mState = RUNNING;
|
||||
}
|
||||
|
||||
if (available) {
|
||||
// When we are playing a low latency stream, and it is the first time we are
|
||||
// getting data from the buffer, we prefer to add the silence for an
|
||||
@ -834,6 +983,7 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
|
||||
WriteDumpFile(mDumpFile, this, aFrames, aBuffer);
|
||||
// Don't log if we're not interested or if the stream is inactive
|
||||
if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG) &&
|
||||
mState != SHUTDOWN &&
|
||||
insertTime != INT64_MAX && servicedFrames > underrunFrames) {
|
||||
uint32_t latency = UINT32_MAX;
|
||||
if (cubeb_stream_get_latency(mCubebStream, &latency)) {
|
||||
@ -858,6 +1008,7 @@ AudioStream::StateCallback(cubeb_state aState)
|
||||
if (aState == CUBEB_STATE_DRAINED) {
|
||||
mState = DRAINED;
|
||||
} else if (aState == CUBEB_STATE_ERROR) {
|
||||
LOG(("AudioStream::StateCallback() state %d cubeb error", mState));
|
||||
mState = ERRORED;
|
||||
}
|
||||
mon.NotifyAll();
|
||||
|
@ -10,9 +10,11 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "Latency.h"
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "cubeb/cubeb.h"
|
||||
|
||||
@ -154,6 +156,19 @@ public:
|
||||
mStart %= mCapacity;
|
||||
}
|
||||
|
||||
// Throw away all but aSize bytes from the buffer. Returns new size, which
|
||||
// may be less than aSize
|
||||
uint32_t ContractTo(uint32_t aSize) {
|
||||
NS_ABORT_IF_FALSE(mBuffer && mCapacity, "Buffer not initialized.");
|
||||
if (aSize >= mCount) {
|
||||
return mCount;
|
||||
}
|
||||
mStart += (mCount - aSize);
|
||||
mCount = aSize;
|
||||
mStart %= mCapacity;
|
||||
return mCount;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoArrayPtr<uint8_t> mBuffer;
|
||||
uint32_t mCapacity;
|
||||
@ -161,6 +176,8 @@ private:
|
||||
uint32_t mCount;
|
||||
};
|
||||
|
||||
class AudioInitTask;
|
||||
|
||||
// Access to a single instance of this class must be synchronized by
|
||||
// callers, or made from a single thread. One exception is that access to
|
||||
// GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels}
|
||||
@ -186,8 +203,9 @@ public:
|
||||
// Get the aformentionned sample rate. Does not lock.
|
||||
static int PreferredSampleRate();
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioStream)
|
||||
AudioStream();
|
||||
~AudioStream();
|
||||
virtual ~AudioStream();
|
||||
|
||||
enum LatencyRequest {
|
||||
HighLatency,
|
||||
@ -263,6 +281,14 @@ public:
|
||||
nsresult SetPreservesPitch(bool aPreservesPitch);
|
||||
|
||||
private:
|
||||
friend class AudioInitTask;
|
||||
|
||||
// So we can call it asynchronously from AudioInitTask
|
||||
nsresult OpenCubeb(cubeb_stream_params &aParams,
|
||||
LatencyRequest aLatencyRequest);
|
||||
|
||||
void CheckForStart();
|
||||
|
||||
static void PrefChanged(const char* aPref, void* aClosure);
|
||||
static double GetVolumeScale();
|
||||
static cubeb* GetCubebContext();
|
||||
@ -366,17 +392,20 @@ private:
|
||||
|
||||
enum StreamState {
|
||||
INITIALIZED, // Initialized, playback has not begun.
|
||||
STARTED, // Started by a call to Write() (iff INITIALIZED) or Resume().
|
||||
STARTED, // cubeb started, but callbacks haven't started
|
||||
RUNNING, // DataCallbacks have started after STARTED, or after Resume().
|
||||
STOPPED, // Stopped by a call to Pause().
|
||||
DRAINING, // Drain requested. DataCallback will indicate end of stream
|
||||
// once the remaining contents of mBuffer are requested by
|
||||
// cubeb, after which StateCallback will indicate drain
|
||||
// completion.
|
||||
DRAINED, // StateCallback has indicated that the drain is complete.
|
||||
ERRORED // Stream disabled due to an internal error.
|
||||
ERRORED, // Stream disabled due to an internal error.
|
||||
SHUTDOWN // Shutdown has been called
|
||||
};
|
||||
|
||||
StreamState mState;
|
||||
bool mNeedsStart; // needed in case Start() is called before cubeb is open
|
||||
|
||||
// This mutex protects the static members below.
|
||||
static StaticMutex sMutex;
|
||||
@ -391,6 +420,35 @@ private:
|
||||
static bool sCubebLatencyPrefSet;
|
||||
};
|
||||
|
||||
class AudioInitTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AudioInitTask(AudioStream *aStream,
|
||||
AudioStream::LatencyRequest aLatencyRequest,
|
||||
const cubeb_stream_params &aParams)
|
||||
: mAudioStream(aStream)
|
||||
, mLatencyRequest(aLatencyRequest)
|
||||
, mParams(aParams)
|
||||
{}
|
||||
|
||||
nsresult Dispatch()
|
||||
{
|
||||
return NS_NewNamedThread("CubebInit", getter_AddRefs(mThread), this);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~AudioInitTask() {};
|
||||
|
||||
private:
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL;
|
||||
|
||||
RefPtr<AudioStream> mAudioStream;
|
||||
AudioStream::LatencyRequest mLatencyRequest;
|
||||
cubeb_stream_params mParams;
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -783,7 +783,7 @@ void MediaDecoderStateMachine::AudioLoop()
|
||||
// AudioStream initialization can block for extended periods in unusual
|
||||
// circumstances, so we take care to drop the decoder monitor while
|
||||
// initializing.
|
||||
nsAutoPtr<AudioStream> audioStream(new AudioStream());
|
||||
RefPtr<AudioStream> audioStream(new AudioStream());
|
||||
audioStream->Init(channels, rate, audioChannel, AudioStream::HighLatency);
|
||||
audioStream->SetVolume(volume);
|
||||
if (audioStream->SetPreservesPitch(preservesPitch) != NS_OK) {
|
||||
@ -799,7 +799,7 @@ void MediaDecoderStateMachine::AudioLoop()
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mAudioStream = audioStream;
|
||||
mAudioStream = audioStream.forget();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1556,6 +1556,7 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
||||
(!needToDecodeAudio && !needToDecodeVideo));
|
||||
|
||||
bool needIdle = !mDecoder->IsLogicallyPlaying() &&
|
||||
mState != DECODER_STATE_SEEKING &&
|
||||
!needToDecodeAudio &&
|
||||
!needToDecodeVideo &&
|
||||
!IsPlaying();
|
||||
|
@ -731,7 +731,7 @@ private:
|
||||
// This is created and destroyed on the audio thread, while holding the
|
||||
// decoder monitor, so if this is used off the audio thread, you must
|
||||
// first acquire the decoder monitor and check that it is non-null.
|
||||
nsAutoPtr<AudioStream> mAudioStream;
|
||||
RefPtr<AudioStream> mAudioStream;
|
||||
|
||||
// The reader, don't call its methods with the decoder monitor held.
|
||||
// This is created in the play state machine's constructor, and destroyed
|
||||
|
@ -831,9 +831,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTim
|
||||
continue;
|
||||
}
|
||||
|
||||
// XXX allocating a AudioStream could be slow so we're going to have to do
|
||||
// something here ... preallocation, async allocation, multiplexing onto a single
|
||||
// stream ...
|
||||
// Allocating a AudioStream would be slow, so we finish the Init async
|
||||
MediaStream::AudioOutputStream* audioOutputStream =
|
||||
aStream->mAudioOutputStreams.AppendElement();
|
||||
audioOutputStream->mAudioPlaybackStartTime = aAudioOutputStartTime;
|
||||
@ -842,6 +840,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTim
|
||||
audioOutputStream->mStream = new AudioStream();
|
||||
// XXX for now, allocate stereo output. But we need to fix this to
|
||||
// match the system's ideal channel configuration.
|
||||
// NOTE: we presume this is either fast or async-under-the-covers
|
||||
audioOutputStream->mStream->Init(2, IdealAudioRate(),
|
||||
AudioChannel::Normal,
|
||||
AudioStream::LowLatency);
|
||||
|
@ -575,7 +575,7 @@ protected:
|
||||
MediaTime mBlockedAudioTime;
|
||||
// Last tick written to the audio output.
|
||||
TrackTicks mLastTickWritten;
|
||||
nsAutoPtr<AudioStream> mStream;
|
||||
RefPtr<AudioStream> mStream;
|
||||
TrackID mTrackID;
|
||||
};
|
||||
nsTArray<AudioOutputStream> mAudioOutputStreams;
|
||||
|
@ -40,13 +40,16 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define DECODER_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder) :
|
||||
MediaDecoderReader(aDecoder),
|
||||
mHasVideo(false),
|
||||
mHasAudio(false),
|
||||
mVideoSeekTimeUs(-1),
|
||||
mAudioSeekTimeUs(-1),
|
||||
mSkipCount(0)
|
||||
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
|
||||
: MediaDecoderReader(aDecoder)
|
||||
, mHasVideo(false)
|
||||
, mHasAudio(false)
|
||||
, mVideoSeekTimeUs(-1)
|
||||
, mAudioSeekTimeUs(-1)
|
||||
, mSkipCount(0)
|
||||
#ifdef DEBUG
|
||||
, mIsActive(true)
|
||||
#endif
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gMediaDecoderLog) {
|
||||
@ -132,6 +135,7 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mIsActive);
|
||||
|
||||
*aTags = nullptr;
|
||||
|
||||
@ -207,6 +211,8 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold)
|
||||
{
|
||||
MOZ_ASSERT(mIsActive);
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
uint32_t parsed = 0, decoded = 0;
|
||||
@ -335,6 +341,7 @@ void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, in
|
||||
bool MediaOmxReader::DecodeAudioData()
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mIsActive);
|
||||
|
||||
// This is the approximate byte position in the stream.
|
||||
int64_t pos = mDecoder->GetResource()->Tell();
|
||||
@ -368,6 +375,7 @@ bool MediaOmxReader::DecodeAudioData()
|
||||
nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
|
||||
{
|
||||
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mIsActive);
|
||||
|
||||
ResetDecode();
|
||||
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
|
||||
@ -402,6 +410,9 @@ static uint64_t BytesToTime(int64_t offset, uint64_t length, uint64_t durationUs
|
||||
}
|
||||
|
||||
void MediaOmxReader::SetIdle() {
|
||||
#ifdef DEBUG
|
||||
mIsActive = false;
|
||||
#endif
|
||||
if (!mOmxDecoder.get()) {
|
||||
return;
|
||||
}
|
||||
@ -409,6 +420,9 @@ void MediaOmxReader::SetIdle() {
|
||||
}
|
||||
|
||||
void MediaOmxReader::SetActive() {
|
||||
#ifdef DEBUG
|
||||
mIsActive = true;
|
||||
#endif
|
||||
if (!mOmxDecoder.get()) {
|
||||
return;
|
||||
}
|
||||
|
@ -100,6 +100,11 @@ public:
|
||||
void CheckAudioOffload();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// This flag is true when SetActive() has been called without a matching
|
||||
// SetIdle(). This is used to sanity check the SetIdle/SetActive calls, to
|
||||
// ensure SetActive has been called before a decode call.
|
||||
DebugOnly<bool> mIsActive;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -2397,6 +2397,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
|
||||
nsXULPrototypeDocument* aProtoDoc,
|
||||
const nsCOMArray<nsINodeInfo> *aNodeInfos)
|
||||
{
|
||||
NS_ENSURE_TRUE(aProtoDoc, NS_ERROR_UNEXPECTED);
|
||||
AutoSafeJSContext cx;
|
||||
JS::Rooted<JSObject*> global(cx, aProtoDoc->GetCompilationGlobal());
|
||||
NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
|
||||
|
@ -23,7 +23,7 @@ namespace dom {
|
||||
class ScriptSettingsStack;
|
||||
static mozilla::ThreadLocal<ScriptSettingsStack*> sScriptSettingsTLS;
|
||||
|
||||
ScriptSettingsStackEntry ScriptSettingsStackEntry::SystemSingleton;
|
||||
ScriptSettingsStackEntry ScriptSettingsStackEntry::NoJSAPISingleton;
|
||||
|
||||
class ScriptSettingsStack {
|
||||
public:
|
||||
@ -34,13 +34,13 @@ public:
|
||||
|
||||
void Push(ScriptSettingsStackEntry* aSettings) {
|
||||
// The bottom-most entry must always be a candidate entry point.
|
||||
MOZ_ASSERT_IF(mStack.Length() == 0 || mStack.LastElement()->IsSystemSingleton(),
|
||||
MOZ_ASSERT_IF(mStack.Length() == 0 || mStack.LastElement()->NoJSAPI(),
|
||||
aSettings->mIsCandidateEntryPoint);
|
||||
mStack.AppendElement(aSettings);
|
||||
}
|
||||
|
||||
void PushSystem() {
|
||||
mStack.AppendElement(&ScriptSettingsStackEntry::SystemSingleton);
|
||||
void PushNoJSAPI() {
|
||||
mStack.AppendElement(&ScriptSettingsStackEntry::NoJSAPISingleton);
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
@ -158,9 +158,9 @@ GetWebIDLCallerPrincipal()
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ScriptSettingsStackEntry *entry = ScriptSettingsStack::Ref().EntryPoint();
|
||||
|
||||
// If we have an entry point that is not the system singleton, we know it
|
||||
// If we have an entry point that is not the NoJSAPI singleton, we know it
|
||||
// must be an AutoEntryScript.
|
||||
if (!entry || entry->IsSystemSingleton()) {
|
||||
if (!entry || entry->NoJSAPI()) {
|
||||
return nullptr;
|
||||
}
|
||||
AutoEntryScript* aes = static_cast<AutoEntryScript*>(entry);
|
||||
@ -184,7 +184,7 @@ GetWebIDLCallerPrincipal()
|
||||
// that we should return a non-null WebIDL Caller.
|
||||
//
|
||||
// Once we fix bug 951991, this can all be simplified.
|
||||
if (!aes->mCxPusher.ref().IsStackTop()) {
|
||||
if (!aes->CxPusherIsStackTop()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -206,28 +206,48 @@ FindJSContext(nsIGlobalObject* aGlobalObject)
|
||||
return cx;
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
, mStack(ScriptSettingsStack::Ref())
|
||||
, mCx(aCx)
|
||||
AutoJSAPI::AutoJSAPI()
|
||||
: mCx(nsContentUtils::GetDefaultJSContextForThread())
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT_IF(!mCx, aIsMainThread); // cx is mandatory off-main-thread.
|
||||
MOZ_ASSERT_IF(mCx && aIsMainThread, mCx == FindJSContext(aGlobalObject));
|
||||
if (!mCx) {
|
||||
// If the caller didn't provide a cx, hunt one down. This isn't exactly
|
||||
// fast, but the callers that care about performance can pass an explicit
|
||||
// cx for now. Eventually, the whole cx pushing thing will go away
|
||||
// entirely.
|
||||
mCx = FindJSContext(aGlobalObject);
|
||||
MOZ_ASSERT(mCx);
|
||||
if (NS_IsMainThread()) {
|
||||
mCxPusher.construct(mCx);
|
||||
}
|
||||
|
||||
// Leave the cx in a null compartment.
|
||||
mNullAc.construct(mCx);
|
||||
}
|
||||
|
||||
AutoJSAPI::AutoJSAPI(JSContext *aCx, bool aIsMainThread, bool aSkipNullAc)
|
||||
: mCx(aCx)
|
||||
{
|
||||
MOZ_ASSERT_IF(aIsMainThread, NS_IsMainThread());
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.construct(mCx);
|
||||
}
|
||||
mAc.construct(mCx, aGlobalObject->GetGlobalJSObject());
|
||||
|
||||
// In general we want to leave the cx in a null compartment, but we let
|
||||
// subclasses skip this if they plan to immediately enter a compartment.
|
||||
if (!aSkipNullAc) {
|
||||
mNullAc.construct(mCx);
|
||||
}
|
||||
}
|
||||
|
||||
AutoJSAPIWithErrorsReportedToWindow::AutoJSAPIWithErrorsReportedToWindow(nsIScriptContext* aScx)
|
||||
: AutoJSAPI(aScx->GetNativeContext(), /* aIsMainThread = */ true)
|
||||
{
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: AutoJSAPI(aCx ? aCx : FindJSContext(aGlobalObject), aIsMainThread, /* aSkipNullAc = */ true)
|
||||
, ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
, mAc(cx(), aGlobalObject->GetGlobalJSObject())
|
||||
, mStack(ScriptSettingsStack::Ref())
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
|
||||
MOZ_ASSERT_IF(aCx && aIsMainThread, aCx == FindJSContext(aGlobalObject));
|
||||
mStack.Push(this);
|
||||
}
|
||||
|
||||
@ -251,17 +271,19 @@ AutoIncumbentScript::~AutoIncumbentScript()
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoSystemCaller::AutoSystemCaller(bool aIsMainThread)
|
||||
AutoNoJSAPI::AutoNoJSAPI(bool aIsMainThread)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
{
|
||||
MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContextForThread(),
|
||||
!JS_IsExceptionPending(nsContentUtils::GetCurrentJSContextForThread()));
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.construct(static_cast<JSContext*>(nullptr),
|
||||
/* aAllowNull = */ true);
|
||||
}
|
||||
mStack.PushSystem();
|
||||
mStack.PushNoJSAPI();
|
||||
}
|
||||
|
||||
AutoSystemCaller::~AutoSystemCaller()
|
||||
AutoNoJSAPI::~AutoNoJSAPI()
|
||||
{
|
||||
mStack.Pop();
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ struct ScriptSettingsStackEntry {
|
||||
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
|
||||
}
|
||||
|
||||
bool IsSystemSingleton() { return this == &SystemSingleton; }
|
||||
static ScriptSettingsStackEntry SystemSingleton;
|
||||
bool NoJSAPI() { return this == &NoJSAPISingleton; }
|
||||
static ScriptSettingsStackEntry NoJSAPISingleton;
|
||||
|
||||
private:
|
||||
ScriptSettingsStackEntry() : mGlobalObject(nullptr)
|
||||
@ -95,10 +95,76 @@ private:
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* For any interaction with JSAPI, an AutoJSAPI (or one of its subclasses)
|
||||
* must be on the stack.
|
||||
*
|
||||
* This base class should be instantiated as-is when the caller wants to use
|
||||
* JSAPI but doesn't expect to run script. Its current duties are as-follows:
|
||||
*
|
||||
* * Grabbing an appropriate JSContext, and, on the main thread, pushing it onto
|
||||
* the JSContext stack.
|
||||
* * Entering a null compartment, so that the consumer is forced to select a
|
||||
* compartment to enter before manipulating objects.
|
||||
*
|
||||
* Additionally, the following duties are planned, but not yet implemented:
|
||||
*
|
||||
* * De-poisoning the JSRuntime to allow manipulation of JSAPI. We can't
|
||||
* actually implement this poisoning until all the JSContext pushing in the
|
||||
* system goes through AutoJSAPI (see bug 951991). For now, this de-poisoning
|
||||
* effectively corresponds to having a non-null cx on the stack.
|
||||
* * Reporting any exceptions left on the JSRuntime, unless the caller steals
|
||||
* or silences them.
|
||||
* * Entering a JSAutoRequest. At present, this is handled by the cx pushing
|
||||
* on the main thread, and by other code on workers. Depending on the order
|
||||
* in which various cleanup lands, this may never be necessary, because
|
||||
* JSAutoRequests may go away.
|
||||
*
|
||||
* In situations where the consumer expects to run script, AutoEntryScript
|
||||
* should be used, which does additional manipulation of the script settings
|
||||
* stack. In bug 991758, we'll add hard invariants to SpiderMonkey, such that
|
||||
* any attempt to run script without an AutoEntryScript on the stack will
|
||||
* fail. This prevents system code from accidentally triggering script
|
||||
* execution at inopportune moments via surreptitious getters and proxies.
|
||||
*/
|
||||
class AutoJSAPI {
|
||||
public:
|
||||
// Public constructor for use when the base class is constructed as-is. It
|
||||
// uses the SafeJSContext (or worker equivalent), and enters a null
|
||||
// compartment.
|
||||
AutoJSAPI();
|
||||
JSContext* cx() const { return mCx; }
|
||||
|
||||
bool CxPusherIsStackTop() { return mCxPusher.ref().IsStackTop(); }
|
||||
|
||||
protected:
|
||||
// Protected constructor, allowing subclasses to specify a particular cx to
|
||||
// be used.
|
||||
AutoJSAPI(JSContext *aCx, bool aIsMainThread, bool aSkipNullAC = false);
|
||||
|
||||
private:
|
||||
mozilla::Maybe<AutoCxPusher> mCxPusher;
|
||||
mozilla::Maybe<JSAutoNullCompartment> mNullAc;
|
||||
JSContext *mCx;
|
||||
};
|
||||
|
||||
// Note - the ideal way to implement this is with an accessor on AutoJSAPI
|
||||
// that lets us select the error reporting target. But at present,
|
||||
// implementing it that way would require us to destroy and reconstruct
|
||||
// mCxPusher, which is pretty wasteful. So we do this for now, since it should
|
||||
// be pretty easy to switch things over later.
|
||||
//
|
||||
// This should only be used on the main thread.
|
||||
class AutoJSAPIWithErrorsReportedToWindow : public AutoJSAPI {
|
||||
public:
|
||||
AutoJSAPIWithErrorsReportedToWindow(nsIScriptContext* aScx);
|
||||
};
|
||||
|
||||
/*
|
||||
* A class that represents a new script entry point.
|
||||
*/
|
||||
class AutoEntryScript : protected ScriptSettingsStackEntry {
|
||||
class AutoEntryScript : public AutoJSAPI,
|
||||
protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread = NS_IsMainThread(),
|
||||
@ -110,15 +176,10 @@ public:
|
||||
mWebIDLCallerPrincipal = aPrincipal;
|
||||
}
|
||||
|
||||
JSContext* cx() const { return mCx; }
|
||||
|
||||
private:
|
||||
JSAutoCompartment mAc;
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
nsCOMPtr<nsIPrincipal> mWebIDLCallerPrincipal;
|
||||
JSContext *mCx;
|
||||
mozilla::Maybe<AutoCxPusher> mCxPusher;
|
||||
mozilla::Maybe<JSAutoCompartment> mAc; // This can de-Maybe-fy when mCxPusher
|
||||
// goes away.
|
||||
friend nsIPrincipal* GetWebIDLCallerPrincipal();
|
||||
};
|
||||
|
||||
@ -135,14 +196,17 @@ private:
|
||||
};
|
||||
|
||||
/*
|
||||
* A class used for C++ to indicate that existing entry and incumbent scripts
|
||||
* should not apply to anything in scope, and that callees should act as if
|
||||
* they were invoked "from C++".
|
||||
* A class to put the JS engine in an unusable state. The subject principal
|
||||
* will become System, the information on the script settings stack is
|
||||
* rendered inaccessible, and JSAPI may not be manipulated until the class is
|
||||
* either popped or an AutoJSAPI instance is subsequently pushed.
|
||||
*
|
||||
* This class may not be instantiated if an exception is pending.
|
||||
*/
|
||||
class AutoSystemCaller {
|
||||
class AutoNoJSAPI {
|
||||
public:
|
||||
AutoSystemCaller(bool aIsMainThread = NS_IsMainThread());
|
||||
~AutoSystemCaller();
|
||||
AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
|
||||
~AutoNoJSAPI();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
mozilla::Maybe<AutoCxPusher> mCxPusher;
|
||||
|
@ -11472,9 +11472,9 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
||||
// that we don't force a system caller here, because that screws it up
|
||||
// when it tries to compute the caller principal to associate with dialog
|
||||
// arguments. That whole setup just really needs to be rewritten. :-(
|
||||
Maybe<AutoSystemCaller> asc;
|
||||
Maybe<AutoNoJSAPI> nojsapi;
|
||||
if (!aContentModal) {
|
||||
asc.construct();
|
||||
nojsapi.construct();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2037,7 +2037,7 @@ ConstructJSImplementation(JSContext* aCx, const char* aContractId,
|
||||
// initializing the object, so exceptions from that will get reported
|
||||
// properly, since those are never exceptions that a spec wants to be thrown.
|
||||
{
|
||||
AutoSystemCaller asc;
|
||||
AutoNoJSAPI nojsapi;
|
||||
|
||||
// Get the XPCOM component containing the JS implementation.
|
||||
nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId);
|
||||
|
@ -57,6 +57,25 @@ extern bool gBluetoothDebugFlag;
|
||||
#define BT_WARNING(msg, ...) printf("%s: " msg, __FUNCTION__, ##__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Wrap literal name and value into a BluetoothNamedValue
|
||||
* and append it to the array.
|
||||
*/
|
||||
#define BT_APPEND_NAMED_VALUE(array, name, value) \
|
||||
array.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING(name), value))
|
||||
|
||||
/**
|
||||
* Ensure success of system message broadcast with void return.
|
||||
*/
|
||||
#define BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters) \
|
||||
do { \
|
||||
if (!BroadcastSystemMessage(type, parameters)) { \
|
||||
BT_WARNING("Failed to broadcast [%s]", \
|
||||
NS_ConvertUTF16toUTF8(type).get()); \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define BEGIN_BLUETOOTH_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace bluetooth {
|
||||
#define END_BLUETOOTH_NAMESPACE \
|
||||
|
@ -241,18 +241,10 @@ BluetoothHidManager::NotifyStatusChanged()
|
||||
NS_NAMED_LITERAL_STRING(type, BLUETOOTH_HID_STATUS_CHANGED_ID);
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
|
||||
BluetoothValue v = mConnected;
|
||||
parameters.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("connected"), v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "connected", mConnected);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast system message to settings");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -266,8 +266,7 @@ A2dpConnectionStateCallback(btav_connection_state_t aState,
|
||||
AvStatusToSinkString(aState, a2dpState);
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("State"), a2dpState));
|
||||
BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
|
||||
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
|
||||
remoteDeviceBdAddress, props);
|
||||
@ -296,8 +295,7 @@ A2dpAudioStateCallback(btav_audio_state_t aState,
|
||||
}
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("State"), a2dpState));
|
||||
BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
|
||||
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
|
||||
remoteDeviceBdAddress, props);
|
||||
|
@ -1265,39 +1265,17 @@ BluetoothOppManager::FileTransferComplete()
|
||||
return;
|
||||
}
|
||||
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-transfer-complete");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-transfer-complete");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "success", mSuccessFlag);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "received", mIsServer);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileName", mFileName);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mSentFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "contentType", mContentType);
|
||||
|
||||
name.AssignLiteral("success");
|
||||
v = mSuccessFlag;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("received");
|
||||
v = mIsServer;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
v = mFileName;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mSentFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("contentType");
|
||||
v = mContentType;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
|
||||
mSendTransferCompleteFlag = true;
|
||||
}
|
||||
@ -1305,35 +1283,16 @@ BluetoothOppManager::FileTransferComplete()
|
||||
void
|
||||
BluetoothOppManager::StartFileTransfer()
|
||||
{
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-transfer-start");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-transfer-start");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "received", mIsServer);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileName", mFileName);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "contentType", mContentType);
|
||||
|
||||
name.AssignLiteral("received");
|
||||
v = mIsServer;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
v = mFileName;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("contentType");
|
||||
v = mContentType;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
|
||||
mSendTransferCompleteFlag = false;
|
||||
}
|
||||
@ -1341,61 +1300,29 @@ BluetoothOppManager::StartFileTransfer()
|
||||
void
|
||||
BluetoothOppManager::UpdateProgress()
|
||||
{
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-update-progress");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-update-progress");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "received", mIsServer);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "processedLength", mSentFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mFileLength);
|
||||
|
||||
name.AssignLiteral("received");
|
||||
v = mIsServer;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("processedLength");
|
||||
v = mSentFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::ReceivingFileConfirmation()
|
||||
{
|
||||
nsString type, name;
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-opp-receiving-file-confirmation");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
type.AssignLiteral("bluetooth-opp-receiving-file-confirmation");
|
||||
|
||||
name.AssignLiteral("address");
|
||||
v = mDeviceAddress;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileName", mFileName);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "fileLength", mFileLength);
|
||||
BT_APPEND_NAMED_VALUE(parameters, "contentType", mContentType);
|
||||
|
||||
name.AssignLiteral("fileName");
|
||||
v = mFileName;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("fileLength");
|
||||
v = mFileLength;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
name.AssignLiteral("contentType");
|
||||
v = mContentType;
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
|
||||
return;
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -294,15 +294,13 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
||||
if (p.type == BT_PROPERTY_BDADDR) {
|
||||
BdAddressTypeToString((bt_bdaddr_t*)p.val, sAdapterBdAddress);
|
||||
propertyValue = sAdapterBdAddress;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Address", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_BDNAME) {
|
||||
// Construct nsCString here because Bd name returned from bluedroid
|
||||
// is missing a null terminated character after SetProperty.
|
||||
propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16(
|
||||
nsCString((char*)p.val, p.len));
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
|
||||
bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
|
||||
|
||||
@ -312,13 +310,10 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
||||
propertyValue = sAdapterDiscoverable = false;
|
||||
}
|
||||
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
|
||||
propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("DiscoverableTimeout"),
|
||||
propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
|
||||
// We have to cache addresses of bonded devices. Unlike BlueZ,
|
||||
// bluedroid would not send an another BT_PROPERTY_ADAPTER_BONDED_DEVICES
|
||||
@ -337,8 +332,7 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
||||
}
|
||||
|
||||
propertyValue = sAdapterBondedAddressArray;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Devices"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_UUIDS) {
|
||||
//FIXME: This will be implemented in the later patchset
|
||||
continue;
|
||||
@ -389,25 +383,21 @@ RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
|
||||
|
||||
nsString remoteDeviceBdAddress;
|
||||
BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), remoteDeviceBdAddress));
|
||||
BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress);
|
||||
|
||||
for (int i = 0; i < aNumProperties; ++i) {
|
||||
bt_property_t p = aProperties[i];
|
||||
|
||||
if (p.type == BT_PROPERTY_BDNAME) {
|
||||
BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
|
||||
uint32_t cod = *(uint32_t*)p.val;
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Class"), BluetoothValue(cod)));
|
||||
BT_APPEND_NAMED_VALUE(props, "Class", cod);
|
||||
|
||||
nsString icon;
|
||||
ClassToIcon(cod, icon);
|
||||
props.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Icon"), BluetoothValue(icon)));
|
||||
BT_APPEND_NAMED_VALUE(props, "Icon", icon);
|
||||
} else {
|
||||
BT_LOGD("Other non-handled device properties. Type: %d", p.type);
|
||||
}
|
||||
@ -460,22 +450,20 @@ DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
|
||||
nsString remoteDeviceBdAddress;
|
||||
BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress);
|
||||
propertyValue = remoteDeviceBdAddress;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), propertyValue));
|
||||
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_BDNAME) {
|
||||
propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Name", propertyValue);
|
||||
} else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
|
||||
uint32_t cod = *(uint32_t*)p.val;
|
||||
propertyValue = cod;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Class"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue);
|
||||
|
||||
nsString icon;
|
||||
ClassToIcon(cod, icon);
|
||||
propertyValue = icon;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Icon"), propertyValue));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue);
|
||||
} else {
|
||||
BT_LOGD("Not handled remote device property: %d", p.type);
|
||||
}
|
||||
@ -515,15 +503,12 @@ PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress,
|
||||
nsAutoString remoteAddress;
|
||||
BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
|
||||
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), remoteAddress));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("method"),
|
||||
NS_LITERAL_STRING("pincode")));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("name"),
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "method",
|
||||
NS_LITERAL_STRING("pincode"));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "name",
|
||||
NS_ConvertUTF8toUTF16(
|
||||
(const char*)aRemoteBdName->name)));
|
||||
(const char*)aRemoteBdName->name));
|
||||
|
||||
BluetoothValue value = propertiesArray;
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("RequestPinCode"),
|
||||
@ -546,17 +531,13 @@ SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName,
|
||||
nsAutoString remoteAddress;
|
||||
BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
|
||||
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), remoteAddress));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("method"),
|
||||
NS_LITERAL_STRING("confirmation")));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("name"),
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "method",
|
||||
NS_LITERAL_STRING("confirmation"));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "name",
|
||||
NS_ConvertUTF8toUTF16(
|
||||
(const char*)aRemoteBdName->name)));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("passkey"), aPasskey));
|
||||
(const char*)aRemoteBdName->name));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPasskey);
|
||||
|
||||
BluetoothValue value = propertiesArray;
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("RequestConfirmation"),
|
||||
@ -592,9 +573,9 @@ BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
|
||||
|
||||
// Update bonded address list to BluetoothAdapter
|
||||
InfallibleTArray<BluetoothNamedValue> propertiesChangeArray;
|
||||
propertiesChangeArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Devices"),
|
||||
sAdapterBondedAddressArray));
|
||||
BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices",
|
||||
sAdapterBondedAddressArray);
|
||||
|
||||
BluetoothValue value(propertiesChangeArray);
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
@ -603,10 +584,9 @@ BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
|
||||
|
||||
// Update bonding status to gaia
|
||||
InfallibleTArray<BluetoothNamedValue> propertiesArray;
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), remoteAddress));
|
||||
propertiesArray.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("status"), bonded));
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
|
||||
|
||||
BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
BluetoothValue(propertiesArray));
|
||||
@ -796,23 +776,20 @@ BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
|
||||
|
||||
BluetoothValue v = InfallibleTArray<BluetoothNamedValue>();
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Address"), sAdapterBdAddress));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Address", sAdapterBdAddress);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Name"), sAdapterBdName));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Name", sAdapterBdName);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"),
|
||||
sAdapterDiscoverable));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Discoverable", sAdapterDiscoverable);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("DiscoverableTimeout"),
|
||||
sAdapterDiscoverableTimeout));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"DiscoverableTimeout", sAdapterDiscoverableTimeout);
|
||||
|
||||
v.get_ArrayOfBluetoothNamedValue().AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("Devices"),
|
||||
sAdapterBondedAddressArray));
|
||||
BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
|
||||
"Devices", sAdapterBondedAddressArray);
|
||||
|
||||
nsAutoString replyError;
|
||||
DispatchBluetoothReply(runnable.get(), v, replyError);
|
||||
|
@ -176,10 +176,8 @@ DispatchStatusChangedEvent(const nsAString& aType,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> data;
|
||||
data.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("address"), nsString(aAddress)));
|
||||
data.AppendElement(
|
||||
BluetoothNamedValue(NS_LITERAL_STRING("status"), aStatus));
|
||||
BT_APPEND_NAMED_VALUE(data, "address", nsString(aAddress));
|
||||
BT_APPEND_NAMED_VALUE(data, "status", aStatus);
|
||||
|
||||
BluetoothSignal signal(nsString(aType), NS_LITERAL_STRING(KEY_ADAPTER), data);
|
||||
|
||||
|
@ -811,18 +811,12 @@ BluetoothHfpManager::NotifyConnectionStateChanged(const nsAString& aType)
|
||||
void
|
||||
BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
|
||||
{
|
||||
BluetoothValue v;
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-dialer-command");
|
||||
InfallibleTArray<BluetoothNamedValue> parameters;
|
||||
|
||||
NS_NAMED_LITERAL_STRING(type, "bluetooth-dialer-command");
|
||||
NS_NAMED_LITERAL_STRING(name, "command");
|
||||
BT_APPEND_NAMED_VALUE(parameters, "command", nsString(aCommand));
|
||||
|
||||
v = nsString(aCommand);
|
||||
parameters.AppendElement(BluetoothNamedValue(name, v));
|
||||
|
||||
if (!BroadcastSystemMessage(type, parameters)) {
|
||||
BT_WARNING("Failed to broadcast system message to dialer");
|
||||
}
|
||||
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -791,8 +791,10 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
|
||||
nsIScriptContext* context = global->GetScriptContext();
|
||||
NS_ENSURE_STATE(context);
|
||||
|
||||
// Push a context to make sure exceptions are reported in the right place.
|
||||
AutoPushJSContextForErrorReporting cx(context->GetNativeContext());
|
||||
// Activate JSAPI, and make sure that exceptions are reported on the right
|
||||
// Window.
|
||||
AutoJSAPIWithErrorsReportedToWindow jsapi(context);
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
nsCOMPtr<nsIAtom> typeAtom = aListener->mTypeAtom;
|
||||
nsIAtom* attrName = typeAtom;
|
||||
|
@ -15,6 +15,8 @@ KeyboardEvent::KeyboardEvent(EventTarget* aOwner,
|
||||
WidgetKeyboardEvent* aEvent)
|
||||
: UIEvent(aOwner, aPresContext,
|
||||
aEvent ? aEvent : new WidgetKeyboardEvent(false, 0, nullptr))
|
||||
, mInitializedByCtor(false)
|
||||
, mInitialzedWhichValue(0)
|
||||
{
|
||||
NS_ASSERTION(mEvent->eventStructType == NS_KEY_EVENT, "event type mismatch");
|
||||
|
||||
@ -139,6 +141,11 @@ KeyboardEvent::GetCharCode(uint32_t* aCharCode)
|
||||
uint32_t
|
||||
KeyboardEvent::CharCode()
|
||||
{
|
||||
// If this event is initialized with ctor, we shouldn't check event type.
|
||||
if (mInitializedByCtor) {
|
||||
return mEvent->AsKeyboardEvent()->charCode;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_DOWN:
|
||||
@ -160,6 +167,11 @@ KeyboardEvent::GetKeyCode(uint32_t* aKeyCode)
|
||||
uint32_t
|
||||
KeyboardEvent::KeyCode()
|
||||
{
|
||||
// If this event is initialized with ctor, we shouldn't check event type.
|
||||
if (mInitializedByCtor) {
|
||||
return mEvent->AsKeyboardEvent()->keyCode;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_PRESS:
|
||||
@ -172,6 +184,11 @@ KeyboardEvent::KeyCode()
|
||||
uint32_t
|
||||
KeyboardEvent::Which()
|
||||
{
|
||||
// If this event is initialized with ctor, which can have independent value.
|
||||
if (mInitializedByCtor) {
|
||||
return mInitialzedWhichValue;
|
||||
}
|
||||
|
||||
switch (mEvent->message) {
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_DOWN:
|
||||
@ -206,6 +223,36 @@ KeyboardEvent::Location()
|
||||
return mEvent->AsKeyboardEvent()->location;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<KeyboardEvent>
|
||||
KeyboardEvent::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const KeyboardEventInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsRefPtr<KeyboardEvent> newEvent =
|
||||
new KeyboardEvent(target, nullptr, nullptr);
|
||||
bool trusted = newEvent->Init(target);
|
||||
aRv = newEvent->InitKeyEvent(aType, aParam.mBubbles, aParam.mCancelable,
|
||||
aParam.mView, aParam.mCtrlKey, aParam.mAltKey,
|
||||
aParam.mShiftKey, aParam.mMetaKey,
|
||||
aParam.mKeyCode, aParam.mCharCode);
|
||||
newEvent->SetTrusted(trusted);
|
||||
newEvent->mDetail = aParam.mDetail;
|
||||
newEvent->mInitializedByCtor = true;
|
||||
newEvent->mInitialzedWhichValue = aParam.mWhich;
|
||||
|
||||
WidgetKeyboardEvent* internalEvent = newEvent->mEvent->AsKeyboardEvent();
|
||||
internalEvent->location = aParam.mLocation;
|
||||
internalEvent->mIsRepeat = aParam.mRepeat;
|
||||
internalEvent->mIsComposing = aParam.mIsComposing;
|
||||
internalEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
|
||||
internalEvent->mKeyValue = aParam.mKey;
|
||||
|
||||
return newEvent.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
KeyboardEvent::InitKeyEvent(const nsAString& aType,
|
||||
bool aCanBubble,
|
||||
@ -229,6 +276,28 @@ KeyboardEvent::InitKeyEvent(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
KeyboardEvent::InitKeyboardEvent(const nsAString& aType,
|
||||
bool aCanBubble,
|
||||
bool aCancelable,
|
||||
nsIDOMWindow* aView,
|
||||
uint32_t aDetail,
|
||||
const nsAString& aKey,
|
||||
uint32_t aLocation,
|
||||
const nsAString& aModifiersList,
|
||||
bool aRepeat,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRv = UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
|
||||
|
||||
WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
|
||||
keyEvent->modifiers = UIEvent::ComputeModifierState(aModifiersList);
|
||||
keyEvent->location = aLocation;
|
||||
keyEvent->mIsRepeat = aRepeat;
|
||||
keyEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
|
||||
keyEvent->mKeyValue = aKey;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -30,6 +30,12 @@ public:
|
||||
// Forward to base class
|
||||
NS_FORWARD_TO_UIEVENT
|
||||
|
||||
static already_AddRefed<KeyboardEvent> Constructor(
|
||||
const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const KeyboardEventInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE
|
||||
{
|
||||
return KeyboardEventBinding::Wrap(aCx, this);
|
||||
@ -62,6 +68,21 @@ public:
|
||||
aCtrlKey, aAltKey, aShiftKey,aMetaKey,
|
||||
aKeyCode, aCharCode);
|
||||
}
|
||||
|
||||
void InitKeyboardEvent(const nsAString& aType,
|
||||
bool aCanBubble, bool aCancelable,
|
||||
nsIDOMWindow* aView, uint32_t aDetail,
|
||||
const nsAString& aKey, uint32_t aLocation,
|
||||
const nsAString& aModifiersList, bool aRepeat,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
// True, if the instance is created with Constructor().
|
||||
bool mInitializedByCtor;
|
||||
// If the instance is created with Constructor(), which may have independent
|
||||
// value. mInitializedWhichValue stores it. I.e., this is invalid when
|
||||
// mInitializedByCtor is false.
|
||||
uint32_t mInitialzedWhichValue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -188,20 +188,11 @@ const kEventConstructors = {
|
||||
},
|
||||
},
|
||||
KeyEvent: { create: function (aName, aProps) {
|
||||
var e = document.createEvent("keyboardevent");
|
||||
e.initKeyEvent(aName, aProps.bubbles, aProps.cancelable,
|
||||
aProps.view,
|
||||
aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey,
|
||||
aProps.keyCode, aProps.charCode);
|
||||
return e;
|
||||
return new KeyboardEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
KeyboardEvent: { create: function (aName, aProps) {
|
||||
var e = document.createEvent("keyboardevent");
|
||||
e.initKeyEvent(aName, aProps.bubbles, aProps.cancelable,
|
||||
aProps.view, aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey,
|
||||
aProps.keyCode, aProps.charCode);
|
||||
return e;
|
||||
return new KeyboardEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
MediaStreamEvent: { create: function (aName, aProps) {
|
||||
|
@ -20,55 +20,126 @@ SimpleTest.waitForFocus(runTests, window);
|
||||
function testInitializingUntrustedEvent()
|
||||
{
|
||||
const kTests = [
|
||||
{ createEventArg: "KeyboardEvent",
|
||||
// initKeyEvent
|
||||
{ createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
|
||||
type: "keydown", bubbles: true, cancelable: true, view: null,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x00 },
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 0
|
||||
|
||||
{ createEventArg: "keyboardevent",
|
||||
{ createEventArg: "keyboardevent", useInitKeyboardEvent: false,
|
||||
type: "keyup", bubbles: false, cancelable: true, view: window,
|
||||
ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x10, charCode: 0x00 },
|
||||
keyCode: 0x10, charCode: 0x00,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 1
|
||||
|
||||
{ createEventArg: "Keyboardevent",
|
||||
{ createEventArg: "Keyboardevent", useInitKeyboardEvent: false,
|
||||
type: "keypess", bubbles: true, cancelable: false, view: null,
|
||||
ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x11, charCode: 0x30 },
|
||||
keyCode: 0x11, charCode: 0x30,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 2
|
||||
|
||||
{ createEventArg: "keyboardEvent",
|
||||
{ createEventArg: "keyboardEvent", useInitKeyboardEvent: false,
|
||||
type: "boo", bubbles: false, cancelable: false, view: window,
|
||||
ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
|
||||
keyCode: 0x30, charCode: 0x40 },
|
||||
keyCode: 0x30, charCode: 0x40,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 3
|
||||
|
||||
{ createEventArg: "KeyEvents",
|
||||
{ createEventArg: "KeyEvents", useInitKeyboardEvent: false,
|
||||
type: "foo", bubbles: true, cancelable: true, view: null,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
|
||||
keyCode: 0x00, charCode: 0x50 },
|
||||
keyCode: 0x00, charCode: 0x50,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 4
|
||||
|
||||
{ createEventArg: "keyevents",
|
||||
{ createEventArg: "keyevents", useInitKeyboardEvent: false,
|
||||
type: "bar", bubbles: false, cancelable: true, view: window,
|
||||
ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x60 },
|
||||
keyCode: 0x00, charCode: 0x60,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 5
|
||||
|
||||
{ createEventArg: "Keyevents",
|
||||
{ createEventArg: "Keyevents", useInitKeyboardEvent: false,
|
||||
type: "keydown", bubbles: true, cancelable: false, view: null,
|
||||
ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
|
||||
keyCode: 0x30, charCode: 0x00 },
|
||||
keyCode: 0x30, charCode: 0x00,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 6
|
||||
|
||||
{ createEventArg: "keyEvents",
|
||||
{ createEventArg: "keyEvents", useInitKeyboardEvent: false,
|
||||
type: "keyup", bubbles: false, cancelable: false, view: window,
|
||||
ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
|
||||
keyCode: 0x10, charCode: 0x80 },
|
||||
keyCode: 0x10, charCode: 0x80,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 7
|
||||
|
||||
{ createEventArg: "KeyboardEvent",
|
||||
{ createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
|
||||
type: "keypress", bubbles: false, cancelable: false, view: window,
|
||||
ctrlKey: true, altKey: false, shiftKey: true, metaKey: true,
|
||||
keyCode: 0x10, charCode: 0x80 },
|
||||
keyCode: 0x10, charCode: 0x80,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 8
|
||||
|
||||
{ createEventArg: "KeyboardEvent",
|
||||
{ createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
|
||||
type: "foo", bubbles: false, cancelable: false, view: window,
|
||||
ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
|
||||
keyCode: 0x10, charCode: 0x80 },
|
||||
keyCode: 0x10, charCode: 0x80,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 9
|
||||
|
||||
// initKeyboardEvent
|
||||
{ createEventArg: "KeyboardEvent", useInitKeyboardEvent: true,
|
||||
type: "keydown", bubbles: true, cancelable: true, view: null,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "", location: 0, modifiersList: "", repeat: false,
|
||||
}, // 10
|
||||
|
||||
{ createEventArg: "keyboardevent", useInitKeyboardEvent: true,
|
||||
type: "keyup", bubbles: false, cancelable: true, view: window,
|
||||
ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 2, key: "Unidentified", location: 1, modifiersList: "Control", repeat: false,
|
||||
}, // 11
|
||||
|
||||
{ createEventArg: "Keyboardevent", useInitKeyboardEvent: true,
|
||||
type: "keypess", bubbles: true, cancelable: false, view: null,
|
||||
ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "FooBar", location: 2, modifiersList: "Alt", repeat: true,
|
||||
}, // 12
|
||||
|
||||
{ createEventArg: "keyboardevent", useInitKeyboardEvent: true,
|
||||
type: "foo", bubbles: true, cancelable: true, view: null,
|
||||
ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "a", location: 0, modifiersList: "Meta", repeat: false,
|
||||
}, // 13
|
||||
|
||||
{ createEventArg: "Keyevents", useInitKeyboardEvent: true,
|
||||
type: "", bubbles: false, cancelable: false, view: null,
|
||||
ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "3", location: 0, modifiersList: "Control Alt Meta Shift", repeat: true,
|
||||
}, // 14
|
||||
|
||||
{ createEventArg: "keyevents", useInitKeyboardEvent: true,
|
||||
type: "", bubbles: false, cancelable: false, view: null,
|
||||
ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "3", location: 6, modifiersList: "Shift", repeat: true,
|
||||
}, // 15
|
||||
|
||||
{ createEventArg: "keyevents", useInitKeyboardEvent: true,
|
||||
type: "", bubbles: false, cancelable: false, view: null,
|
||||
ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
|
||||
keyCode: 0x00, charCode: 0x00,
|
||||
detail: 0, key: "", location: 4, modifiersList: "Shift, Alt", repeat: false,
|
||||
}, // 16
|
||||
];
|
||||
|
||||
const kOtherModifierName = [
|
||||
@ -85,17 +156,23 @@ function testInitializingUntrustedEvent()
|
||||
var description = "testInitializingUntrustedEvent, Index: " + i + ", ";
|
||||
const kTest = kTests[i];
|
||||
var e = document.createEvent(kTest.createEventArg);
|
||||
e.initKeyEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
|
||||
kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
|
||||
kTest.keyCode, kTest.charCode);
|
||||
if (kTest.useInitKeyboardEvent) {
|
||||
// IE has extra argument for |.locale|. Calling with it shouldn't cause error for compatibility with IE.
|
||||
e.initKeyboardEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view, kTest.detail,
|
||||
kTest.key, kTest.location, kTest.modifiersList, kTest.repeat, "locale");
|
||||
} else {
|
||||
e.initKeyEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
|
||||
kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
|
||||
kTest.keyCode, kTest.charCode);
|
||||
}
|
||||
is(e.toString(), "[object KeyboardEvent]",
|
||||
description + 'class string should be "KeyboardEvent"');
|
||||
|
||||
for (var attr in kTest) {
|
||||
if (attr == "createEventArg") {
|
||||
if (attr == "createEventArg" || attr == "useInitKeyboardEvent" || attr == "modifiersList") {
|
||||
continue;
|
||||
}
|
||||
if (attr == "keyCode") {
|
||||
if (!kTest.useInitKeyboardEvent && attr == "keyCode") {
|
||||
// If this is keydown, keyup of keypress event, keycod must be correct.
|
||||
if (kTest.type == "keydown" || kTest.type == "keyup" || kTest.type == "keypress") {
|
||||
is(e[attr], kTest[attr], description + attr + " returns wrong value");
|
||||
@ -103,7 +180,7 @@ function testInitializingUntrustedEvent()
|
||||
} else {
|
||||
is(e[attr], 0, description + attr + " returns non-zero for invalid event");
|
||||
}
|
||||
} else if (attr == "charCode") {
|
||||
} else if (!kTest.useInitKeyboardEvent && attr == "charCode") {
|
||||
// If this is keydown or keyup event, charCode always 0.
|
||||
if (kTest.type == "keydown" || kTest.type == "keyup") {
|
||||
is(e[attr], 0, description + attr + " returns non-zero for keydown or keyup event");
|
||||
@ -122,9 +199,6 @@ function testInitializingUntrustedEvent()
|
||||
}
|
||||
is(e.isTrusted, false, description + "isTrusted returns wrong value");
|
||||
|
||||
// Currently, there is no way to initialize char and key attribute values.
|
||||
ok(e.key === "", description + "key must return empty string - got " + e.key);
|
||||
|
||||
// getModifierState() tests
|
||||
is(e.getModifierState("Shift"), kTest.shiftKey,
|
||||
description + "getModifierState(\"Shift\") returns wrong value");
|
||||
|
@ -340,6 +340,88 @@ ok(e.cancelable, "Event should be cancelable!");
|
||||
is(e.detail, 0, "detail should be 0");
|
||||
ok(e.isComposing, "isComposing should be true");
|
||||
|
||||
// KeyboardEvent
|
||||
|
||||
try {
|
||||
e = new KeyboardEvent();
|
||||
} catch(exp) {
|
||||
ex = true;
|
||||
}
|
||||
ok(ex, "KeyboardEvent: First parameter is required!");
|
||||
ex = false;
|
||||
|
||||
e = new KeyboardEvent("hello");
|
||||
ok(e.type, "hello", "KeyboardEvent: Wrong event type!");
|
||||
ok(!e.isTrusted, "KeyboardEvent: Event shouldn't be trusted!");
|
||||
ok(!e.bubbles, "KeyboardEvent: Event shouldn't bubble!");
|
||||
ok(!e.cancelable, "KeyboardEvent: Event shouldn't be cancelable!");
|
||||
document.dispatchEvent(e);
|
||||
is(receivedEvent, e, "KeyboardEvent: Wrong event!");
|
||||
|
||||
var keyboardEventProps =
|
||||
[
|
||||
{ bubbles: false },
|
||||
{ cancelable: false },
|
||||
{ view: null },
|
||||
{ detail: 0 },
|
||||
{ key: "" },
|
||||
{ location: 0 },
|
||||
{ ctrlKey: false },
|
||||
{ shiftKey: false },
|
||||
{ altKey: false },
|
||||
{ metaKey: false },
|
||||
{ repeat: false },
|
||||
{ isComposing: false },
|
||||
{ charCode: 0 },
|
||||
{ keyCode: 0 },
|
||||
{ which: 0 },
|
||||
];
|
||||
|
||||
var testKeyboardProps =
|
||||
[
|
||||
{ bubbles: true },
|
||||
{ cancelable: true },
|
||||
{ view: window },
|
||||
{ detail: 1 },
|
||||
{ key: "CustomKey" },
|
||||
{ location: 1 },
|
||||
{ ctrlKey: true },
|
||||
{ shiftKey: true },
|
||||
{ altKey: true },
|
||||
{ metaKey: true },
|
||||
{ repeat: true },
|
||||
{ isComposing: true },
|
||||
{ charCode: 2 },
|
||||
{ keyCode: 3 },
|
||||
{ which: 4 },
|
||||
{ charCode: 5, which: 6 },
|
||||
{ keyCode: 7, which: 8 },
|
||||
{ keyCode: 9, charCode: 10 },
|
||||
{ keyCode: 11, charCode: 12, which: 13 },
|
||||
];
|
||||
|
||||
var defaultKeyboardEventValues = {};
|
||||
for (var i = 0; i < keyboardEventProps.length; ++i) {
|
||||
for (prop in keyboardEventProps[i]) {
|
||||
ok(prop in e, "keyboardEvent: KeyboardEvent doesn't have property " + prop + "!");
|
||||
defaultKeyboardEventValues[prop] = keyboardEventProps[i][prop];
|
||||
}
|
||||
}
|
||||
|
||||
while (testKeyboardProps.length) {
|
||||
var p = testKeyboardProps.shift();
|
||||
e = new KeyboardEvent("foo", p);
|
||||
for (var def in defaultKeyboardEventValues) {
|
||||
if (!(def in p)) {
|
||||
is(e[def], defaultKeyboardEventValues[def],
|
||||
"KeyboardEvent: Wrong default value for " + def + "!");
|
||||
} else {
|
||||
is(e[def], p[def],
|
||||
"KeyboardEvent: Wrong event init value for " + def + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PageTransitionEvent
|
||||
|
||||
try {
|
||||
|
@ -608,7 +608,9 @@ IndexedDatabaseManager::AsyncDeleteFile(FileManager* aFileManager,
|
||||
|
||||
// See if we're currently clearing the storages for this origin. If so then
|
||||
// we pretend that we've already deleted everything.
|
||||
if (quotaManager->IsClearOriginPending(aFileManager->Origin())) {
|
||||
if (quotaManager->IsClearOriginPending(
|
||||
aFileManager->Origin(),
|
||||
Nullable<PersistenceType>(aFileManager->Type()))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2146,7 +2146,8 @@ OpenDatabaseHelper::StartSetVersion()
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
rv = quotaManager->AcquireExclusiveAccess(
|
||||
mDatabase, mDatabase->Origin(), helper,
|
||||
mDatabase, mDatabase->Origin(),
|
||||
Nullable<PersistenceType>(mDatabase->Type()), helper,
|
||||
&VersionChangeEventsRunnable::QueueVersionChange<SetVersionHelper>,
|
||||
helper);
|
||||
IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
@ -2176,7 +2177,8 @@ OpenDatabaseHelper::StartDelete()
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
rv = quotaManager->AcquireExclusiveAccess(
|
||||
mDatabase, mDatabase->Origin(), helper,
|
||||
mDatabase, mDatabase->Origin(),
|
||||
Nullable<PersistenceType>(mDatabase->Type()), helper,
|
||||
&VersionChangeEventsRunnable::QueueVersionChange<DeleteDatabaseHelper>,
|
||||
helper);
|
||||
IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
@ -1,6 +1,2 @@
|
||||
component {397a7fdf-2254-47be-b74e-76625a1a66d5} MozKeyboard.js
|
||||
contract @mozilla.org/b2g-keyboard;1 {397a7fdf-2254-47be-b74e-76625a1a66d5}
|
||||
category JavaScript-navigator-property mozKeyboard @mozilla.org/b2g-keyboard;1
|
||||
|
||||
component {4607330d-e7d2-40a4-9eb8-43967eae0142} MozKeyboard.js
|
||||
contract @mozilla.org/b2g-inputmethod;1 {4607330d-e7d2-40a4-9eb8-43967eae0142}
|
||||
|
@ -27,7 +27,6 @@ this.Keyboard = {
|
||||
],
|
||||
|
||||
_messageNames: [
|
||||
'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions',
|
||||
'SetSelectionRange', 'ReplaceSurroundingText', 'ShowInputMethodPicker',
|
||||
'SwitchToNextInputMethod', 'HideInputMethod',
|
||||
'GetText', 'SendKey', 'GetContext',
|
||||
@ -170,7 +169,6 @@ this.Keyboard = {
|
||||
this.forwardEvent(name, msg);
|
||||
break;
|
||||
|
||||
case 'Keyboard:SetValue':
|
||||
case 'System:SetValue':
|
||||
this.setValue(msg);
|
||||
break;
|
||||
@ -178,11 +176,9 @@ this.Keyboard = {
|
||||
case 'System:RemoveFocus':
|
||||
this.removeFocus();
|
||||
break;
|
||||
case 'Keyboard:SetSelectedOption':
|
||||
case 'System:SetSelectedOption':
|
||||
this.setSelectedOption(msg);
|
||||
break;
|
||||
case 'Keyboard:SetSelectedOptions':
|
||||
case 'System:SetSelectedOptions':
|
||||
this.setSelectedOption(msg);
|
||||
break;
|
||||
|
@ -18,187 +18,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "tm",
|
||||
"@mozilla.org/thread-manager;1", "nsIThreadManager");
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// MozKeyboard
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function MozKeyboard() { }
|
||||
|
||||
MozKeyboard.prototype = {
|
||||
classID: Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIB2GKeyboard, Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIObserver
|
||||
]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
"classID": Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
|
||||
"contractID": "@mozilla.org/b2g-keyboard;1",
|
||||
"interfaces": [Ci.nsIB2GKeyboard],
|
||||
"flags": Ci.nsIClassInfo.DOM_OBJECT,
|
||||
"classDescription": "B2G Virtual Keyboard"
|
||||
}),
|
||||
|
||||
init: function mozKeyboardInit(win) {
|
||||
let principal = win.document.nodePrincipal;
|
||||
// Limited the deprecated mozKeyboard API to certified apps only
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(principal,
|
||||
"input-manage");
|
||||
if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
dump("No permission to use the keyboard API for " +
|
||||
principal.origin + "\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
cpmm.addMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.addMessageListener('Keyboard:SelectionChange', this);
|
||||
|
||||
this._window = win;
|
||||
this._utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this.innerWindowID = this._utils.currentInnerWindowID;
|
||||
this._focusHandler = null;
|
||||
this._selectionHandler = null;
|
||||
this._selectionStart = -1;
|
||||
this._selectionEnd = -1;
|
||||
},
|
||||
|
||||
uninit: function mozKeyboardUninit() {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
cpmm.removeMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.removeMessageListener('Keyboard:SelectionChange', this);
|
||||
|
||||
this._window = null;
|
||||
this._utils = null;
|
||||
this._focusHandler = null;
|
||||
this._selectionHandler = null;
|
||||
},
|
||||
|
||||
sendKey: function mozKeyboardSendKey(keyCode, charCode) {
|
||||
charCode = (charCode == undefined) ? keyCode : charCode;
|
||||
|
||||
let mainThread = tm.mainThread;
|
||||
let utils = this._utils;
|
||||
|
||||
function send(type) {
|
||||
mainThread.dispatch(function() {
|
||||
utils.sendKeyEvent(type, keyCode, charCode, null);
|
||||
}, mainThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
send("keydown");
|
||||
send("keypress");
|
||||
send("keyup");
|
||||
},
|
||||
|
||||
setSelectedOption: function mozKeyboardSetSelectedOption(index) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetSelectedOption', {
|
||||
'index': index
|
||||
});
|
||||
},
|
||||
|
||||
setValue: function mozKeyboardSetValue(value) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetValue', {
|
||||
'value': value
|
||||
});
|
||||
},
|
||||
|
||||
setSelectedOptions: function mozKeyboardSetSelectedOptions(indexes) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetSelectedOptions', {
|
||||
'indexes': indexes
|
||||
});
|
||||
},
|
||||
|
||||
set onselectionchange(val) {
|
||||
this._selectionHandler = val;
|
||||
},
|
||||
|
||||
get onselectionchange() {
|
||||
return this._selectionHandler;
|
||||
},
|
||||
|
||||
get selectionStart() {
|
||||
return this._selectionStart;
|
||||
},
|
||||
|
||||
get selectionEnd() {
|
||||
return this._selectionEnd;
|
||||
},
|
||||
|
||||
setSelectionRange: function mozKeyboardSetSelectionRange(start, end) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetSelectionRange', {
|
||||
'selectionStart': start,
|
||||
'selectionEnd': end
|
||||
});
|
||||
},
|
||||
|
||||
removeFocus: function mozKeyboardRemoveFocus() {
|
||||
cpmm.sendAsyncMessage('Keyboard:RemoveFocus', {});
|
||||
},
|
||||
|
||||
set onfocuschange(val) {
|
||||
this._focusHandler = val;
|
||||
},
|
||||
|
||||
get onfocuschange() {
|
||||
return this._focusHandler;
|
||||
},
|
||||
|
||||
replaceSurroundingText: function mozKeyboardReplaceSurroundingText(
|
||||
text, beforeLength, afterLength) {
|
||||
cpmm.sendAsyncMessage('Keyboard:ReplaceSurroundingText', {
|
||||
'text': text || '',
|
||||
'beforeLength': (typeof beforeLength === 'number' ? beforeLength : 0),
|
||||
'afterLength': (typeof afterLength === 'number' ? afterLength: 0)
|
||||
});
|
||||
},
|
||||
|
||||
receiveMessage: function mozKeyboardReceiveMessage(msg) {
|
||||
if (msg.name == "Keyboard:FocusChange") {
|
||||
let msgJson = msg.json;
|
||||
if (msgJson.type != "blur") {
|
||||
this._selectionStart = msgJson.selectionStart;
|
||||
this._selectionEnd = msgJson.selectionEnd;
|
||||
} else {
|
||||
this._selectionStart = 0;
|
||||
this._selectionEnd = 0;
|
||||
}
|
||||
|
||||
let handler = this._focusHandler;
|
||||
if (!handler || !(handler instanceof Ci.nsIDOMEventListener))
|
||||
return;
|
||||
|
||||
let detail = {
|
||||
"detail": msgJson
|
||||
};
|
||||
|
||||
let evt = new this._window.CustomEvent("focuschanged",
|
||||
Cu.cloneInto(detail, this._window));
|
||||
handler.handleEvent(evt);
|
||||
} else if (msg.name == "Keyboard:SelectionChange") {
|
||||
let msgJson = msg.json;
|
||||
|
||||
this._selectionStart = msgJson.selectionStart;
|
||||
this._selectionEnd = msgJson.selectionEnd;
|
||||
|
||||
let handler = this._selectionHandler;
|
||||
if (!handler || !(handler instanceof Ci.nsIDOMEventListener))
|
||||
return;
|
||||
|
||||
let evt = new this._window.CustomEvent("selectionchange",
|
||||
Cu.cloneInto({}, this._window));
|
||||
handler.handleEvent(evt);
|
||||
}
|
||||
},
|
||||
|
||||
observe: function mozKeyboardObserve(subject, topic, data) {
|
||||
let wId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this.innerWindowID)
|
||||
this.uninit();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A WeakMap to map input method iframe window to its active status.
|
||||
*/
|
||||
@ -288,6 +107,7 @@ MozInputMethod.prototype = {
|
||||
_layouts: {},
|
||||
_window: null,
|
||||
_isSystem: false,
|
||||
_isKeyboard: true,
|
||||
|
||||
classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
|
||||
|
||||
@ -304,6 +124,8 @@ MozInputMethod.prototype = {
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.currentInnerWindowID;
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
|
||||
let principal = win.document.nodePrincipal;
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(principal,
|
||||
"input-manage");
|
||||
@ -311,7 +133,18 @@ MozInputMethod.prototype = {
|
||||
this._isSystem = true;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
// Check if we can use keyboard related APIs.
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) {
|
||||
}
|
||||
perm = Services.perms.testExactPermissionFromPrincipal(principal, "input");
|
||||
if (!testing && perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
this._isKeyboard = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cpmm.addWeakMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
@ -319,15 +152,18 @@ MozInputMethod.prototype = {
|
||||
},
|
||||
|
||||
uninit: function mozInputMethodUninit() {
|
||||
this.setActive(false);
|
||||
this._window = null;
|
||||
this._mgmt = null;
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
if (!this._isKeyboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpmm.removeWeakMessageListener('Keyboard:FocusChange', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
|
||||
|
||||
this._window = null;
|
||||
this._mgmt = null;
|
||||
this.setActive(false);
|
||||
},
|
||||
|
||||
receiveMessage: function mozInputMethodReceiveMsg(msg) {
|
||||
@ -769,5 +605,4 @@ MozInputContext.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
[MozKeyboard, MozInputMethod]);
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozInputMethod]);
|
||||
|
@ -6,12 +6,6 @@
|
||||
|
||||
TEST_DIRS += ['mochitest']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIB2GKeyboard.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_inputmethod'
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'InputMethod.manifest',
|
||||
'MozKeyboard.js',
|
||||
@ -21,4 +15,4 @@ EXTRA_JS_MODULES += [
|
||||
'Keyboard.jsm',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -1,71 +0,0 @@
|
||||
/* 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 "domstubs.idl"
|
||||
|
||||
[scriptable, uuid(40ad96b2-9efa-41fb-84c7-fbcec9b153f0)]
|
||||
interface nsIB2GKeyboard : nsISupports
|
||||
{
|
||||
void sendKey(in long keyCode, in long charCode);
|
||||
|
||||
// Select the <select> option specified by index.
|
||||
// If this method is called on a <select> that support multiple
|
||||
// selection, then the option specified by index will be added to
|
||||
// the selection.
|
||||
// If this method is called for a select that does not support multiple
|
||||
// selection the previous element will be unselected.
|
||||
void setSelectedOption(in jsval index);
|
||||
|
||||
// Select the <select> options specified by indexes. All other options
|
||||
// will be deselected.
|
||||
// If this method is called for a <select> that does not support multiple
|
||||
// selection, then the last index specified in indexes will be selected.
|
||||
void setSelectedOptions(in jsval indexes);
|
||||
|
||||
// Set the value on the currently focused element. This has to be used
|
||||
// for special situations where the value had to be chosen amongst a
|
||||
// list (type=month) or a widget (type=date, time, etc.).
|
||||
// If the value passed in parameter isn't valid (in the term of HTML5
|
||||
// Forms Validation), the value will simply be ignored by the element.
|
||||
void setValue(in jsval value);
|
||||
|
||||
void removeFocus();
|
||||
|
||||
attribute nsIDOMEventListener onfocuschange;
|
||||
|
||||
// Fires when user moves the cursor, changes the selection, or alters the
|
||||
// composing text length
|
||||
attribute nsIDOMEventListener onselectionchange;
|
||||
|
||||
// The start position of the selection.
|
||||
readonly attribute long selectionStart;
|
||||
|
||||
// The stop position of the selection.
|
||||
readonly attribute long selectionEnd;
|
||||
|
||||
/*
|
||||
* Set the selection range of the the editable text.
|
||||
*
|
||||
* @param start The beginning of the selected text.
|
||||
* @param end The end of the selected text.
|
||||
*
|
||||
* Note that the start position should be less or equal to the end position.
|
||||
* To move the cursor, set the start and end position to the same value.
|
||||
*/
|
||||
void setSelectionRange(in long start, in long end);
|
||||
|
||||
/*
|
||||
* Replace text around the beginning of the current selection range of the
|
||||
* editable text.
|
||||
*
|
||||
* @param text The string to be replaced with.
|
||||
* @param beforeLength The number of characters to be deleted before the
|
||||
* beginning of the current selection range. Defaults to 0.
|
||||
* @param afterLength The number of characters to be deleted after the
|
||||
* beginning of the current selection range. Defaults to 0.
|
||||
*/
|
||||
void replaceSurroundingText(in DOMString text,
|
||||
[optional] in long beforeLength,
|
||||
[optional] in long afterLength);
|
||||
};
|
@ -73,6 +73,7 @@
|
||||
#include "ipc/nsGUIEventIPC.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "UnitTransforms.h"
|
||||
#include "ClientLayerManager.h"
|
||||
|
||||
#include "nsColorPickerProxy.h"
|
||||
|
||||
@ -105,6 +106,9 @@ static bool sCpowsEnabled = false;
|
||||
static int32_t sActiveDurationMs = 10;
|
||||
static bool sActiveDurationMsSet = false;
|
||||
|
||||
typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
|
||||
static TabChildMap* sTabChildren;
|
||||
|
||||
TabChildBase::TabChildBase()
|
||||
: mOldViewportWidth(0.0f)
|
||||
, mContentDocumentIsDisplayed(false)
|
||||
@ -669,6 +673,7 @@ TabChild::TabChild(ContentChild* aManager, const TabContext& aContext, uint32_t
|
||||
, mRemoteFrame(nullptr)
|
||||
, mManager(aManager)
|
||||
, mChromeFlags(aChromeFlags)
|
||||
, mLayersId(0)
|
||||
, mOuterRect(0, 0, 0, 0)
|
||||
, mActivePointerId(-1)
|
||||
, mTapHoldTimer(nullptr)
|
||||
@ -1293,6 +1298,17 @@ TabChild::DestroyWindow()
|
||||
mRemoteFrame->Destroy();
|
||||
mRemoteFrame = nullptr;
|
||||
}
|
||||
|
||||
|
||||
if (mLayersId != 0) {
|
||||
MOZ_ASSERT(sTabChildren);
|
||||
sTabChildren->Remove(mLayersId);
|
||||
if (!sTabChildren->Count()) {
|
||||
delete sTabChildren;
|
||||
sTabChildren = nullptr;
|
||||
}
|
||||
mLayersId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2387,6 +2403,13 @@ TabChild::InitRenderingState()
|
||||
ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
|
||||
|
||||
mRemoteFrame = remoteFrame;
|
||||
if (id != 0) {
|
||||
if (!sTabChildren) {
|
||||
sTabChildren = new TabChildMap;
|
||||
}
|
||||
sTabChildren->Put(id, this);
|
||||
mLayersId = id;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
@ -2583,6 +2606,26 @@ TabChild::GetFrom(nsIPresShell* aPresShell)
|
||||
return GetFrom(docShell);
|
||||
}
|
||||
|
||||
TabChild*
|
||||
TabChild::GetFrom(uint64_t aLayersId)
|
||||
{
|
||||
if (!sTabChildren) {
|
||||
return nullptr;
|
||||
}
|
||||
return sTabChildren->Get(aLayersId);
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::DidComposite()
|
||||
{
|
||||
MOZ_ASSERT(mWidget);
|
||||
MOZ_ASSERT(mWidget->GetLayerManager());
|
||||
MOZ_ASSERT(mWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT);
|
||||
|
||||
ClientLayerManager *manager = static_cast<ClientLayerManager*>(mWidget->GetLayerManager());
|
||||
manager->DidComposite();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText)
|
||||
{
|
||||
|
@ -430,6 +430,9 @@ public:
|
||||
}
|
||||
|
||||
static TabChild* GetFrom(nsIPresShell* aPresShell);
|
||||
static TabChild* GetFrom(uint64_t aLayersId);
|
||||
|
||||
void DidComposite();
|
||||
|
||||
static inline TabChild*
|
||||
GetFrom(nsIDOMWindow* aWindow)
|
||||
@ -514,6 +517,7 @@ private:
|
||||
RenderFrameChild* mRemoteFrame;
|
||||
nsRefPtr<ContentChild> mManager;
|
||||
uint32_t mChromeFlags;
|
||||
uint64_t mLayersId;
|
||||
nsIntRect mOuterRect;
|
||||
// When we're tracking a possible tap gesture, this is the "down"
|
||||
// point of the touchstart.
|
||||
|
@ -166,8 +166,9 @@ mozNfc.prototype = {
|
||||
this._window = aWindow;
|
||||
},
|
||||
|
||||
// Only System Process can call the following interfaces
|
||||
// 'checkP2PRegistration' , 'notifyUserAcceptedP2P' , 'notifySendFileStatus'
|
||||
// Only apps which have nfc-manager permission can call the following interfaces
|
||||
// 'checkP2PRegistration' , 'notifyUserAcceptedP2P' , 'notifySendFileStatus',
|
||||
// 'startPoll', 'stopPoll', and 'powerOff'.
|
||||
checkP2PRegistration: function checkP2PRegistration(manifestUrl) {
|
||||
// Get the AppID and pass it to ContentHelper
|
||||
let appID = appsService.getAppLocalIdByManifestURL(manifestUrl);
|
||||
@ -185,6 +186,18 @@ mozNfc.prototype = {
|
||||
status, requestId);
|
||||
},
|
||||
|
||||
startPoll: function startPoll() {
|
||||
return this._nfcContentHelper.startPoll(this._window);
|
||||
},
|
||||
|
||||
stopPoll: function stopPoll() {
|
||||
return this._nfcContentHelper.stopPoll(this._window);
|
||||
},
|
||||
|
||||
powerOff: function powerOff() {
|
||||
return this._nfcContentHelper.powerOff(this._window);
|
||||
},
|
||||
|
||||
getNFCTag: function getNFCTag(sessionToken) {
|
||||
let obj = new MozNFCTag();
|
||||
let nfcTag = this._window.MozNFCTag._create(this._window, obj);
|
||||
|
@ -3,40 +3,35 @@
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
|
||||
SpecialPowers.addPermission("nfc-manager", true, document);
|
||||
|
||||
function toggleNFC(enabled, callback) {
|
||||
isnot(callback, null);
|
||||
var settings = window.navigator.mozSettings;
|
||||
isnot(settings, null);
|
||||
ok(settings instanceof SettingsManager,
|
||||
'settings instanceof ' + settings.constructor +
|
||||
', expected SettingsManager');
|
||||
|
||||
let req = settings.createLock().get('nfc.enabled');
|
||||
let nfc = window.navigator.mozNfc;
|
||||
let req;
|
||||
if (enabled) {
|
||||
req = nfc.startPoll();
|
||||
} else {
|
||||
req = nfc.powerOff();
|
||||
}
|
||||
|
||||
req.onsuccess = function() {
|
||||
if (req.result['nfc.enabled'] === enabled) {
|
||||
callback();
|
||||
} else {
|
||||
let req = settings.createLock().set({'nfc.enabled': enabled});
|
||||
req.onsuccess = function() {
|
||||
window.setTimeout(callback, 5000); // give emulator time to toggle NFC
|
||||
};
|
||||
req.onerror = function() {
|
||||
ok(false,
|
||||
'Setting \'nfc.enabled\' to \'' + enabled +
|
||||
'\' failed, error ' + req.error.name);
|
||||
finish();
|
||||
};
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, 'Getting \'nfc.enabled\' failed, error ' + req.error.name);
|
||||
ok(false, 'operation failed, error ' + req.error.name);
|
||||
finish();
|
||||
};
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
log('Cleaning up');
|
||||
waitFor(finish(),
|
||||
waitFor(function() {
|
||||
SpecialPowers.removePermission("nfc-manager", document);
|
||||
finish()
|
||||
},
|
||||
function() {
|
||||
return pendingEmulatorCmdCount === 0;
|
||||
});
|
||||
|
@ -33,5 +33,4 @@ let tests = [
|
||||
testConstructNDEF
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'settings', 'allow': true, 'context': document}], runTests);
|
||||
runTests();
|
||||
|
@ -4,20 +4,52 @@
|
||||
MARIONETTE_TIMEOUT = 30000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
let nfc = window.navigator.mozNfc;
|
||||
function testEnableNFC() {
|
||||
log('Running \'testEnableNFC\'');
|
||||
toggleNFC(true, runNextTest);
|
||||
let req = nfc.startPoll();
|
||||
req.onsuccess = function () {
|
||||
ok(true);
|
||||
runNextTest();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "startPoll failed");
|
||||
runNextTest();
|
||||
};
|
||||
}
|
||||
|
||||
function testDisableNFC() {
|
||||
log('Running \'testDisableNFC\'');
|
||||
toggleNFC(false, runNextTest);
|
||||
let req = nfc.powerOff();
|
||||
req.onsuccess = function () {
|
||||
ok(true);
|
||||
runNextTest();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "powerOff failed");
|
||||
runNextTest();
|
||||
};
|
||||
}
|
||||
|
||||
function testStopPollNFC() {
|
||||
log('Running \'testStopPollNFC\'');
|
||||
let req = nfc.stopPoll();
|
||||
req.onsuccess = function () {
|
||||
ok(true);
|
||||
runNextTest();
|
||||
};
|
||||
req.onerror = function () {
|
||||
ok(false, "stopPoll failed");
|
||||
runNextTest();
|
||||
};
|
||||
}
|
||||
|
||||
let tests = [
|
||||
testEnableNFC,
|
||||
testStopPollNFC,
|
||||
testDisableNFC
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'settings', 'allow': true, 'context': document}], runTests);
|
||||
[{'type': 'nfc-manager', 'allow': true, 'context': document}],
|
||||
runTests);
|
||||
|
@ -33,5 +33,4 @@ let tests = [
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'nfc-manager', 'allow': true, context: document},
|
||||
{'type': 'settings', 'allow': true, context: document}], runTests);
|
||||
[{'type': 'nfc-manager', 'allow': true, context: document}], runTests);
|
||||
|
@ -20,6 +20,8 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug
|
||||
[test_camera.html]
|
||||
disabled = disabled until bug 859593 is fixed
|
||||
[test_keyboard.html]
|
||||
skip-if = buildapp != 'b2g'
|
||||
skip-if = toolkit == 'android'
|
||||
[test_input-manage.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_wifi-manage.html]
|
||||
skip-if = (buildapp != 'b2g') || (buildapp == 'b2g' && toolkit != 'gonk') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
|
68
dom/permission/tests/test_input-manage.html
Normal file
68
dom/permission/tests/test_input-manage.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=920977
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 920977 </title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=920977">Mozilla Bug 920977 </a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
function verifier(success, failure) {
|
||||
try {
|
||||
if (!this.getObj()) {
|
||||
failure("Did not receive proper object");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
failure("Received exception!: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.getObj().removeFocus();
|
||||
} catch (e) {
|
||||
failure("Received exception!: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("mozbrowser", true);
|
||||
iframe.src = "http://example.org/";
|
||||
iframe.addEventListener("load", function() {
|
||||
iframe.removeEventListener("load", arguments.callee);
|
||||
if (iframe.setInputMethodActive &&
|
||||
typeof iframe.setInputMethodActive == "function") {
|
||||
success("Got setInputMethodActive");
|
||||
} else {
|
||||
failure("Didn't get setInputMethodActive") ;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('content').appendChild(iframe);
|
||||
}
|
||||
|
||||
var gData = [
|
||||
{
|
||||
perm: ["input-manage", "browser"],
|
||||
needParentPerm: true,
|
||||
obj: "mozInputMethod",
|
||||
webidl: "MozInputMethod",
|
||||
settings: [["dom.mozInputMethod.enabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true]],
|
||||
verifier: verifier.toSource()
|
||||
}
|
||||
]
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -16,17 +16,32 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=920977
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
function verifier(success, failure) {
|
||||
try {
|
||||
if (!this.getObj()) {
|
||||
failure("Did not receive proper object");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
failure("Received exception!: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.getObj().removeFocus();
|
||||
failure("Should receive exception when accessing system only method.!");
|
||||
} catch (e) {
|
||||
success(this.perm);
|
||||
}
|
||||
}
|
||||
|
||||
var gData = [
|
||||
{
|
||||
perm: ["input"],
|
||||
obj: "mozInputMethod",
|
||||
webidl: "MozInputMethod",
|
||||
settings: [["dom.mozInputMethod.enabled", true]],
|
||||
},
|
||||
{
|
||||
perm: ["input-manage"],
|
||||
obj: "mozKeyboard",
|
||||
idl: "nsIB2GKeyboard",
|
||||
verifier: verifier.toSource()
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
@ -55,6 +55,28 @@ PersistenceTypeFromText(const nsACString& aText)
|
||||
MOZ_ASSUME_UNREACHABLE("Should never get here!");
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
NullablePersistenceTypeFromText(const nsACString& aText,
|
||||
Nullable<PersistenceType> *aPersistenceType)
|
||||
{
|
||||
if (aText.IsVoid()) {
|
||||
*aPersistenceType = Nullable<PersistenceType>();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aText.EqualsLiteral("persistent")) {
|
||||
*aPersistenceType = Nullable<PersistenceType>(PERSISTENCE_TYPE_PERSISTENT);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aText.EqualsLiteral("temporary")) {
|
||||
*aPersistenceType = Nullable<PersistenceType>(PERSISTENCE_TYPE_TEMPORARY);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
inline mozilla::dom::StorageType
|
||||
PersistenceTypeToStorage(PersistenceType aPersistenceType)
|
||||
{
|
||||
|
@ -188,8 +188,10 @@ class OriginClearRunnable MOZ_FINAL : public nsRunnable,
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
OriginClearRunnable(const OriginOrPatternString& aOriginOrPattern)
|
||||
OriginClearRunnable(const OriginOrPatternString& aOriginOrPattern,
|
||||
Nullable<PersistenceType> aPersistenceType)
|
||||
: mOriginOrPattern(aOriginOrPattern),
|
||||
mPersistenceType(aPersistenceType),
|
||||
mCallbackState(Pending)
|
||||
{ }
|
||||
|
||||
@ -228,6 +230,7 @@ public:
|
||||
|
||||
private:
|
||||
OriginOrPatternString mOriginOrPattern;
|
||||
Nullable<PersistenceType> mPersistenceType;
|
||||
CallbackState mCallbackState;
|
||||
};
|
||||
|
||||
@ -2280,6 +2283,7 @@ NS_IMETHODIMP
|
||||
QuotaManager::ClearStoragesForURI(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
bool aInMozBrowserOnly,
|
||||
const nsACString& aPersistenceType,
|
||||
uint8_t aOptionalArgCount)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
@ -2302,19 +2306,23 @@ QuotaManager::ClearStoragesForURI(nsIURI* aURI,
|
||||
nsAutoCString pattern;
|
||||
GetOriginPatternString(aAppId, aInMozBrowserOnly, origin, pattern);
|
||||
|
||||
Nullable<PersistenceType> persistenceType;
|
||||
rv = NullablePersistenceTypeFromText(aPersistenceType, &persistenceType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If there is a pending or running clear operation for this origin, return
|
||||
// immediately.
|
||||
if (IsClearOriginPending(pattern)) {
|
||||
if (IsClearOriginPending(pattern, persistenceType)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
|
||||
|
||||
// Queue up the origin clear runnable.
|
||||
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
|
||||
nsRefPtr<OriginClearRunnable> runnable =
|
||||
new OriginClearRunnable(oops, persistenceType);
|
||||
|
||||
rv = WaitForOpenAllowed(oops, Nullable<PersistenceType>(), EmptyCString(),
|
||||
runnable);
|
||||
rv = WaitForOpenAllowed(oops, persistenceType, EmptyCString(), runnable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable->AdvanceState();
|
||||
@ -2324,10 +2332,13 @@ QuotaManager::ClearStoragesForURI(nsIURI* aURI,
|
||||
matches.Find(mLiveStorages, pattern);
|
||||
|
||||
for (uint32_t index = 0; index < matches.Length(); index++) {
|
||||
// We need to grab references to any live storages here to prevent them
|
||||
// from dying while we invalidate them.
|
||||
nsCOMPtr<nsIOfflineStorage> storage = matches[index];
|
||||
storage->Invalidate();
|
||||
if (persistenceType.IsNull() ||
|
||||
matches[index]->Type() == persistenceType.Value()) {
|
||||
// We need to grab references to any live storages here to prevent them
|
||||
// from dying while we invalidate them.
|
||||
nsCOMPtr<nsIOfflineStorage> storage = matches[index];
|
||||
storage->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// After everything has been invalidated the helper should be dispatched to
|
||||
@ -2640,6 +2651,7 @@ QuotaManager::LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
|
||||
nsresult
|
||||
QuotaManager::AcquireExclusiveAccess(const nsACString& aPattern,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
nsIOfflineStorage* aStorage,
|
||||
AcquireListener* aListener,
|
||||
WaitingOnStoragesCallback aCallback,
|
||||
@ -2649,16 +2661,9 @@ QuotaManager::AcquireExclusiveAccess(const nsACString& aPattern,
|
||||
NS_ASSERTION(aListener, "Need a listener!");
|
||||
|
||||
// Find the right SynchronizedOp.
|
||||
SynchronizedOp* op;
|
||||
if (aStorage) {
|
||||
op = FindSynchronizedOp(aPattern,
|
||||
Nullable<PersistenceType>(aStorage->Type()),
|
||||
aStorage->Id());
|
||||
}
|
||||
else {
|
||||
op = FindSynchronizedOp(aPattern, Nullable<PersistenceType>(),
|
||||
EmptyCString());
|
||||
}
|
||||
SynchronizedOp* op =
|
||||
FindSynchronizedOp(aPattern, aPersistenceType,
|
||||
aStorage ? aStorage->Id() : EmptyCString());
|
||||
|
||||
NS_ASSERTION(op, "We didn't find a SynchronizedOp?");
|
||||
NS_ASSERTION(!op->mListener, "SynchronizedOp already has a listener?!?");
|
||||
@ -2840,20 +2845,23 @@ QuotaManager::ClearStoragesForApp(uint32_t aAppId, bool aBrowserOnly)
|
||||
nsAutoCString pattern;
|
||||
GetOriginPatternStringMaybeIgnoreBrowser(aAppId, aBrowserOnly, pattern);
|
||||
|
||||
// Clear both temporary and persistent storages.
|
||||
Nullable<PersistenceType> persistenceType;
|
||||
|
||||
// If there is a pending or running clear operation for this app, return
|
||||
// immediately.
|
||||
if (IsClearOriginPending(pattern)) {
|
||||
if (IsClearOriginPending(pattern, persistenceType)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
|
||||
|
||||
// Queue up the origin clear runnable.
|
||||
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
|
||||
nsRefPtr<OriginClearRunnable> runnable =
|
||||
new OriginClearRunnable(oops, persistenceType);
|
||||
|
||||
nsresult rv =
|
||||
WaitForOpenAllowed(oops, Nullable<PersistenceType>(), EmptyCString(),
|
||||
runnable);
|
||||
WaitForOpenAllowed(oops, persistenceType, EmptyCString(), runnable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable->AdvanceState();
|
||||
@ -3507,8 +3515,9 @@ OriginClearRunnable::Run()
|
||||
// Now we have to wait until the thread pool is done with all of the
|
||||
// storages we care about.
|
||||
nsresult rv =
|
||||
quotaManager->AcquireExclusiveAccess(mOriginOrPattern, this,
|
||||
InvalidateOpenedStorages, nullptr);
|
||||
quotaManager->AcquireExclusiveAccess(mOriginOrPattern, mPersistenceType,
|
||||
this, InvalidateOpenedStorages,
|
||||
nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@ -3519,9 +3528,12 @@ OriginClearRunnable::Run()
|
||||
|
||||
AdvanceState();
|
||||
|
||||
DeleteFiles(quotaManager, PERSISTENCE_TYPE_PERSISTENT);
|
||||
|
||||
DeleteFiles(quotaManager, PERSISTENCE_TYPE_TEMPORARY);
|
||||
if (mPersistenceType.IsNull()) {
|
||||
DeleteFiles(quotaManager, PERSISTENCE_TYPE_PERSISTENT);
|
||||
DeleteFiles(quotaManager, PERSISTENCE_TYPE_TEMPORARY);
|
||||
} else {
|
||||
DeleteFiles(quotaManager, mPersistenceType.Value());
|
||||
}
|
||||
|
||||
// Now dispatch back to the main thread.
|
||||
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
|
||||
@ -3536,8 +3548,7 @@ OriginClearRunnable::Run()
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
// Tell the QuotaManager that we're done.
|
||||
quotaManager->AllowNextSynchronizedOp(mOriginOrPattern,
|
||||
Nullable<PersistenceType>(),
|
||||
quotaManager->AllowNextSynchronizedOp(mOriginOrPattern, mPersistenceType,
|
||||
EmptyCString());
|
||||
|
||||
return NS_OK;
|
||||
@ -3863,7 +3874,8 @@ ResetOrClearRunnable::Run()
|
||||
// Now we have to wait until the thread pool is done with all of the
|
||||
// storages we care about.
|
||||
nsresult rv =
|
||||
quotaManager->AcquireExclusiveAccess(NullCString(), this,
|
||||
quotaManager->AcquireExclusiveAccess(NullCString(),
|
||||
Nullable<PersistenceType>(), this,
|
||||
InvalidateOpenedStorages, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -198,23 +198,25 @@ public:
|
||||
nsresult
|
||||
AcquireExclusiveAccess(nsIOfflineStorage* aStorage,
|
||||
const nsACString& aOrigin,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
AcquireListener* aListener,
|
||||
WaitingOnStoragesCallback aCallback,
|
||||
void* aClosure)
|
||||
{
|
||||
NS_ASSERTION(aStorage, "Need a storage here!");
|
||||
return AcquireExclusiveAccess(aOrigin, aStorage, aListener, aCallback,
|
||||
aClosure);
|
||||
return AcquireExclusiveAccess(aOrigin, aPersistenceType, aStorage,
|
||||
aListener, aCallback, aClosure);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AcquireExclusiveAccess(const nsACString& aOrigin,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
AcquireListener* aListener,
|
||||
WaitingOnStoragesCallback aCallback,
|
||||
void* aClosure)
|
||||
{
|
||||
return AcquireExclusiveAccess(aOrigin, nullptr, aListener, aCallback,
|
||||
aClosure);
|
||||
return AcquireExclusiveAccess(aOrigin, aPersistenceType, nullptr,
|
||||
aListener, aCallback, aClosure);
|
||||
}
|
||||
|
||||
void
|
||||
@ -223,10 +225,10 @@ public:
|
||||
const nsACString& aId);
|
||||
|
||||
bool
|
||||
IsClearOriginPending(const nsACString& aPattern)
|
||||
IsClearOriginPending(const nsACString& aPattern,
|
||||
Nullable<PersistenceType> aPersistenceType)
|
||||
{
|
||||
return !!FindSynchronizedOp(aPattern, Nullable<PersistenceType>(),
|
||||
EmptyCString());
|
||||
return !!FindSynchronizedOp(aPattern, aPersistenceType, EmptyCString());
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -369,6 +371,7 @@ private:
|
||||
|
||||
nsresult
|
||||
AcquireExclusiveAccess(const nsACString& aOrigin,
|
||||
Nullable<PersistenceType> aPersistenceType,
|
||||
nsIOfflineStorage* aStorage,
|
||||
AcquireListener* aListener,
|
||||
WaitingOnStoragesCallback aCallback,
|
||||
|
@ -10,7 +10,7 @@ interface nsIQuotaRequest;
|
||||
interface nsIURI;
|
||||
interface nsIUsageCallback;
|
||||
|
||||
[scriptable, builtinclass, uuid(f19a03ae-e97d-41e9-95dd-681b910c4093)]
|
||||
[scriptable, builtinclass, uuid(2968fcd5-1872-4ddc-8c16-62b27e357f31)]
|
||||
interface nsIQuotaManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -51,7 +51,8 @@ interface nsIQuotaManager : nsISupports
|
||||
void
|
||||
clearStoragesForURI(in nsIURI aURI,
|
||||
[optional] in unsigned long aAppId,
|
||||
[optional] in boolean aInMozBrowserOnly);
|
||||
[optional] in boolean aInMozBrowserOnly,
|
||||
[optional] in ACString aPersistenceType);
|
||||
|
||||
/**
|
||||
* Resets quota and storage management. This can be used to force
|
||||
|
@ -66,7 +66,10 @@ const NFC_IPC_WRITE_PERM_MSG_NAMES = [
|
||||
const NFC_IPC_MANAGER_PERM_MSG_NAMES = [
|
||||
"NFC:CheckP2PRegistration",
|
||||
"NFC:NotifyUserAcceptedP2P",
|
||||
"NFC:NotifySendFileStatus"
|
||||
"NFC:NotifySendFileStatus",
|
||||
"NFC:StartPoll",
|
||||
"NFC:StopPoll",
|
||||
"NFC:PowerOff"
|
||||
];
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
@ -420,6 +423,7 @@ function Nfc() {
|
||||
lock.get(NFC.SETTING_NFC_ENABLED, this);
|
||||
// Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
|
||||
this.sessionTokenMap = {};
|
||||
this.targetsByRequestId = {};
|
||||
|
||||
gSystemWorkerManager.registerNfcWorker(this.worker);
|
||||
}
|
||||
@ -516,7 +520,14 @@ Nfc.prototype = {
|
||||
this.currentPeerAppId = null;
|
||||
break;
|
||||
case "ConfigResponse":
|
||||
gSystemMessenger.broadcastMessage("nfc-powerlevel-change", message);
|
||||
let target = this.targetsByRequestId[message.requestId];
|
||||
if (!target) {
|
||||
debug("No target for requestId: " + message.requestId);
|
||||
return;
|
||||
}
|
||||
delete this.targetsByRequestId[message.requestId];
|
||||
|
||||
target.sendAsyncMessage("NFC:ConfigResponse", message);
|
||||
break;
|
||||
case "ConnectResponse": // Fall through.
|
||||
case "CloseResponse":
|
||||
@ -539,12 +550,32 @@ Nfc.prototype = {
|
||||
|
||||
sessionTokenMap: null,
|
||||
|
||||
targetsByRequestId: null,
|
||||
|
||||
/**
|
||||
* Process a message from the content process.
|
||||
*/
|
||||
receiveMessage: function receiveMessage(message) {
|
||||
debug("Received '" + JSON.stringify(message) + "' message from content process");
|
||||
|
||||
// Handle messages without sessionToken.
|
||||
if (message.name == "NFC:StartPoll") {
|
||||
this.targetsByRequestId[message.json.requestId] = message.target;
|
||||
this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_ENABLED,
|
||||
requestId: message.json.requestId});
|
||||
return null;
|
||||
} else if (message.name == "NFC:StopPoll") {
|
||||
this.targetsByRequestId[message.json.requestId] = message.target;
|
||||
this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_LOW,
|
||||
requestId: message.json.requestId});
|
||||
return null;
|
||||
} else if (message.name == "NFC:PowerOff") {
|
||||
this.targetsByRequestId[message.json.requestId] = message.target;
|
||||
this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_DISABLED,
|
||||
requestId: message.json.requestId});
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._enabled) {
|
||||
debug("NFC is not enabled.");
|
||||
this.sendNfcErrorResponse(message);
|
||||
|
@ -54,7 +54,7 @@ const NFC_IPC_MSG_NAMES = [
|
||||
"NFC:CheckP2PRegistrationResponse",
|
||||
"NFC:PeerEvent",
|
||||
"NFC:NotifySendFileStatusResponse",
|
||||
"NFC:SendFileResponse"
|
||||
"NFC:ConfigResponse"
|
||||
];
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
@ -314,6 +314,51 @@ NfcContentHelper.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
startPoll: function startPoll(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = btoa(this.getRequestId(request));
|
||||
this._requestMap[requestId] = window;
|
||||
|
||||
cpmm.sendAsyncMessage("NFC:StartPoll",
|
||||
{requestId: requestId});
|
||||
return request;
|
||||
},
|
||||
|
||||
stopPoll: function stopPoll(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = btoa(this.getRequestId(request));
|
||||
this._requestMap[requestId] = window;
|
||||
|
||||
cpmm.sendAsyncMessage("NFC:StopPoll",
|
||||
{requestId: requestId});
|
||||
return request;
|
||||
},
|
||||
|
||||
powerOff: function powerOff(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = btoa(this.getRequestId(request));
|
||||
this._requestMap[requestId] = window;
|
||||
|
||||
cpmm.sendAsyncMessage("NFC:PowerOff",
|
||||
{requestId: requestId});
|
||||
return request;
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function observe(subject, topic, data) {
|
||||
if (topic == "xpcom-shutdown") {
|
||||
@ -368,6 +413,7 @@ NfcContentHelper.prototype = {
|
||||
case "NFC:MakeReadOnlyNDEFResponse":
|
||||
case "NFC:CheckP2PRegistrationResponse":
|
||||
case "NFC:NotifySendFileStatusResponse":
|
||||
case "NFC:ConfigResponse":
|
||||
if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
|
||||
this.fireRequestError(atob(result.requestId), result.status);
|
||||
} else {
|
||||
|
@ -24,7 +24,7 @@ interface nsINfcPeerCallback : nsISupports
|
||||
in DOMString sessionToken);
|
||||
};
|
||||
|
||||
[scriptable, uuid(70cac000-7e3c-11e3-baa7-0800200c9a66)]
|
||||
[scriptable, uuid(10b2eb1b-3fe0-4c98-9c67-9e4c2274cd78)]
|
||||
interface nsINfcContentHelper : nsISupports
|
||||
{
|
||||
const long NFC_EVENT_PEER_READY = 0x01;
|
||||
@ -135,4 +135,19 @@ interface nsINfcContentHelper : nsISupports
|
||||
void notifySendFileStatus(in nsIDOMWindow window,
|
||||
in octet status,
|
||||
in DOMString requestId);
|
||||
|
||||
/**
|
||||
* Power on the NFC hardware and start polling for NFC tags or devices.
|
||||
*/
|
||||
nsIDOMDOMRequest startPoll(in nsIDOMWindow window);
|
||||
|
||||
/**
|
||||
* Stop polling for NFC tags or devices. i.e. enter low power mode.
|
||||
*/
|
||||
nsIDOMDOMRequest stopPoll(in nsIDOMWindow window);
|
||||
|
||||
/**
|
||||
* Power off the NFC hardware.
|
||||
*/
|
||||
nsIDOMDOMRequest powerOff(in nsIDOMWindow window);
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
interface WindowProxy;
|
||||
|
||||
[Constructor(DOMString typeArg, optional KeyboardEventInit keyboardEventInitDict)]
|
||||
interface KeyboardEvent : UIEvent
|
||||
{
|
||||
readonly attribute unsigned long charCode;
|
||||
@ -30,6 +31,34 @@ interface KeyboardEvent : UIEvent
|
||||
readonly attribute boolean isComposing;
|
||||
|
||||
readonly attribute DOMString key;
|
||||
|
||||
[Throws]
|
||||
void initKeyboardEvent(DOMString typeArg,
|
||||
boolean bubblesArg,
|
||||
boolean cancelableArg,
|
||||
WindowProxy? viewArg,
|
||||
long detailArg,
|
||||
DOMString keyArg,
|
||||
unsigned long locationArg,
|
||||
DOMString modifiersListArg,
|
||||
boolean repeatArg);
|
||||
};
|
||||
|
||||
dictionary KeyboardEventInit : UIEventInit
|
||||
{
|
||||
DOMString key = "";
|
||||
unsigned long location = 0;
|
||||
boolean ctrlKey = false;
|
||||
boolean shiftKey = false;
|
||||
boolean altKey = false;
|
||||
boolean metaKey = false;
|
||||
boolean repeat = false;
|
||||
boolean isComposing = false;
|
||||
|
||||
// legacy attributes
|
||||
unsigned long charCode = 0;
|
||||
unsigned long keyCode = 0;
|
||||
unsigned long which = 0;
|
||||
};
|
||||
|
||||
// Mozilla extensions
|
||||
|
@ -25,6 +25,21 @@ interface MozNfcManager {
|
||||
* Notify the status of sendFile operation
|
||||
*/
|
||||
void notifySendFileStatus(octet status, DOMString requestId);
|
||||
|
||||
/**
|
||||
* Power on the NFC hardware and start polling for NFC tags or devices.
|
||||
*/
|
||||
DOMRequest startPoll();
|
||||
|
||||
/**
|
||||
* Stop polling for NFC tags or devices. i.e. enter low power mode.
|
||||
*/
|
||||
DOMRequest stopPoll();
|
||||
|
||||
/**
|
||||
* Power off the NFC hardware.
|
||||
*/
|
||||
DOMRequest powerOff();
|
||||
};
|
||||
|
||||
[JSImplementation="@mozilla.org/navigatorNfc;1",
|
||||
|
@ -957,6 +957,8 @@ GetOrCreateMapEntryForPrototype(JSContext *cx, JS::Handle<JSObject*> proto)
|
||||
}
|
||||
JS::Rooted<JS::Value> entryVal(cx, JS::ObjectValue(*entry));
|
||||
if (!JS::SetWeakMapEntry(cx, map, wrappedProto, entryVal)) {
|
||||
NS_WARNING("SetWeakMapEntry failed, probably due to non-preservable WeakMap "
|
||||
"key. XBL binding will fail for this element.");
|
||||
return nullptr;
|
||||
}
|
||||
return entry;
|
||||
@ -997,6 +999,9 @@ nsXBLBinding::DoInitJSClass(JSContext *cx,
|
||||
JSAutoCompartment innerAC(cx, xblScope);
|
||||
holder = GetOrCreateClassObjectMap(cx, xblScope, "__ContentClassObjectMap__");
|
||||
}
|
||||
if (NS_WARN_IF(!holder)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
js::AssertSameCompartment(holder, xblScope);
|
||||
JSAutoCompartment ac(cx, holder);
|
||||
|
||||
|
@ -1032,7 +1032,7 @@ public:
|
||||
*/
|
||||
static bool CheckSurfaceSize(const IntSize &sz, int32_t limit = 0);
|
||||
|
||||
static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize);
|
||||
static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
|
||||
|
||||
static TemporaryRef<SourceSurface>
|
||||
CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface,
|
||||
|
@ -1157,12 +1157,12 @@ DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFo
|
||||
}
|
||||
|
||||
bool
|
||||
DrawTargetCairo::InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize)
|
||||
DrawTargetCairo::InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
|
||||
{
|
||||
mContext = cairo_create(aSurface);
|
||||
mSurface = aSurface;
|
||||
mSize = aSize;
|
||||
mFormat = CairoContentToGfxFormat(cairo_surface_get_content(aSurface));
|
||||
mFormat = aFormat ? *aFormat : CairoContentToGfxFormat(cairo_surface_get_content(aSurface));
|
||||
|
||||
if (mFormat == SurfaceFormat::B8G8R8A8 ||
|
||||
mFormat == SurfaceFormat::R8G8B8A8) {
|
||||
@ -1218,10 +1218,10 @@ DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFor
|
||||
}
|
||||
|
||||
bool
|
||||
DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize)
|
||||
DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
|
||||
{
|
||||
cairo_surface_reference(aSurface);
|
||||
return InitAlreadyReferenced(aSurface, aSize);
|
||||
return InitAlreadyReferenced(aSurface, aSize, aFormat);
|
||||
}
|
||||
|
||||
bool
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user