Merge m-c to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2014-04-15 15:17:48 +02:00
commit acba6fe86f
209 changed files with 21335 additions and 1129 deletions

View File

@ -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));

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "a54e097e9e3384d885c0116d9c4ca15c1e1cd75e",
"revision": "c766bc0d49af19f18788ad8ed0542b82db81f1d8",
"repo_path": "/integration/gaia-central"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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

View File

@ -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',

View File

@ -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"

View File

@ -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"

View File

@ -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"
}
]

View File

@ -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

View File

@ -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

View File

@ -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'):

View File

@ -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

View File

@ -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)
{

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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>

View 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");
}

View 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>

View File

@ -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]

View File

@ -33,7 +33,7 @@ function runTest() {
else
renderFailure(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -65,7 +65,7 @@ function runTest() {
else
renderFailure(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -60,7 +60,7 @@ function runTest() {
else
renderFailure(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -44,7 +44,7 @@ function runTest() {
else
renderBackup(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -42,7 +42,7 @@ function runTest() {
else
renderFailure(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -41,7 +41,7 @@ function runTest() {
else
renderFailure(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -41,7 +41,7 @@ function runTest() {
else
renderFailure(canvas);
rAF(testComplete);
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -42,7 +42,7 @@ function runTest() {
else
renderFailure(canvas);
testComplete();
waitForComposite(testComplete);
}
function testComplete() {

View File

@ -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);
}

View 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>

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);

View File

@ -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 \

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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");

View File

@ -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 {

View File

@ -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;
}

View File

@ -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);

View File

@ -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}

View File

@ -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;

View File

@ -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]);

View File

@ -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']

View File

@ -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);
};

View File

@ -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)
{

View File

@ -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.

View File

@ -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);

View File

@ -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;
});

View File

@ -33,5 +33,4 @@ let tests = [
testConstructNDEF
];
SpecialPowers.pushPermissions(
[{'type': 'settings', 'allow': true, 'context': document}], runTests);
runTests();

View File

@ -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);

View File

@ -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);

View File

@ -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)

View 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>

View File

@ -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>

View File

@ -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)
{

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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);
};

View File

@ -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

View File

@ -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",

View File

@ -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);

View File

@ -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,

View File

@ -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