Merge m-c to fx-team, a=merge

This commit is contained in:
Wes Kocher 2016-01-21 17:37:58 -08:00
commit 8dfdddf741
197 changed files with 4244 additions and 12153 deletions

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee",
"git_revision": "89602d6ae53ecf4129b35a84e49d25b9fd37bc39",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "d74e738cd626558fb9dc289500ad28ae29deab03",
"revision": "ea9b9cc69315e86bf7198ec0d57a267e64345b32",
"repo_path": "integration/gaia-central"
}

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -494,7 +494,7 @@
</div>
<div id="learnMoreContainer">
<p><a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
<p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
</div>
<div id="buttonContainer">

View File

@ -272,7 +272,7 @@
</div>
<p id="badStsCertExplanation">&certerror.whatShouldIDo.badStsCertExplanation;</p>
<div>
<p><a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&certerror.learnMore;</a></p>
<p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new">&certerror.learnMore;</a></p>
</div>
<div id="buttonContainer">

View File

@ -463,14 +463,19 @@ endif
endif
ifdef SYMBOLS_FILE
ifeq ($(OS_TARGET),WINNT)
ifndef GNU_CC
EXTRA_DSO_LDOPTS += -DEF:$(call normalizepath,$(SYMBOLS_FILE))
else
EXTRA_DSO_LDOPTS += $(call normalizepath,$(SYMBOLS_FILE))
endif
else
ifdef GCC_USE_GNU_LD
EXTRA_DSO_LDOPTS += -Wl,--version-script,$(SYMBOLS_FILE)
else
ifeq ($(OS_TARGET),Darwin)
EXTRA_DSO_LDOPTS += -Wl,-exported_symbols_list,$(SYMBOLS_FILE)
endif
ifeq ($(OS_TARGET),WINNT)
EXTRA_DSO_LDOPTS += -DEF:$(call normalizepath,$(SYMBOLS_FILE))
endif
endif
EXTRA_DEPS += $(SYMBOLS_FILE)

View File

@ -75,7 +75,7 @@ GNOMEUI_VERSION=2.2.0
GCONF_VERSION=1.2.1
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.10.1
SQLITE_VERSION=3.10.2
MSMANIFEST_TOOL=
@ -3746,7 +3746,7 @@ if test -n "$MOZ_FMP4"; then
else
MOZ_FMP4=
fi
MOZ_FFMPEG=1
MOZ_FFMPEG=
MOZ_WEBRTC=1
MOZ_PEERCONNECTION=
MOZ_SRTP=
@ -5226,6 +5226,14 @@ fi;
dnl ========================================================
dnl FFmpeg H264/AAC Decoding Support
dnl ========================================================
case "$OS_TARGET" in
WINNT|Android)
;;
*)
MOZ_FFMPEG=1
;;
esac
MOZ_ARG_DISABLE_BOOL(ffmpeg,
[ --disable-ffmpeg Disable FFmpeg for fragmented H264/AAC decoding],
MOZ_FFMPEG=,

View File

@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.10.1. By combining all the individual C code files into this
** version 3.10.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@ -325,9 +325,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.10.1"
#define SQLITE_VERSION_NUMBER 3010001
#define SQLITE_SOURCE_ID "2016-01-13 21:41:56 254419c36766225ca542ae873ed38255e3fb8588"
#define SQLITE_VERSION "3.10.2"
#define SQLITE_VERSION_NUMBER 3010002
#define SQLITE_SOURCE_ID "2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -49045,7 +49045,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
if( rc!=SQLITE_OK ){
return rc;
}
sqlite3WalExclusiveMode(pPager->pWal, 1);
(void)sqlite3WalExclusiveMode(pPager->pWal, 1);
}
/* Grab the write lock on the log file. If successful, upgrade to
@ -50115,7 +50115,11 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
** This will be either the rollback journal or the WAL file.
*/
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
#if SQLITE_OMIT_WAL
return pPager->jfd;
#else
return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
#endif
}
/*
@ -100279,7 +100283,7 @@ static int patternCompare(
}
c2 = Utf8Read(zString);
if( c==c2 ) continue;
if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
continue;
}
if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
@ -135026,7 +135030,6 @@ static int openDatabase(
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
opendb_out:
sqlite3_free(zOpen);
if( db ){
assert( db->mutex!=0 || isThreadsafe==0
|| sqlite3GlobalConfig.bFullMutex==0 );
@ -135063,6 +135066,7 @@ opendb_out:
}
}
#endif
sqlite3_free(zOpen);
return rc & 0xff;
}
@ -182280,7 +182284,7 @@ static void fts5SourceIdFunc(
sqlite3_value **apVal /* Function arguments */
){
assert( nArg==0 );
sqlite3_result_text(pCtx, "fts5: 2016-01-13 21:41:56 254419c36766225ca542ae873ed38255e3fb8588", -1, SQLITE_TRANSIENT);
sqlite3_result_text(pCtx, "fts5: 2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9", -1, SQLITE_TRANSIENT);
}
static int fts5Init(sqlite3 *db){

View File

@ -111,9 +111,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.10.1"
#define SQLITE_VERSION_NUMBER 3010001
#define SQLITE_SOURCE_ID "2016-01-13 21:41:56 254419c36766225ca542ae873ed38255e3fb8588"
#define SQLITE_VERSION "3.10.2"
#define SQLITE_VERSION_NUMBER 3010002
#define SQLITE_SOURCE_ID "2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9"
/*
** CAPI3REF: Run-Time Library Version Numbers

View File

@ -31,7 +31,7 @@ class nsDOMNavigationTiming;
[ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming);
[ref] native nsIContentViewerTArray(nsTArray<nsCOMPtr<nsIContentViewer> >);
[scriptable, builtinclass, uuid(91b6c1f3-fc5f-43a9-88f4-9286bd19387f)]
[scriptable, builtinclass, uuid(2da17016-7851-4a45-a7a8-00b360e01595)]
interface nsIContentViewer : nsISupports
{
[noscript] void init(in nsIWidgetPtr aParentWidget,
@ -229,6 +229,18 @@ interface nsIContentViewer : nsISupports
*/
[noscript] void appendSubtree(in nsIContentViewerTArray array);
/**
* Instruct the refresh driver to discontinue painting until further
* notice.
*/
void pausePainting();
/**
* Instruct the refresh driver to resume painting after a previous call to
* pausePainting().
*/
void resumePainting();
/*
* Render the document as if being viewed on a device with the specified
* media type. This will cause a reflow.

View File

@ -27,6 +27,7 @@ support-files =
file_bug234628-9-child.html
file_bug234628-9.html
file_bug420605.html
file_bug422543_script.js
file_bug503832.html
file_bug655270.html
file_bug670318.html
@ -59,13 +60,10 @@ support-files =
[browser_bug234628-8.js]
[browser_bug234628-9.js]
[browser_bug349769.js]
skip-if = e10s # Bug ?????? - test touches content (newBrowser.contentDocument.nodePrincipal)
[browser_bug388121-1.js]
skip-if = e10s # Bug ?????? - test touches content (newBrowser.contentDocument.nodePrincipal)
[browser_bug388121-2.js]
[browser_bug420605.js]
[browser_bug422543.js]
skip-if = e10s # Bug 1220927 - Test tries to do addSHistoryListener on content.
[browser_bug441169.js]
skip-if = buildapp == 'mulet'
[browser_bug503832.js]
@ -74,7 +72,6 @@ skip-if = buildapp == 'mulet'
[browser_bug655270.js]
[browser_bug655273.js]
[browser_bug670318.js]
skip-if = e10s # Bug 1220927 - Test tries to do addSHistoryListener on content.
[browser_bug673467.js]
[browser_bug852909.js]
[browser_bug92473.js]

View File

@ -1,44 +1,47 @@
function test() {
waitForExplicitFinish();
var newTab;
var newBrowser;
add_task(function* test() {
const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
var iteration = 1;
const uris = [undefined, "about:blank"];
var uri;
function testLoad(event) {
newBrowser.removeEventListener("load", testLoad, true);
is (event.target, newBrowser.contentDocument, "Unexpected target");
var prin = newBrowser.contentDocument.nodePrincipal;
isnot(prin, null, "Loaded principal must not be null when adding " + uri);
isnot(prin, undefined, "Loaded principal must not be undefined when loading " + uri);
is(secMan.isSystemPrincipal(prin), false,
"Loaded principal must not be system when loading " + uri);
gBrowser.removeTab(newTab);
function checkContentProcess(uri) {
yield ContentTask.spawn(newBrowser, uri, function* (uri) {
var prin = content.document.nodePrincipal;
isnot(prin, null, "Loaded principal must not be null when adding " + uri);
isnot(prin, undefined, "Loaded principal must not be undefined when loading " + uri);
if (iteration == uris.length) {
finish();
} else {
++iteration;
doTest();
}
const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
is(secMan.isSystemPrincipal(prin), false,
"Loaded principal must not be system when loading " + uri);
});
}
function doTest() {
uri = uris[iteration - 1];
newTab = gBrowser.addTab(uri);
newBrowser = gBrowser.getBrowserForTab(newTab);
newBrowser.addEventListener("load", testLoad, true);
var prin = newBrowser.contentDocument.nodePrincipal;
isnot(prin, null, "Forced principal must not be null when loading " + uri);
isnot(prin, undefined,
"Forced principal must not be undefined when loading " + uri);
is(secMan.isSystemPrincipal(prin), false,
"Forced principal must not be system when loading " + uri);
}
for (var uri of uris) {
yield BrowserTestUtils.withNewTab({ gBrowser }, function* (newBrowser) {
yield BrowserTestUtils.loadURI(newBrowser, uri);
doTest();
}
var prin = newBrowser.contentPrincipal;
isnot(prin, null, "Forced principal must not be null when loading " + uri);
isnot(prin, undefined,
"Forced principal must not be undefined when loading " + uri);
is(secMan.isSystemPrincipal(prin), false,
"Forced principal must not be system when loading " + uri);
// Belt-and-suspenders e10s check: make sure that the same checks hold
// true in the content process.
checkContentProcess(uri);
yield BrowserTestUtils.browserLoaded(newBrowser);
prin = newBrowser.contentPrincipal;
isnot(prin, null, "Loaded principal must not be null when adding " + uri);
isnot(prin, undefined, "Loaded principal must not be undefined when loading " + uri);
is(secMan.isSystemPrincipal(prin), false,
"Loaded principal must not be system when loading " + uri);
// Belt-and-suspenders e10s check: make sure that the same checks hold
// true in the content process.
checkContentProcess(uri);
});
}
});

View File

@ -1,26 +1,15 @@
function test() {
waitForExplicitFinish();
add_task(function* test() {
yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, function* (newBrowser) {
yield ContentTask.spawn(newBrowser, null, function* () {
var prin = content.document.nodePrincipal;
isnot(prin, null, "Loaded principal must not be null");
isnot(prin, undefined, "Loaded principal must not be undefined");
var newTab;
var newBrowser;
const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
function testLoad(event) {
newBrowser.removeEventListener("load", testLoad, true);
is (event.target, newBrowser.contentDocument, "Unexpected target");
var prin = newBrowser.contentDocument.nodePrincipal;
isnot(prin, null, "Loaded principal must not be null");
isnot(prin, undefined, "Loaded principal must not be undefined");
is(secMan.isSystemPrincipal(prin), false,
"Loaded principal must not be system");
gBrowser.removeTab(newTab);
finish();
}
newTab = gBrowser.addTab();
newBrowser = gBrowser.getBrowserForTab(newTab);
newBrowser.contentWindow.location.href = "about:blank"
newBrowser.addEventListener("load", testLoad, true);
}
const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
is(secMan.isSystemPrincipal(prin), false,
"Loaded principal must not be system");
});
});
});

View File

@ -1,174 +1,116 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function SHistoryListener() {
}
SHistoryListener.prototype = {
retval: true,
last: "initial",
OnHistoryNewEntry: function (aNewURI) {
this.last = "newentry";
},
OnHistoryGoBack: function (aBackURI) {
this.last = "goback";
return this.retval;
},
OnHistoryGoForward: function (aForwardURI) {
this.last = "goforward";
return this.retval;
},
OnHistoryGotoIndex: function (aIndex, aGotoURI) {
this.last = "gotoindex";
return this.retval;
},
OnHistoryPurge: function (aNumEntries) {
this.last = "purge";
return this.retval;
},
OnHistoryReload: function (aReloadURI, aReloadFlags) {
this.last = "reload";
return this.retval;
},
OnHistoryReplaceEntry: function (aIndex) {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
Ci.nsISupportsWeakReference])
};
var gFirstListener = new SHistoryListener();
var gSecondListener = new SHistoryListener();
function test() {
TestRunner.run();
}
function runTests() {
add_task(function* runTests() {
yield setup();
let browser = gBrowser.selectedBrowser;
checkListeners("initial", "listeners initialized");
// Now that we're set up, initialize our frame script.
yield checkListeners("initial", "listeners initialized");
// Check if all history listeners are always notified.
info("# part 1");
browser.loadURI("http://www.example.com/");
yield whenPageShown(browser);
checkListeners("newentry", "shistory has a new entry");
yield whenPageShown(browser, () => browser.loadURI("http://www.example.com/"));
yield checkListeners("newentry", "shistory has a new entry");
ok(browser.canGoBack, "we can go back");
browser.goBack();
yield whenPageShown(browser);
checkListeners("goback", "back to the first shentry");
yield whenPageShown(browser, () => browser.goBack());
yield checkListeners("goback", "back to the first shentry");
ok(browser.canGoForward, "we can go forward");
browser.goForward();
yield whenPageShown(browser);
checkListeners("goforward", "forward to the second shentry");
yield whenPageShown(browser, () => browser.goForward());
yield checkListeners("goforward", "forward to the second shentry");
browser.reload();
yield whenPageShown(browser);
checkListeners("reload", "current shentry reloaded");
yield whenPageShown(browser, () => browser.reload());
yield checkListeners("reload", "current shentry reloaded");
browser.gotoIndex(0);
yield whenPageShown(browser);
checkListeners("gotoindex", "back to the first index");
yield whenPageShown(browser, () => browser.gotoIndex(0));
yield checkListeners("gotoindex", "back to the first index");
// Check nsISHistoryInternal.notifyOnHistoryReload
info("# part 2");
ok(notifyReload(), "reloading has not been canceled");
checkListeners("reload", "saw the reload notification");
ok((yield notifyReload()), "reloading has not been canceled");
yield checkListeners("reload", "saw the reload notification");
// Let the first listener cancel the reload action.
info("# part 3");
resetListeners();
gFirstListener.retval = false;
ok(!notifyReload(), "reloading has been canceled");
checkListeners("reload", "saw the reload notification");
yield resetListeners();
yield setListenerRetval(0, false);
ok(!(yield notifyReload()), "reloading has been canceled");
yield checkListeners("reload", "saw the reload notification");
// Let both listeners cancel the reload action.
info("# part 4");
resetListeners();
gSecondListener.retval = false;
ok(!notifyReload(), "reloading has been canceled");
checkListeners("reload", "saw the reload notification");
yield resetListeners();
yield setListenerRetval(1, false);
ok(!(yield notifyReload()), "reloading has been canceled");
yield checkListeners("reload", "saw the reload notification");
// Let the second listener cancel the reload action.
info("# part 5");
resetListeners();
gFirstListener.retval = true;
ok(!notifyReload(), "reloading has been canceled");
checkListeners("reload", "saw the reload notification");
}
yield resetListeners();
yield setListenerRetval(0, true);
ok(!(yield notifyReload()), "reloading has been canceled");
yield checkListeners("reload", "saw the reload notification");
});
function checkListeners(aLast, aMessage) {
is(gFirstListener.last, aLast, aMessage);
is(gSecondListener.last, aLast, aMessage);
}
function resetListeners() {
gFirstListener.last = gSecondListener.last = "initial";
}
function notifyReload() {
let browser = gBrowser.selectedBrowser;
let shistory = browser.docShell.sessionHistory;
shistory.QueryInterface(Ci.nsISHistoryInternal);
return shistory.notifyOnHistoryReload(browser.currentURI, 0);
}
function setup(aCallback) {
let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla");
let browser = tab.linkedBrowser;
registerCleanupFunction(function () { gBrowser.removeTab(tab); });
whenPageShown(browser, function () {
gFirstListener = new SHistoryListener();
gSecondListener = new SHistoryListener();
let shistory = browser.docShell.sessionHistory;
shistory.addSHistoryListener(gFirstListener);
shistory.addSHistoryListener(gSecondListener);
registerCleanupFunction(function () {
shistory.removeSHistoryListener(gFirstListener);
shistory.removeSHistoryListener(gSecondListener);
function listenOnce(message, arg = {}) {
return new Promise(resolve => {
let mm = gBrowser.selectedBrowser.messageManager;
mm.addMessageListener(message + ":return", function listener(msg) {
mm.removeMessageListener(message + ":return", listener);
resolve(msg.data);
});
(aCallback || TestRunner.next)();
mm.sendAsyncMessage(message, arg);
});
}
function whenPageShown(aBrowser, aCallback) {
aBrowser.addEventListener("pageshow", function onLoad() {
aBrowser.removeEventListener("pageshow", onLoad, true);
executeSoon(aCallback || TestRunner.next);
}, true);
function checkListeners(aLast, aMessage) {
return listenOnce("bug422543:getListenerStatus").then((listenerStatuses) => {
is(listenerStatuses[0], aLast, aMessage);
is(listenerStatuses[1], aLast, aMessage);
});
}
var TestRunner = {
run: function () {
waitForExplicitFinish();
this._iter = runTests();
this.next();
},
function resetListeners() {
return listenOnce("bug422543:resetListeners");
}
next: function () {
try {
TestRunner._iter.next();
} catch (e if e instanceof StopIteration) {
TestRunner.finish();
}
},
function notifyReload() {
return listenOnce("bug422543:notifyReload").then(({ rval }) => {
return rval;
});
}
finish: function () {
finish();
}
};
function setListenerRetval(num, val) {
return listenOnce("bug422543:setRetval", { num, val });
}
function setup() {
return BrowserTestUtils.openNewForegroundTab(gBrowser,
"http://mochi.test:8888")
.then(function (tab) {
let browser = tab.linkedBrowser;
registerCleanupFunction(function* () {
yield listenOnce("bug422543:cleanup");
gBrowser.removeTab(tab);
});
browser.messageManager
.loadFrameScript(getRootDirectory(gTestPath) + "file_bug422543_script.js", false);
});
}
function whenPageShown(aBrowser, aNavigation) {
let listener = ContentTask.spawn(aBrowser, null, function () {
return new Promise(resolve => {
addEventListener("pageshow", function onLoad() {
removeEventListener("pageshow", onLoad, true);
resolve();
}, true);
});
});
aNavigation();
return listener;
}

View File

@ -10,51 +10,53 @@
const URL = "http://mochi.test:8888/browser/docshell/test/browser/file_bug670318.html";
function test() {
waitForExplicitFinish();
add_task(function* test() {
yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
function* (browser) {
yield ContentTask.spawn(browser, URL, function* (URL) {
let history = docShell.sessionHistory;
let count = 0;
let count = 0, historyListenerRemoved = false;
let testDone = {};
testDone.promise = new Promise(resolve => { testDone.resolve = resolve; });
let listener = {
OnHistoryNewEntry: function (aNewURI) {
if (aNewURI.spec == URL && 5 == ++count) {
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
let listener = {
OnHistoryNewEntry: function (aNewURI) {
if (aNewURI.spec == URL && 5 == ++count) {
addEventListener("load", function onLoad() {
removeEventListener("load", onLoad, true);
ok(history.index < history.count, "history.index is valid");
finish();
}, true);
ok(history.index < history.count, "history.index is valid");
testDone.resolve();
}, true);
history.removeSHistoryListener(listener);
historyListenerRemoved = true;
history.removeSHistoryListener(listener);
content.setTimeout(() => { content.location.reload(); }, 0);
}
executeSoon(function () { BrowserReload(); });
}
return true;
},
return true;
},
OnHistoryReload: () => true,
OnHistoryGoBack: () => true,
OnHistoryGoForward: () => true,
OnHistoryGotoIndex: () => true,
OnHistoryPurge: () => true,
OnHistoryReplaceEntry: () => {
// The initial load of about:blank causes a transient entry to be
// created, so our first navigation to a real page is a replace
// instead of a new entry.
++count;
return true;
},
OnHistoryReload: () => true,
OnHistoryGoBack: () => true,
OnHistoryGoForward: () => true,
OnHistoryGotoIndex: () => true,
OnHistoryPurge: () => true,
OnHistoryReplaceEntry: () => true,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
Ci.nsISupportsWeakReference])
};
QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
Ci.nsISupportsWeakReference])
};
let tab = gBrowser.loadOneTab(URL, {inBackground: false});
let browser = tab.linkedBrowser;
let history = browser.sessionHistory;
history.addSHistoryListener(listener);
registerCleanupFunction(function () {
gBrowser.removeTab(tab);
if (!historyListenerRemoved)
history.removeSHistoryListener(listener);
history.addSHistoryListener(listener);
content.location = URL;
yield testDone.promise;
});
});
}
});

View File

@ -0,0 +1,98 @@
const { utils: Cu, interfaces: Ci } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function SHistoryListener() {
}
SHistoryListener.prototype = {
retval: true,
last: "initial",
OnHistoryNewEntry: function (aNewURI) {
this.last = "newentry";
},
OnHistoryGoBack: function (aBackURI) {
this.last = "goback";
return this.retval;
},
OnHistoryGoForward: function (aForwardURI) {
this.last = "goforward";
return this.retval;
},
OnHistoryGotoIndex: function (aIndex, aGotoURI) {
this.last = "gotoindex";
return this.retval;
},
OnHistoryPurge: function (aNumEntries) {
this.last = "purge";
return this.retval;
},
OnHistoryReload: function (aReloadURI, aReloadFlags) {
this.last = "reload";
return this.retval;
},
OnHistoryReplaceEntry: function (aIndex) {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
Ci.nsISupportsWeakReference])
};
let testAPI = {
shistory: null,
listeners: [ new SHistoryListener(),
new SHistoryListener() ],
init() {
this.shistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
for (let listener of this.listeners) {
this.shistory.addSHistoryListener(listener);
}
},
cleanup() {
for (let listener of this.listeners) {
this.shistory.removeSHistoryListener(listener);
}
this.shistory = null;
sendAsyncMessage("bug422543:cleanup:return", {});
},
getListenerStatus() {
sendAsyncMessage("bug422543:getListenerStatus:return",
this.listeners.map(l => l.last));
},
resetListeners() {
for (let listener of this.listeners) {
listener.last = "initial";
}
sendAsyncMessage("bug422543:resetListeners:return", {});
},
notifyReload() {
let internal = this.shistory.QueryInterface(Ci.nsISHistoryInternal);
let rval =
internal.notifyOnHistoryReload(content.document.documentURIObject, 0);
sendAsyncMessage("bug422543:notifyReload:return", { rval });
},
setRetval({ num, val }) {
this.listeners[num].retval = val;
sendAsyncMessage("bug422543:setRetval:return", {});
},
};
addMessageListener("bug422543:cleanup", () => { testAPI.cleanup(); });
addMessageListener("bug422543:getListenerStatus", () => { testAPI.getListenerStatus(); });
addMessageListener("bug422543:notifyReload", () => { testAPI.notifyReload(); });
addMessageListener("bug422543:resetListeners", () => { testAPI.resetListeners(); });
addMessageListener("bug422543:setRetval", (msg) => { testAPI.setRetval(msg.data); });
testAPI.init();

View File

@ -4,7 +4,7 @@
function load() {
function next() {
if (count < 5)
iframe.src = 'data:text/html,iframe ' + (++count);
iframe.src = 'data:text/html;charset=utf-8,iframe ' + (++count);
}
var count = 0;

View File

@ -8,5 +8,4 @@ support-files =
bug343515_pg3_2.html
[browser_bug343515.js]
skip-if = e10s # Bug ?????? - test directly touches content (tries to QI the content window)
[browser_test-content-chromeflags.js]

View File

@ -4,14 +4,6 @@
var testPath = "http://mochi.test:8888/browser/docshell/test/navigation/";
var ctx = {};
// Helper function to check if a window is active
function isActive(aWindow) {
var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
return docshell.isActive;
}
// We need to wait until the page from each testcase is fully loaded,
// including all of its descendant iframes. To do that we manually count
// how many load events should happen on that page (one for the toplevel doc
@ -34,6 +26,12 @@ function oneShotListener(aElem, aType, aCallback) {
nShotsListener(aElem, aType, aCallback, 1);
}
function waitForPageshow(aBrowser, callback) {
return ContentTask.spawn(aBrowser, null, function* () {
yield ContentTaskUtils.waitForEvent(this, "pageshow");
}).then(callback);
}
// Entry point from Mochikit
function test() {
@ -49,15 +47,13 @@ function step1() {
// Get a handle on the initial tab
ctx.tab0 = gBrowser.selectedTab;
ctx.tab0Browser = gBrowser.getBrowserForTab(ctx.tab0);
ctx.tab0Window = ctx.tab0Browser.contentWindow;
// Our current tab should be active
ok(isActive(ctx.tab0Window), "Tab 0 should be active at test start");
ok(ctx.tab0Browser.docShellIsActive, "Tab 0 should be active at test start");
// Open a New Tab
ctx.tab1 = gBrowser.addTab(testPath + "bug343515_pg1.html");
ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1);
ctx.tab1Window = ctx.tab1Browser.contentWindow;
oneShotListener(ctx.tab1Browser, "load", step2);
}
@ -66,24 +62,23 @@ function step2() {
"Got expected tab 1 url in step 2");
// Our current tab should still be active
ok(isActive(ctx.tab0Window), "Tab 0 should still be active");
ok(!isActive(ctx.tab1Window), "Tab 1 should not be active");
ok(ctx.tab0Browser.docShellIsActive, "Tab 0 should still be active");
ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should not be active");
// Switch to tab 1
gBrowser.selectedTab = ctx.tab1;
BrowserTestUtils.switchTab(gBrowser, ctx.tab1).then(() => {
// Tab 1 should now be active
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
// Tab 1 should now be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
// Open another tab
ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html");
ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2);
// Open another tab
ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html");
ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2);
ctx.tab2Window = ctx.tab2Browser.contentWindow;
// bug343515_pg2.html consists of a page with two iframes,
// which will therefore generate 3 load events.
nShotsListener(ctx.tab2Browser, "load", step3, 3);
// bug343515_pg2.html consists of a page with two iframes,
// which will therefore generate 3 load events.
nShotsListener(ctx.tab2Browser, "load", step3, 3);
});
}
function step3() {
@ -91,115 +86,169 @@ function step3() {
"Got expected tab 2 url in step 3");
// Tab 0 should be inactive, Tab 1 should be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
// Tab 2's window _and_ its iframes should be inactive
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes");
for (var i = 0; i < ctx.tab2Window.frames.length; i++)
info("step 3, frame " + i + " info: " + ctx.tab2Window.frames[i].location);
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive");
ContentTask.spawn(ctx.tab2Browser, null, function* () {
is(content.frames.length, 2, "Tab 2 should have 2 iframes");
for (var i = 0; i < content.frames.length; i++) {
info("step 3, frame " + i + " info: " + content.frames[i].location);
let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
// Navigate tab 2 to a different page
ctx.tab2Window.location = testPath + "bug343515_pg3.html";
ok(!docShell.isActive, `Tab2 iframe ${i} should be inactive`);
}
}).then(() => {
// Navigate tab 2 to a different page
ctx.tab2Browser.loadURI(testPath + "bug343515_pg3.html");
// bug343515_pg3.html consists of a page with two iframes, one of which
// contains another iframe, so there'll be a total of 4 load events
nShotsListener(ctx.tab2Browser, "load", step4, 4);
// bug343515_pg3.html consists of a page with two iframes, one of which
// contains another iframe, so there'll be a total of 4 load events
nShotsListener(ctx.tab2Browser, "load", step4, 4);
});
}
function step4() {
function checkTab2Active(expected) {
return ContentTask.spawn(ctx.tab2Browser, expected, function* (expected) {
function isActive(aWindow) {
var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
return docshell.isActive;
}
let active = expected ? "active" : "inactive";
is(content.frames.length, 2, "Tab 2 should have 2 iframes");
for (var i = 0; i < content.frames.length; i++)
info("step 4, frame " + i + " info: " + content.frames[i].location);
is(content.frames[0].frames.length, 1, "Tab 2 iframe 0 should have 1 iframes");
is(isActive(content.frames[0]), expected, `Tab2 iframe 0 should be ${active}`);
is(isActive(content.frames[0].frames[0]), expected,
`Tab2 iframe 0 subiframe 0 should be ${active}`);
is(isActive(content.frames[1]), expected, `Tab2 iframe 1 should be ${active}`);
});
}
is(testPath + "bug343515_pg3.html", ctx.tab2Browser.currentURI.spec,
"Got expected tab 2 url in step 4");
// Tab 0 should be inactive, Tab 1 should be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
// Tab2 and all descendants should be inactive
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes");
for (var i = 0; i < ctx.tab2Window.frames.length; i++)
info("step 4, frame " + i + " info: " + ctx.tab2Window.frames[i].location);
is(ctx.tab2Window.frames[0].frames.length, 1, "Tab 2 iframe 0 should have 1 iframes");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
// Switch to Tab 2
gBrowser.selectedTab = ctx.tab2;
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(!isActive(ctx.tab1Window), "Tab 1 should be inactive");
ok(isActive(ctx.tab2Window), "Tab 2 should be active");
ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active");
ok(isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be active");
ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active");
// Go back
oneShotListener(ctx.tab2Browser, "pageshow", step5);
ctx.tab2Browser.goBack();
checkTab2Active(false).then(() => {
// Switch to Tab 2
return BrowserTestUtils.switchTab(gBrowser, ctx.tab2);
}).then(() => {
// Check everything
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should be inactive");
ok(ctx.tab2Browser.docShellIsActive, "Tab 2 should be active");
return checkTab2Active(true);
}).then(() => {
// Go back
waitForPageshow(ctx.tab2Browser, step5);
ctx.tab2Browser.goBack();
});
}
function step5() {
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(!isActive(ctx.tab1Window), "Tab 1 should be inactive");
ok(isActive(ctx.tab2Window), "Tab 2 should be active");
ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active");
ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active");
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should be inactive");
ok(ctx.tab2Browser.docShellIsActive, "Tab 2 should be active");
ContentTask.spawn(ctx.tab2Browser, null, function* () {
for (var i = 0; i < content.frames.length; i++) {
let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
// Switch to tab 1
gBrowser.selectedTab = ctx.tab1;
ok(docShell.isActive, `Tab2 iframe ${i} should be active`);
}
}).then(() => {
// Switch to tab 1
return BrowserTestUtils.switchTab(gBrowser, ctx.tab1);
}).then(() => {
// Navigate to page 3
ctx.tab1Browser.loadURI(testPath + "bug343515_pg3.html");
// Navigate to page 3
ctx.tab1Window.location = testPath + "bug343515_pg3.html";
// bug343515_pg3.html consists of a page with two iframes, one of which
// contains another iframe, so there'll be a total of 4 load events
nShotsListener(ctx.tab1Browser, "load", step6, 4);
// bug343515_pg3.html consists of a page with two iframes, one of which
// contains another iframe, so there'll be a total of 4 load events
nShotsListener(ctx.tab1Browser, "load", step6, 4);
});
}
function step6() {
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active");
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
ContentTask.spawn(ctx.tab1Browser, null, function* () {
function isActive(aWindow) {
var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
return docshell.isActive;
}
// Go forward on tab 2
oneShotListener(ctx.tab2Browser, "pageshow", step7);
var tab2docshell = ctx.tab2Window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
tab2docshell.goForward();
ok(isActive(content.frames[0]), "Tab1 iframe 0 should be active");
ok(isActive(content.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
ok(isActive(content.frames[1]), "Tab1 iframe 1 should be active");
}).then(() => {
ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive");
return ContentTask.spawn(ctx.tab2Browser, null, function* () {
for (var i = 0; i < content.frames.length; i++) {
let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
ok(!docShell.isActive, `Tab2 iframe ${i} should be inactive`);
}
});
}).then(() => {
// Go forward on tab 2
waitForPageshow(ctx.tab2Browser, step7);
ctx.tab2Browser.goForward();
});
}
function step7() {
function checkBrowser(browser, tabNum, active) {
return ContentTask.spawn(browser, { tabNum, active },
function* ({ tabNum, active }) {
function isActive(aWindow) {
var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
return docshell.isActive;
}
ctx.tab2Window = ctx.tab2Browser.contentWindow;
let activestr = active ? "active" : "inactive";
is(isActive(content.frames[0]), active,
`Tab${tabNum} iframe 0 should be ${activestr}`);
is(isActive(content.frames[0].frames[0]), active,
`Tab${tabNum} iframe 0 subiframe 0 should be ${activestr}`);
is(isActive(content.frames[1]), active,
`Tab${tabNum} iframe 1 should be ${activestr}`);
});
}
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active");
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
// That's probably enough
allDone();
ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
checkBrowser(ctx.tab1Browser, 1, true).then(() => {
ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive");
return checkBrowser(ctx.tab2Browser, 2, false);
}).then(() => {
// That's probably enough
allDone();
});
}
function allDone() {

View File

@ -685,7 +685,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(Console)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Console)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
Console::Console(nsPIDOMWindow* aWindow)
@ -709,7 +710,7 @@ Console::Console(nsPIDOMWindow* aWindow)
if (NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this, "inner-window-destroyed", false);
obs->AddObserver(this, "inner-window-destroyed", true);
}
}

View File

@ -14,6 +14,7 @@
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsWrapperCache.h"
#include "nsDOMNavigationTiming.h"
#include "nsPIDOMWindow.h"
@ -29,12 +30,13 @@ struct ConsoleStackEntry;
class Console final : public nsIObserver
, public nsWrapperCache
, public nsSupportsWeakReference
{
~Console();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Console)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console, nsIObserver)
NS_DECL_NSIOBSERVER
explicit Console(nsPIDOMWindow* aWindow);

View File

@ -67,9 +67,6 @@ GetSriLog()
return gSriPRLog;
}
// The nsScriptLoadRequest is passed as the context to necko, and thus
// it needs to be threadsafe. Necko won't do anything with this
// context, but it will AddRef and Release it on other threads.
NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
nsScriptLoadRequestList::~nsScriptLoadRequestList()

View File

@ -82,7 +82,7 @@ public:
{
}
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_ISUPPORTS
void FireScriptAvailable(nsresult aResult)
{

View File

@ -228,6 +228,10 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
}
BluetoothA2dpManager::~BluetoothA2dpManager()
{ }
void
BluetoothA2dpManager::Uninit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
@ -273,9 +277,9 @@ BluetoothA2dpManager::Get()
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothA2dpManager* manager = new BluetoothA2dpManager();
sBluetoothA2dpManager = manager;
// Create a new instance and return
sBluetoothA2dpManager = new BluetoothA2dpManager();
return sBluetoothA2dpManager;
}
@ -297,6 +301,9 @@ public:
sBtA2dpInterface->SetNotificationHandler(nullptr);
sBtA2dpInterface = nullptr;
sBluetoothA2dpManager->Uninit();
sBluetoothA2dpManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
@ -309,6 +316,9 @@ public:
sBtA2dpInterface->SetNotificationHandler(nullptr);
sBtA2dpInterface = nullptr;
sBluetoothA2dpManager->Uninit();
sBluetoothA2dpManager = nullptr;
if (mRes) {
mRes->Deinit();
}

View File

@ -58,6 +58,7 @@ private:
BluetoothA2dpManager();
void Uninit();
void HandleShutdown();
void NotifyConnectionStatusChanged();

View File

@ -268,6 +268,10 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
}
BluetoothAvrcpManager::~BluetoothAvrcpManager()
{ }
void
BluetoothAvrcpManager::Uninit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
@ -294,9 +298,9 @@ BluetoothAvrcpManager::Get()
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
sBluetoothAvrcpManager = manager;
// Create a new instance and return
sBluetoothAvrcpManager = new BluetoothAvrcpManager();
return sBluetoothAvrcpManager;
}
@ -318,6 +322,9 @@ public:
sBtAvrcpInterface->SetNotificationHandler(nullptr);
sBtAvrcpInterface = nullptr;
sBluetoothAvrcpManager->Uninit();
sBluetoothAvrcpManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
@ -330,6 +337,9 @@ public:
sBtAvrcpInterface->SetNotificationHandler(nullptr);
sBtAvrcpInterface = nullptr;
sBluetoothAvrcpManager->Uninit();
sBluetoothAvrcpManager = nullptr;
if (mRes) {
mRes->Deinit();
}

View File

@ -71,6 +71,7 @@ private:
BluetoothAvrcpManager();
void Uninit();
void HandleShutdown();
void NotifyConnectionStatusChanged();

View File

@ -389,26 +389,39 @@ BluetoothGattManager::Get()
NS_ENSURE_FALSE(mInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothGattManager* manager = new BluetoothGattManager();
NS_ENSURE_TRUE(manager->Init(), nullptr);
RefPtr<BluetoothGattManager> manager = new BluetoothGattManager();
NS_ENSURE_SUCCESS(manager->Init(), nullptr);
sBluetoothGattManager = manager;
return sBluetoothGattManager;
}
bool
nsresult
BluetoothGattManager::Init()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, false);
NS_ENSURE_TRUE(obs, NS_ERROR_NOT_AVAILABLE);
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_FAILED(rv)) {
BT_WARNING("Failed to add observers!");
return false;
return rv;
}
return true;
return NS_OK;
}
void
BluetoothGattManager::Uninit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
class BluetoothGattManager::RegisterModuleResultHandler final
@ -569,6 +582,11 @@ public:
sBluetoothGattInterface->SetNotificationHandler(nullptr);
sBluetoothGattInterface = nullptr;
sClients = nullptr;
sServers = nullptr;
sBluetoothGattManager->Uninit();
sBluetoothGattManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
@ -584,6 +602,9 @@ public:
sClients = nullptr;
sServers = nullptr;
sBluetoothGattManager->Uninit();
sBluetoothGattManager = nullptr;
if (mRes) {
mRes->Deinit();
}
@ -4090,13 +4111,7 @@ BluetoothGattManager::BluetoothGattManager()
{ }
BluetoothGattManager::~BluetoothGattManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
{ }
NS_IMETHODIMP
BluetoothGattManager::Observe(nsISupports* aSubject,

View File

@ -216,8 +216,9 @@ private:
class ServerSendIndicationResultHandler;
BluetoothGattManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void RegisterClientNotification(BluetoothGattStatus aStatus,

View File

@ -84,6 +84,8 @@ BluetoothMapSmsManager::HandleShutdown()
sInShutdown = true;
Disconnect(nullptr);
Uninit();
sMapSmsManager = nullptr;
}
@ -98,27 +100,19 @@ BluetoothMapSmsManager::BluetoothMapSmsManager()
}
BluetoothMapSmsManager::~BluetoothMapSmsManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
{ }
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
bool
nsresult
BluetoothMapSmsManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return false;
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_WARN_IF(NS_FAILED(
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
return false;
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
/**
@ -130,7 +124,64 @@ BluetoothMapSmsManager::Init()
* absence of read events when device boots up.
*/
return true;
return NS_OK;
}
void
BluetoothMapSmsManager::Uninit()
{
if (mMasServerSocket) {
mMasServerSocket->SetObserver(nullptr);
if (mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasServerSocket->Close();
}
mMasServerSocket = nullptr;
}
if (mMasSocket) {
mMasSocket->SetObserver(nullptr);
if (mMasSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasSocket->Close();
}
mMasSocket = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
// static
void
BluetoothMapSmsManager::InitMapSmsInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothMapSmsManager::DeinitMapSmsInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sMapSmsManager) {
sMapSmsManager->Uninit();
sMapSmsManager = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static
@ -150,8 +201,8 @@ BluetoothMapSmsManager::Get()
}
// Create a new instance, register, and return
BluetoothMapSmsManager *manager = new BluetoothMapSmsManager();
if (NS_WARN_IF(!manager->Init())) {
RefPtr<BluetoothMapSmsManager> manager = new BluetoothMapSmsManager();
if (NS_WARN_IF(NS_FAILED(manager->Init()))) {
return nullptr;
}
@ -175,10 +226,11 @@ BluetoothMapSmsManager::Listen()
* BT stops; otherwise no more read events would be received even if
* BT restarts.
*/
if (mMasServerSocket) {
if (mMasServerSocket &&
mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasServerSocket->Close();
mMasServerSocket = nullptr;
}
mMasServerSocket = nullptr;
mMasServerSocket = new BluetoothSocket(this);
@ -1510,7 +1562,17 @@ BluetoothMapSmsManager::OnSocketConnectError(BluetoothSocket* aSocket)
}
// MAS socket connection error
if (mMasServerSocket &&
mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasServerSocket->Close();
}
mMasServerSocket = nullptr;
if (mMasSocket &&
mMasSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasSocket->Close();
}
mMasSocket = nullptr;
}
@ -1541,6 +1603,7 @@ BluetoothMapSmsManager::OnSocketDisconnect(BluetoothSocket* aSocket)
// MAS socket is disconnected
AfterMapSmsDisconnected();
mDeviceAddress.Clear();
mMasSocket = nullptr;
Listen();

View File

@ -86,7 +86,10 @@ public:
// By defualt SMS/MMS is default supported
static const int SDP_SMS_MMS_INSTANCE_ID = 0;
static void InitMapSmsInterface(BluetoothProfileResultHandler* aRes);
static void DeinitMapSmsInterface(BluetoothProfileResultHandler* aRes);
static BluetoothMapSmsManager* Get();
bool Listen();
/**
@ -194,7 +197,9 @@ protected:
private:
BluetoothMapSmsManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void ReplyToConnect();

View File

@ -214,31 +214,24 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
{ }
BluetoothOppManager::~BluetoothOppManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
{ }
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
BT_WARNING("Failed to remove volume observer!");
}
}
bool
nsresult
BluetoothOppManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, false);
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
NS_ENSURE_TRUE(obs, NS_ERROR_NOT_AVAILABLE);
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_FAILED(rv)) {
BT_WARNING("Failed to add shutdown observer!");
return false;
return rv;
}
if (NS_FAILED(obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false))) {
rv = obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
if (NS_FAILED(rv)) {
BT_WARNING("Failed to add ns volume observer!");
return false;
return rv;
}
/**
@ -250,7 +243,67 @@ BluetoothOppManager::Init()
* absence of read events when device boots up.
*/
return true;
return NS_OK;
}
void
BluetoothOppManager::Uninit()
{
if (mServerSocket) {
mServerSocket->SetObserver(nullptr);
if (mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
}
if (mSocket) {
mSocket->SetObserver(nullptr);
if (mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
BT_WARNING("Failed to remove volume observer!");
}
}
// static
void
BluetoothOppManager::InitOppInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothOppManager::DeinitOppInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBluetoothOppManager) {
sBluetoothOppManager->Uninit();
sBluetoothOppManager = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static
@ -268,10 +321,11 @@ BluetoothOppManager::Get()
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothOppManager *manager = new BluetoothOppManager();
NS_ENSURE_TRUE(manager->Init(), nullptr);
RefPtr<BluetoothOppManager> manager = new BluetoothOppManager();
NS_ENSURE_SUCCESS(manager->Init(), nullptr);
sBluetoothOppManager = manager;
return sBluetoothOppManager;
}
@ -281,10 +335,11 @@ BluetoothOppManager::ConnectInternal(const BluetoothAddress& aDeviceAddress)
MOZ_ASSERT(NS_IsMainThread());
// Stop listening because currently we only support one connection at a time.
if (mServerSocket) {
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
mServerSocket = nullptr;
}
mServerSocket = nullptr;
mIsServer = false;
@ -310,6 +365,8 @@ BluetoothOppManager::HandleShutdown()
MOZ_ASSERT(NS_IsMainThread());
sInShutdown = true;
Disconnect(nullptr);
Uninit();
sBluetoothOppManager = nullptr;
}
@ -356,10 +413,11 @@ BluetoothOppManager::Listen()
* BT stops; otherwise no more read events would be received even if
* BT restarts.
*/
if (mServerSocket) {
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
mServerSocket = nullptr;
}
mServerSocket = nullptr;
mServerSocket = new BluetoothSocket(this);
@ -1526,7 +1584,16 @@ BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
{
BT_LOGR("[%s]", (mIsServer)? "server" : "client");
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
if (mSocket &&
mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
if (!mIsServer) {
@ -1576,7 +1643,8 @@ BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
mDeviceAddress.Clear();
mSuccessFlag = false;
mSocket = nullptr;
mSocket = nullptr; // should already be closed
// Listen as a server if there's no more batch to process
if (!ProcessNextBatch()) {
Listen();

View File

@ -40,6 +40,7 @@ class BluetoothOppManager : public BluetoothSocketObserver
class SendSocketDataTask;
public:
BT_DECL_PROFILE_MGR_BASE
BT_DECL_SOCKET_OBSERVER
virtual void GetName(nsACString& aName)
@ -49,7 +50,10 @@ public:
static const int MAX_PACKET_LENGTH = 0xFFFE;
static void InitOppInterface(BluetoothProfileResultHandler* aRes);
static void DeinitOppInterface(BluetoothProfileResultHandler* aRes);
static BluetoothOppManager* Get();
void ClientDataHandler(mozilla::ipc::UnixSocketBuffer* aMessage);
void ServerDataHandler(mozilla::ipc::UnixSocketBuffer* aMessage);
@ -75,7 +79,8 @@ protected:
private:
BluetoothOppManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void HandleVolumeStateChanged(nsISupports* aSubject);

View File

@ -94,6 +94,8 @@ BluetoothPbapManager::HandleShutdown()
sInShutdown = true;
Disconnect(nullptr);
Uninit();
sPbapManager = nullptr;
}
@ -105,27 +107,19 @@ BluetoothPbapManager::BluetoothPbapManager() : mPhonebookSizeRequired(false)
}
BluetoothPbapManager::~BluetoothPbapManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
{ }
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
bool
nsresult
BluetoothPbapManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return false;
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_WARN_IF(NS_FAILED(
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
return false;
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
/**
@ -137,7 +131,64 @@ BluetoothPbapManager::Init()
* absence of read events when device boots up.
*/
return true;
return NS_OK;
}
void
BluetoothPbapManager::Uninit()
{
if (mServerSocket) {
mServerSocket->SetObserver(nullptr);
if (mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
}
if (mSocket) {
mSocket->SetObserver(nullptr);
if (mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
// static
void
BluetoothPbapManager::InitPbapInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothPbapManager::DeinitPbapInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sPbapManager) {
sPbapManager->Uninit();
sPbapManager = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static
@ -157,8 +208,8 @@ BluetoothPbapManager::Get()
}
// Create a new instance, register, and return
BluetoothPbapManager *manager = new BluetoothPbapManager();
if (NS_WARN_IF(!manager->Init())) {
RefPtr<BluetoothPbapManager> manager = new BluetoothPbapManager();
if (NS_WARN_IF(NS_FAILED(manager->Init()))) {
return nullptr;
}
@ -181,10 +232,11 @@ BluetoothPbapManager::Listen()
* BT stops; otherwise no more read events would be received even if
* BT restarts.
*/
if (mServerSocket) {
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
mServerSocket = nullptr;
}
mServerSocket = nullptr;
mServerSocket = new BluetoothSocket(this);
@ -1131,7 +1183,16 @@ BluetoothPbapManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
void
BluetoothPbapManager::OnSocketConnectError(BluetoothSocket* aSocket)
{
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
if (mSocket &&
mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
}
@ -1147,7 +1208,8 @@ BluetoothPbapManager::OnSocketDisconnect(BluetoothSocket* aSocket)
AfterPbapDisconnected();
mDeviceAddress.Clear();
mSocket = nullptr;
mSocket = nullptr; // should already be closed
Listen();
}

View File

@ -67,7 +67,10 @@ public:
static const int MAX_PACKET_LENGTH = 0xFFFE;
static const int DIGEST_LENGTH = 16;
static void InitPbapInterface(BluetoothProfileResultHandler* aRes);
static void DeinitPbapInterface(BluetoothProfileResultHandler* aRes);
static BluetoothPbapManager* Get();
bool Listen();
/**
@ -146,7 +149,9 @@ protected:
private:
BluetoothPbapManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void ReplyToConnect(const nsAString& aPassword = EmptyString());

View File

@ -138,6 +138,10 @@ public:
void Init() override
{
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothMapSmsManager::InitMapSmsInterface,
BluetoothOppManager::InitOppInterface,
BluetoothPbapManager::InitPbapInterface,
BluetoothHidManager::InitHidInterface,
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface,
BluetoothAvrcpManager::InitAvrcpInterface,
@ -280,14 +284,15 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
static BluetoothProfileManagerBase* sProfiles[] = {
BluetoothHfpManager::Get(),
BluetoothProfileManagerBase* sProfiles[] = {
// BluetoothGattManager not handled here
BluetoothAvrcpManager::Get(),
BluetoothA2dpManager::Get(),
BluetoothOppManager::Get(),
BluetoothHfpManager::Get(),
BluetoothHidManager::Get(),
BluetoothPbapManager::Get(),
BluetoothMapSmsManager::Get(),
BluetoothHidManager::Get()
BluetoothOppManager::Get(),
BluetoothMapSmsManager::Get()
};
// Disconnect all connected profiles
@ -2037,7 +2042,11 @@ BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
BluetoothGattManager::DeinitGattInterface,
BluetoothAvrcpManager::DeinitAvrcpInterface,
BluetoothA2dpManager::DeinitA2dpInterface,
BluetoothHfpManager::DeinitHfpInterface
BluetoothHfpManager::DeinitHfpInterface,
BluetoothHidManager::DeinitHidInterface,
BluetoothPbapManager::DeinitPbapInterface,
BluetoothOppManager::DeinitOppInterface,
BluetoothMapSmsManager::DeinitMapSmsInterface
};
// Return error if BluetoothService is unavailable

View File

@ -20,24 +20,6 @@ using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
static const size_t MAX_READ_SIZE = 1 << 16;
static BluetoothSocketInterface* sBluetoothSocketInterface;
// helper functions
static bool
EnsureBluetoothSocketHalLoad()
{
if (sBluetoothSocketInterface) {
return true;
}
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE(btInf, false);
sBluetoothSocketInterface = btInf->GetBluetoothSocketInterface();
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
return true;
}
class mozilla::dom::bluetooth::DroidSocketImpl
: public mozilla::ipc::UnixFdWatcher
@ -429,24 +411,20 @@ private:
class InvokeAcceptTask final : public SocketTask<DroidSocketImpl>
{
public:
InvokeAcceptTask(DroidSocketImpl* aImpl, int aFd)
InvokeAcceptTask(DroidSocketImpl* aImpl, int aListenFd)
: SocketTask<DroidSocketImpl>(aImpl)
, mFd(aFd)
, mListenFd(aListenFd)
{ }
void Run() override
{
MOZ_ASSERT(GetIO()->IsConsumerThread());
MOZ_ASSERT(sBluetoothSocketInterface);
BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
GetIO()->mConsumer->SetCurrentResultHandler(res);
sBluetoothSocketInterface->Accept(mFd, res);
GetIO()->mConsumer->Accept(mListenFd, new AcceptResultHandler(GetIO()));
}
private:
int mFd;
int mListenFd;
};
void
@ -581,22 +559,27 @@ DroidSocketImpl::DiscardBuffer()
//
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver)
: mObserver(aObserver)
: mSocketInterface(nullptr)
, mObserver(aObserver)
, mCurrentRes(nullptr)
, mImpl(nullptr)
{
MOZ_ASSERT(aObserver);
MOZ_COUNT_CTOR_INHERITED(BluetoothSocket, DataSocket);
EnsureBluetoothSocketHalLoad();
}
BluetoothSocket::~BluetoothSocket()
{
MOZ_ASSERT(!mImpl); // Socket is closed
MOZ_COUNT_DTOR_INHERITED(BluetoothSocket, DataSocket);
}
void
BluetoothSocket::SetObserver(BluetoothSocketObserver* aObserver)
{
mObserver = aObserver;
}
class ConnectSocketResultHandler final : public BluetoothSocketResultHandler
{
public:
@ -655,6 +638,11 @@ BluetoothSocket::Connect(const BluetoothAddress& aDeviceAddress,
{
MOZ_ASSERT(!mImpl);
auto rv = LoadSocketInterface();
if (NS_FAILED(rv)) {
return rv;
}
SetConnectionStatus(SOCKET_CONNECTING);
mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this);
@ -662,7 +650,7 @@ BluetoothSocket::Connect(const BluetoothAddress& aDeviceAddress,
BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
SetCurrentResultHandler(res);
sBluetoothSocketInterface->Connect(
mSocketInterface->Connect(
aDeviceAddress, aType,
aServiceUuid, aChannel,
aEncrypt, aAuth, res);
@ -719,8 +707,13 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
{
MOZ_ASSERT(!mImpl);
auto rv = LoadSocketInterface();
if (NS_FAILED(rv)) {
return rv;
}
BluetoothServiceName serviceName;
nsresult rv = StringToServiceName(aServiceName, serviceName);
rv = StringToServiceName(aServiceName, serviceName);
if (NS_FAILED(rv)) {
return rv;
}
@ -732,7 +725,7 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
SetCurrentResultHandler(res);
sBluetoothSocketInterface->Listen(
mSocketInterface->Listen(
aType,
serviceName, aServiceUuid, aChannel,
aEncrypt, aAuth, res);
@ -751,12 +744,26 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
MessageLoop::current(), XRE_GetIOMessageLoop());
}
nsresult
BluetoothSocket::Accept(int aListenFd, BluetoothSocketResultHandler* aRes)
{
auto rv = LoadSocketInterface();
if (NS_FAILED(rv)) {
return rv;
}
SetCurrentResultHandler(aRes);
mSocketInterface->Accept(aListenFd, aRes);
return NS_OK;
}
void
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
{
MOZ_ASSERT(mObserver);
mObserver->ReceiveSocketData(this, aBuffer);
if (mObserver) {
mObserver->ReceiveSocketData(this, aBuffer);
}
}
// |DataSocket|
@ -778,50 +785,86 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
void
BluetoothSocket::Close()
{
MOZ_ASSERT(sBluetoothSocketInterface);
if (!mImpl) {
return;
}
MOZ_ASSERT(mImpl->IsConsumerThread());
// Stop any watching |SocketMessageWatcher|
if (mCurrentRes) {
sBluetoothSocketInterface->Close(mCurrentRes);
}
// From this point on, we consider mImpl as being deleted.
// We sever the relationship here so any future calls to listen or connect
// will create a new implementation.
mImpl->ShutdownOnConsumerThread();
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
mImpl = nullptr;
NotifyDisconnect();
}
void
BluetoothSocket::OnConnectSuccess()
{
MOZ_ASSERT(mObserver);
SetCurrentResultHandler(nullptr);
mObserver->OnSocketConnectSuccess(this);
if (mObserver) {
mObserver->OnSocketConnectSuccess(this);
}
}
void
BluetoothSocket::OnConnectError()
{
MOZ_ASSERT(mObserver);
auto observer = mObserver;
SetCurrentResultHandler(nullptr);
mObserver->OnSocketConnectError(this);
Cleanup();
if (observer) {
observer->OnSocketConnectError(this);
}
}
void
BluetoothSocket::OnDisconnect()
{
MOZ_ASSERT(mObserver);
mObserver->OnSocketDisconnect(this);
auto observer = mObserver;
Cleanup();
if (observer) {
observer->OnSocketDisconnect(this);
}
}
nsresult
BluetoothSocket::LoadSocketInterface()
{
if (mSocketInterface) {
return NS_OK;
}
auto interface = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE(!!interface, NS_ERROR_FAILURE);
auto socketInterface = interface->GetBluetoothSocketInterface();
NS_ENSURE_TRUE(!!socketInterface, NS_ERROR_FAILURE);
mSocketInterface = socketInterface;
return NS_OK;
}
void
BluetoothSocket::Cleanup()
{
MOZ_ASSERT(mSocketInterface);
MOZ_ASSERT(mImpl);
MOZ_ASSERT(mImpl->IsConsumerThread());
// Stop any watching |SocketMessageWatcher|
if (mCurrentRes) {
mSocketInterface->Close(mCurrentRes);
}
// From this point on, we consider mImpl as being deleted. We
// sever the relationship here so any future calls to listen
// or connect will create a new implementation.
mImpl->ShutdownOnConsumerThread();
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
mImpl = nullptr;
mSocketInterface = nullptr;
mObserver = nullptr;
mCurrentRes = nullptr;
mDeviceAddress.Clear();
}

View File

@ -14,6 +14,7 @@ class MessageLoop;
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSocketInterface;
class BluetoothSocketObserver;
class BluetoothSocketResultHandler;
class DroidSocketImpl;
@ -24,6 +25,8 @@ public:
BluetoothSocket(BluetoothSocketObserver* aObserver);
~BluetoothSocket();
void SetObserver(BluetoothSocketObserver* aObserver);
nsresult Connect(const BluetoothAddress& aDeviceAddress,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
@ -52,6 +55,8 @@ public:
int aChannel,
bool aAuth, bool aEncrypt);
nsresult Accept(int aListenFd, BluetoothSocketResultHandler* aRes);
/**
* Method to be called whenever data is received. This is only called on the
* consumer thread.
@ -70,11 +75,6 @@ public:
mDeviceAddress = aDeviceAddress;
}
inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
{
mCurrentRes = aRes;
}
// Methods for |DataSocket|
//
@ -90,6 +90,15 @@ public:
void OnDisconnect() override;
private:
nsresult LoadSocketInterface();
void Cleanup();
inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
{
mCurrentRes = aRes;
}
BluetoothSocketInterface* mSocketInterface;
BluetoothSocketObserver* mObserver;
BluetoothSocketResultHandler* mCurrentRes;
DroidSocketImpl* mImpl;

View File

@ -176,6 +176,8 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothHfpManager = nullptr;
/**
* TODO:
* Implement DeinitHfpInterface() for applications that want to create SCO

View File

@ -446,6 +446,7 @@ public:
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
sBluetoothHfpInterface = nullptr;
sBluetoothHfpManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
@ -458,6 +459,7 @@ public:
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
sBluetoothHfpInterface = nullptr;
sBluetoothHfpManager = nullptr;
if (mRes) {
mRes->Deinit();

View File

@ -78,6 +78,30 @@ BluetoothHidManager::~BluetoothHidManager()
}
}
// static
void
BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothHidManager = nullptr;
if (aRes) {
aRes->Deinit();
}
}
//static
BluetoothHidManager*
BluetoothHidManager::Get()

View File

@ -22,6 +22,8 @@ public:
aName.AssignLiteral("HID");
}
static void InitHidInterface(BluetoothProfileResultHandler* aRes);
static void DeinitHidInterface(BluetoothProfileResultHandler* aRes);
static BluetoothHidManager* Get();
// HID-specific functions

View File

@ -258,7 +258,7 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
static bool
ValidateTextureLayerAttachment(GLenum attachment)
{
if (LOCAL_GL_COLOR_ATTACHMENT0 < attachment &&
if (LOCAL_GL_COLOR_ATTACHMENT0 <= attachment &&
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
{
return true;
@ -293,15 +293,23 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
"texture object.");
}
if (level < 0)
if (layer < 0)
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
if (level < 0)
return ErrorInvalidValue("framebufferTextureLayer: level must be >= 0.");
switch (texture->Target().get()) {
case LOCAL_GL_TEXTURE_3D:
if (uint32_t(layer) >= mImplMax3DTextureSize) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_3D_TEXTURE_SIZE");
}
if (uint32_t(level) > FloorLog2(mImplMax3DTextureSize)) {
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
"log2(MAX_3D_TEXTURE_SIZE");
}
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
@ -309,6 +317,11 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_ARRAY_TEXTURE_LAYERS");
}
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
"log2(MAX_TEXTURE_SIZE");
}
break;
default:

View File

@ -52,21 +52,42 @@ bool WebGL2Context::ValidateClearBuffer(const char* info, GLenum buffer, GLint d
void
WebGL2Context::ClearBufferiv_base(GLenum buffer, GLint drawbuffer, const GLint* value)
{
const char funcName[] = "clearBufferiv";
MakeContextCurrent();
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
return;
}
gl->fClearBufferiv(buffer, drawbuffer, value);
}
void
WebGL2Context::ClearBufferuiv_base(GLenum buffer, GLint drawbuffer, const GLuint* value)
{
const char funcName[] = "clearBufferuiv";
MakeContextCurrent();
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
return;
}
gl->fClearBufferuiv(buffer, drawbuffer, value);
}
void
WebGL2Context::ClearBufferfv_base(GLenum buffer, GLint drawbuffer, const GLfloat* value)
{
const char funcName[] = "clearBufferfv";
MakeContextCurrent();
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
return;
}
gl->fClearBufferfv(buffer, drawbuffer, value);
}

View File

@ -47,6 +47,8 @@ WebGL2Context::DeleteSampler(WebGLSampler* sampler)
for (int n = 0; n < mGLMaxTextureUnits; n++) {
if (mBoundSamplers[n] == sampler) {
mBoundSamplers[n] = nullptr;
InvalidateResolveCacheForTextureWithTexUnit(n);
}
}
@ -88,6 +90,7 @@ WebGL2Context::BindSampler(GLuint unit, WebGLSampler* sampler)
return ErrorInvalidOperation("bindSampler: binding deleted sampler");
WebGLContextUnchecked::BindSampler(unit, sampler);
InvalidateResolveCacheForTextureWithTexUnit(unit);
mBoundSamplers[unit] = sampler;
}
@ -104,6 +107,7 @@ WebGL2Context::SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint para
if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameteri"))
return;
sampler->SamplerParameter1i(pname, param);
WebGLContextUnchecked::SamplerParameteri(sampler, pname, param);
}
@ -124,6 +128,7 @@ WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom
if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameteriv"))
return;
sampler->SamplerParameter1i(pname, param.Data()[0]);
WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Data());
}
@ -143,6 +148,7 @@ WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom
if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameteriv"))
return;
sampler->SamplerParameter1i(pname, param[0]);
WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Elements());
}
@ -158,6 +164,7 @@ WebGL2Context::SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat pa
if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameterf"))
return;
sampler->SamplerParameter1f(pname, param);
WebGLContextUnchecked::SamplerParameterf(sampler, pname, param);
}
@ -178,6 +185,7 @@ WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom
if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameterfv"))
return;
sampler->SamplerParameter1f(pname, param.Data()[0]);
WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Data());
}
@ -197,6 +205,7 @@ WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom
if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameterfv"))
return;
sampler->SamplerParameter1f(pname, param[0]);
WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Elements());
}

View File

@ -332,6 +332,8 @@ public:
return ActiveBoundTextureForTarget(texTarget);
}
void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
already_AddRefed<Layer>
GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
LayerManager* manager) override;

View File

@ -1316,15 +1316,50 @@ WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei he
}
static bool
IsFormatAndTypeUnpackable(GLenum format, GLenum type)
IsFormatAndTypeUnpackable(GLenum format, GLenum type, bool isWebGL2)
{
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
switch (format) {
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_LUMINANCE_ALPHA:
if (!isWebGL2)
return false;
case LOCAL_GL_ALPHA:
case LOCAL_GL_RED:
case LOCAL_GL_RED_INTEGER:
case LOCAL_GL_RG:
case LOCAL_GL_RG_INTEGER:
case LOCAL_GL_RGB:
case LOCAL_GL_RGB_INTEGER:
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA_INTEGER:
return true;
default:
return false;
}
case LOCAL_GL_BYTE:
switch (format) {
case LOCAL_GL_RED:
case LOCAL_GL_RED_INTEGER:
case LOCAL_GL_RG:
case LOCAL_GL_RG_INTEGER:
case LOCAL_GL_RGB:
case LOCAL_GL_RGB_INTEGER:
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA_INTEGER:
return true;
default:
return false;
}
case LOCAL_GL_FLOAT:
case LOCAL_GL_HALF_FLOAT:
case LOCAL_GL_HALF_FLOAT_OES:
switch (format) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_RED:
case LOCAL_GL_RG:
case LOCAL_GL_RGB:
case LOCAL_GL_RGBA:
return true;
@ -1348,14 +1383,28 @@ static bool
IsIntegerFormatAndTypeUnpackable(GLenum format, GLenum type)
{
switch (type) {
case LOCAL_GL_UNSIGNED_SHORT:
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_INT:
case LOCAL_GL_INT:
switch (format) {
case LOCAL_GL_RED_INTEGER:
case LOCAL_GL_RG_INTEGER:
case LOCAL_GL_RGB_INTEGER:
case LOCAL_GL_RGBA_INTEGER:
return true;
default:
return false;
}
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
return format == LOCAL_GL_RGBA ||
format == LOCAL_GL_RGBA_INTEGER;
case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
return format == LOCAL_GL_RGB;
default:
return false;
}
@ -1418,7 +1467,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
return ErrorInvalidValue("readPixels: null destination buffer");
if (!(IsWebGL2() && IsIntegerFormatAndTypeUnpackable(format, type)) &&
!IsFormatAndTypeUnpackable(format, type)) {
!IsFormatAndTypeUnpackable(format, type, IsWebGL2())) {
return ErrorInvalidEnum("readPixels: Bad format or type.");
}
@ -1427,9 +1476,18 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
// Check the format param
switch (format) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_RED:
case LOCAL_GL_RED_INTEGER:
channels = 1;
break;
case LOCAL_GL_LUMINANCE_ALPHA:
case LOCAL_GL_RG:
case LOCAL_GL_RG_INTEGER:
channels = 2;
break;
case LOCAL_GL_RGB:
case LOCAL_GL_RGB_INTEGER:
channels = 3;
break;
case LOCAL_GL_RGBA:
@ -1445,11 +1503,22 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
int bytesPerPixel;
int requiredDataType;
switch (type) {
case LOCAL_GL_BYTE:
bytesPerPixel = 1*channels;
requiredDataType = js::Scalar::Int8;
break;
case LOCAL_GL_UNSIGNED_BYTE:
bytesPerPixel = 1*channels;
requiredDataType = js::Scalar::Uint8;
break;
case LOCAL_GL_SHORT:
bytesPerPixel = 2*channels;
requiredDataType = js::Scalar::Int16;
break;
case LOCAL_GL_UNSIGNED_SHORT:
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
@ -1457,13 +1526,21 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
requiredDataType = js::Scalar::Uint16;
break;
case LOCAL_GL_UNSIGNED_INT:
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
case LOCAL_GL_UNSIGNED_INT_24_8:
bytesPerPixel = 4;
requiredDataType = js::Scalar::Uint32;
break;
case LOCAL_GL_UNSIGNED_INT:
bytesPerPixel = 4*channels;
requiredDataType = js::Scalar::Uint32;
break;
case LOCAL_GL_INT:
bytesPerPixel = 4;
bytesPerPixel = 4*channels;
requiredDataType = js::Scalar::Int32;
break;
@ -1524,14 +1601,28 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
return;
auto srcType = srcFormat->format->componentType;
const bool isSrcTypeFloat = (srcType == webgl::ComponentType::Float);
// Check the format and type params to assure they are an acceptable pair (as per spec)
const GLenum mainReadFormat = LOCAL_GL_RGBA;
const GLenum mainReadType = isSrcTypeFloat ? LOCAL_GL_FLOAT
: LOCAL_GL_UNSIGNED_BYTE;
auto srcType = srcFormat->format->componentType;
GLenum mainReadFormat;
GLenum mainReadType;
switch (srcType) {
case webgl::ComponentType::Float:
mainReadFormat = LOCAL_GL_RGBA;
mainReadType = LOCAL_GL_FLOAT;
break;
case webgl::ComponentType::UInt:
mainReadFormat = LOCAL_GL_RGBA_INTEGER;
mainReadType = LOCAL_GL_UNSIGNED_INT;
break;
case webgl::ComponentType::Int:
mainReadFormat = LOCAL_GL_RGBA_INTEGER;
mainReadType = LOCAL_GL_INT;
break;
default:
mainReadFormat = LOCAL_GL_RGBA;
mainReadType = LOCAL_GL_UNSIGNED_BYTE;
break;
}
GLenum auxReadFormat = mainReadFormat;
GLenum auxReadType = mainReadType;
@ -1547,7 +1638,18 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
const bool mainMatches = (format == mainReadFormat && type == mainReadType);
const bool auxMatches = (format == auxReadFormat && type == auxReadType);
const bool isValid = mainMatches || auxMatches;
bool isValid = mainMatches || auxMatches;
// OpenGL ES 3.0.4 p194 - When the internal format of the rendering surface is
// RGB10_A2, a third combination of format RGBA and type UNSIGNED_INT_2_10_10_10_REV
// is accepted.
if (srcFormat->format->effectiveFormat == webgl::EffectiveFormat::RGB10_A2 &&
format == LOCAL_GL_RGBA &&
type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV)
{
isValid = true;
}
if (!isValid)
return ErrorInvalidOperation("readPixels: Invalid format/type pair");

View File

@ -310,6 +310,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
} else {
i = LOCAL_GL_UNSIGNED_BYTE;
}
return JS::NumberValue(uint32_t(i));
}
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
@ -330,6 +331,14 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
} else {
i = LOCAL_GL_RGBA;
}
// OpenGL ES 3.0.4 p112 Table 3.2 shows that read format SRGB_ALPHA is
// not supported. And if internal format of fbo is SRGB8_ALPHA8, then
// IMPLEMENTATION_COLOR_READ_FORMAT is SRGB_ALPHA which is not supported
// by ReadPixels. So, just return RGBA here.
if (i == LOCAL_GL_SRGB_ALPHA)
i = LOCAL_GL_RGBA;
return JS::NumberValue(uint32_t(i));
}
// int

View File

@ -187,6 +187,19 @@ WebGLContext::IsTexParamValid(GLenum pname) const
}
}
void
WebGLContext::InvalidateResolveCacheForTextureWithTexUnit(const GLuint texUnit)
{
if (mBound2DTextures[texUnit])
mBound2DTextures[texUnit]->InvalidateResolveCache();
if (mBoundCubeMapTextures[texUnit])
mBoundCubeMapTextures[texUnit]->InvalidateResolveCache();
if (mBound3DTextures[texUnit])
mBound3DTextures[texUnit]->InvalidateResolveCache();
if (mBound2DArrayTextures[texUnit])
mBound2DArrayTextures[texUnit]->InvalidateResolveCache();
}
//////////////////////////////////////////////////////////////////////////////////////////
// GL calls

View File

@ -989,7 +989,13 @@ WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName)
}
// Clear!
mContext->ForceClearFramebufferWithDefaultValues(clearBits, false);
{
// This FB maybe bind to GL_READ_FRAMEBUFFER and glClear only
// clear GL_DRAW_FRAMEBUFFER. So bind FB to GL_DRAW_FRAMEBUFFER
// here.
gl::ScopedBindFramebuffer autoFB(mContext->gl, mGLName);
mContext->ForceClearFramebufferWithDefaultValues(clearBits, false);
}
if (hasDrawBuffers) {
fnDrawBuffers(mDrawBuffers);

View File

@ -14,6 +14,15 @@ namespace mozilla {
WebGLSampler::WebGLSampler(WebGLContext* webgl, GLuint sampler)
: WebGLContextBoundObject(webgl)
, mGLName(sampler)
, mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
, mMagFilter(LOCAL_GL_LINEAR)
, mWrapS(LOCAL_GL_REPEAT)
, mWrapT(LOCAL_GL_REPEAT)
, mWrapR(LOCAL_GL_REPEAT)
, mMinLod(-1000)
, mMaxLod(1000)
, mCompareMode(LOCAL_GL_NONE)
, mCompareFunc(LOCAL_GL_LEQUAL)
{
mContext->mSamplers.insertBack(this);
}
@ -44,6 +53,72 @@ WebGLSampler::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
return dom::WebGLSamplerBinding::Wrap(cx, this, givenProto);
}
void
WebGLSampler::SamplerParameter1i(GLenum pname, GLint param)
{
switch (pname) {
case LOCAL_GL_TEXTURE_MIN_FILTER:
mMinFilter = param;
break;
case LOCAL_GL_TEXTURE_MAG_FILTER:
mMagFilter = param;
break;
case LOCAL_GL_TEXTURE_WRAP_S:
mWrapS = param;
break;
case LOCAL_GL_TEXTURE_WRAP_T:
mWrapT = param;
break;
case LOCAL_GL_TEXTURE_WRAP_R:
mWrapR = param;
break;
case LOCAL_GL_TEXTURE_COMPARE_MODE:
mCompareMode = param;
break;
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
mCompareFunc = param;
break;
default:
MOZ_CRASH("Unhandled pname");
break;
}
for (uint32_t i = 0; i < mContext->mBoundSamplers.Length(); ++i) {
if (this == mContext->mBoundSamplers[i])
mContext->InvalidateResolveCacheForTextureWithTexUnit(i);
}
}
void
WebGLSampler::SamplerParameter1f(GLenum pname, GLfloat param)
{
switch (pname) {
case LOCAL_GL_TEXTURE_MIN_LOD:
mMinLod = param;
break;
case LOCAL_GL_TEXTURE_MAX_LOD:
mMaxLod = param;
break;
default:
MOZ_CRASH("Unhandled pname");
break;
}
for (uint32_t i = 0; i < mContext->mBoundSamplers.Length(); ++i) {
if (this == mContext->mBoundSamplers[i])
mContext->InvalidateResolveCacheForTextureWithTexUnit(i);
}
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLSampler)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLSampler, AddRef)

View File

@ -19,6 +19,7 @@ class WebGLSampler final
, public WebGLContextBoundObject
{
friend class WebGLContext2;
friend class WebGLTexture;
public:
explicit WebGLSampler(WebGLContext* webgl, GLuint sampler);
@ -30,11 +31,24 @@ public:
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
void SamplerParameter1i(GLenum pname, GLint param);
void SamplerParameter1f(GLenum pname, GLfloat param);
private:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLSampler)
TexMinFilter mMinFilter;
TexMagFilter mMagFilter;
TexWrap mWrapS;
TexWrap mWrapT;
TexWrap mWrapR;
GLint mMinLod;
GLint mMaxLod;
TexCompareMode mCompareMode;
TexCompareFunc mCompareFunc;
private:
~WebGLSampler();
};

View File

@ -269,6 +269,22 @@ STRONG_GLENUM_BEGIN(TexWrap)
STRONG_GLENUM_VALUE(MIRRORED_REPEAT),
STRONG_GLENUM_END(TexWrap)
STRONG_GLENUM_BEGIN(TexCompareMode)
STRONG_GLENUM_VALUE(NONE),
STRONG_GLENUM_VALUE(COMPARE_REF_TO_TEXTURE),
STRONG_GLENUM_END(TexCompareMode)
STRONG_GLENUM_BEGIN(TexCompareFunc)
STRONG_GLENUM_VALUE(LEQUAL),
STRONG_GLENUM_VALUE(GEQUAL),
STRONG_GLENUM_VALUE(LESS),
STRONG_GLENUM_VALUE(GREATER),
STRONG_GLENUM_VALUE(EQUAL),
STRONG_GLENUM_VALUE(NOTEQUAL),
STRONG_GLENUM_VALUE(ALWAYS),
STRONG_GLENUM_VALUE(NEVER),
STRONG_GLENUM_END(TexCompareFunc)
STRONG_GLENUM_BEGIN(TexFormat)
STRONG_GLENUM_VALUE(NONE), // 0x0000
STRONG_GLENUM_VALUE(DEPTH_COMPONENT), // 0x1902

View File

@ -190,12 +190,12 @@ WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo)
}
bool
WebGLTexture::IsMipmapComplete() const
WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
{
MOZ_ASSERT(DoesMinFilterRequireMipmap());
// GLES 3.0.4, p161
const uint32_t maxLevel = MaxEffectiveMipmapLevel();
const uint32_t maxLevel = MaxEffectiveMipmapLevel(texUnit);
// "* `level_base <= level_max`"
if (mBaseMipmapLevel > maxLevel)
@ -290,7 +290,7 @@ WebGLTexture::IsCubeComplete() const
}
bool
WebGLTexture::IsComplete(const char** const out_reason) const
WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
{
// Texture completeness is established at GLES 3.0.4, p160-161.
// "[A] texture is complete unless any of the following conditions hold true:"
@ -315,19 +315,23 @@ WebGLTexture::IsComplete(const char** const out_reason) const
return false;
}
WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
TexMagFilter magFilter = sampler ? sampler->mMagFilter : mMagFilter;
// "* The minification filter requires a mipmap (is neither NEAREST nor LINEAR) and
// the texture is not mipmap complete."
const bool requiresMipmap = (mMinFilter != LOCAL_GL_NEAREST &&
mMinFilter != LOCAL_GL_LINEAR);
if (requiresMipmap && !IsMipmapComplete()) {
const bool requiresMipmap = (minFilter != LOCAL_GL_NEAREST &&
minFilter != LOCAL_GL_LINEAR);
if (requiresMipmap && !IsMipmapComplete(texUnit)) {
*out_reason = "Because the minification filter requires mipmapping, the texture"
" must be \"mipmap complete\".";
return false;
}
const bool isMinFilteringNearest = (mMinFilter == LOCAL_GL_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
const bool isMagFilteringNearest = (mMagFilter == LOCAL_GL_NEAREST);
const bool isMinFilteringNearest = (minFilter == LOCAL_GL_NEAREST ||
minFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
const bool isMagFilteringNearest = (magFilter == LOCAL_GL_NEAREST);
const bool isFilteringNearestOnly = (isMinFilteringNearest && isMagFilteringNearest);
if (!isFilteringNearestOnly) {
auto formatUsage = baseImageInfo.mFormat;
@ -394,9 +398,11 @@ WebGLTexture::IsComplete(const char** const out_reason) const
// non-power-of-two images, and either the texture wrap mode is not
// CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
if (!baseImageInfo.IsPowerOfTwo()) {
TexWrap wrapS = sampler ? sampler->mWrapS : mWrapS;
TexWrap wrapT = sampler ? sampler->mWrapT : mWrapT;
// "either the texture wrap mode is not CLAMP_TO_EDGE"
if (mWrapS != LOCAL_GL_CLAMP_TO_EDGE ||
mWrapT != LOCAL_GL_CLAMP_TO_EDGE)
if (wrapS != LOCAL_GL_CLAMP_TO_EDGE ||
wrapT != LOCAL_GL_CLAMP_TO_EDGE)
{
*out_reason = "Non-power-of-two textures must have a wrap mode of"
" CLAMP_TO_EDGE.";
@ -421,10 +427,12 @@ WebGLTexture::IsComplete(const char** const out_reason) const
uint32_t
WebGLTexture::MaxEffectiveMipmapLevel() const
WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit) const
{
if (mMinFilter == LOCAL_GL_NEAREST ||
mMinFilter == LOCAL_GL_LINEAR)
WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
if (minFilter == LOCAL_GL_NEAREST ||
minFilter == LOCAL_GL_LINEAR)
{
// No mips used.
return mBaseMipmapLevel;
@ -442,7 +450,7 @@ WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
FakeBlackType* const out_fakeBlack)
{
const char* incompleteReason;
if (!IsComplete(&incompleteReason)) {
if (!IsComplete(texUnit, &incompleteReason)) {
if (incompleteReason) {
mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
" 'incomplete', and will be rendered as"
@ -458,7 +466,7 @@ WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
bool hasUninitializedData = false;
bool hasInitializedData = false;
const auto maxLevel = MaxEffectiveMipmapLevel();
const auto maxLevel = MaxEffectiveMipmapLevel(texUnit);
MOZ_ASSERT(mBaseMipmapLevel <= maxLevel);
for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
for (uint8_t face = 0; face < mFaceCount; face++) {
@ -734,6 +742,12 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
return;
}
if (!baseImageInfo.mFormat->isRenderable || !baseImageInfo.mFormat->isFilterable) {
mContext->ErrorInvalidOperation("generateMipmap: Texture at base level is not"
" color-renderable or texture-filterable.");
return;
}
// Done with validation. Do the operation.
mContext->MakeContextCurrent();

View File

@ -284,7 +284,7 @@ protected:
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
uint32_t MaxEffectiveMipmapLevel() const;
uint32_t MaxEffectiveMipmapLevel(uint32_t texUnit) const;
static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
GLenum rawTexImageTarget = texImageTarget.get();
@ -369,11 +369,11 @@ public:
bool AreAllLevel0ImageInfosEqual() const;
bool IsMipmapComplete() const;
bool IsMipmapComplete(uint32_t texUnit) const;
bool IsCubeComplete() const;
bool IsComplete(const char** const out_reason) const;
bool IsComplete(uint32_t texUnit, const char** const out_reason) const;
bool IsMipmapCubeComplete() const;

View File

@ -11265,22 +11265,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0);
// Fails on Linux with Azure/Cairo only
// The arc is drawn badly due to Cairo limitations, the error only becomes
// apparent on Linux because of anti-aliasing, probably due to X.
// The limitation is that Cairo draws arcs by stroking perpendicular to the arc,
// and at very large stroke thicknesses, this becomes a fan. Where exactly the
// 'blades' of the fan appear seems to depend on exactly how the arc is defined
// and the platform. So if the blades of the fan are where pixels are tested it
// passes the test, if the testing pixels fall in between the blades, then we fail.
// With Thebes/Cairo, we were rendering wrong, but got lucky with the test, now
// we are not so lucky.
// Bug 764125
if (IsAzureCairo() && IsLinux()) {
todo_isPixel(ctx, 20,48, 0,255,0,255, 0);
} else {
isPixel(ctx, 20,48, 0,255,0,255, 0);
}
isPixel(ctx, 20,48, 0,255,0,255, 0);
isPixel(ctx, 98,48, 0,255,0,255, 0);
}

View File

@ -2121,7 +2121,8 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mElementInTreeState(ELEMENT_NOT_INTREE),
mHasUserInteraction(false),
mFirstFrameLoaded(false),
mDefaultPlaybackStartPosition(0.0)
mDefaultPlaybackStartPosition(0.0),
mIsAudioTrackAudible(false)
{
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
@ -5177,5 +5178,14 @@ HTMLMediaElement::IsCurrentlyPlaying() const
return false;
}
void
HTMLMediaElement::NotifyAudibleStateChanged(bool aAudible)
{
if (mIsAudioTrackAudible != aAudible) {
mIsAudioTrackAudible = aAudible;
// To do ...
}
}
} // namespace dom
} // namespace mozilla

View File

@ -397,6 +397,9 @@ public:
// when the connection between Rtsp server and client gets lost.
virtual void ResetConnectionState() final override;
// Called by media decoder when the audible state changed.
virtual void NotifyAudibleStateChanged(bool aAudible) final override;
// XPCOM GetPreload() is OK
void SetPreload(const nsAString& aValue, ErrorResult& aRv)
{
@ -1525,6 +1528,9 @@ private:
// initially be set to zero seconds. This time is used to allow the element to
// be seeked even before the media is loaded.
double mDefaultPlaybackStartPosition;
// True if the audio track is producing audible sound.
bool mIsAudioTrackAudible;
};
} // namespace dom

View File

@ -1934,6 +1934,21 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
// be set later with the updated mValueBeingSet.
return true;
}
if (NS_WARN_IF(!mBoundFrame)) {
// We're not sure if this case is possible.
} else {
// If setting value won't change current value, we shouldn't commit
// composition for compatibility with the other browsers.
nsAutoString currentValue;
mBoundFrame->GetText(currentValue);
if (newValue == currentValue) {
// Note that in this case, we shouldn't fire any events with setting
// value because event handlers may try to set value recursively but
// we cannot commit composition at that time due to unsafe to run
// script (see below).
return true;
}
}
// If there is composition, need to commit composition first because
// other browsers do that.
// NOTE: We don't need to block nested calls of this because input nor

View File

@ -54,6 +54,23 @@ AudioData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
return size;
}
bool
AudioData::IsAudible() const
{
if (!mAudioData) {
return false;
}
for (uint32_t frame = 0; frame < mFrames; ++frame) {
for (uint32_t channel = 0; channel < mChannels; ++channel) {
if (mAudioData[frame * mChannels + channel] != 0) {
return true;
}
}
}
return false;
}
/* static */
already_AddRefed<AudioData>
AudioData::TransferAndUpdateTimestampAndDuration(AudioData* aOther,

View File

@ -149,6 +149,10 @@ public:
// If mAudioBuffer is null, creates it from mAudioData.
void EnsureAudioBuffer();
// To check whether mAudioData has audible signal, it's used to distinguish
// the audiable data and silent data.
bool IsAudible() const;
const uint32_t mChannels;
const uint32_t mRate;
// At least one of mAudioBuffer/mAudioData must be non-null.

View File

@ -532,6 +532,8 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
"MediaDecoder::mStateMachineDuration (Mirror)")
, mPlaybackPosition(AbstractThread::MainThread(), 0,
"MediaDecoder::mPlaybackPosition (Mirror)")
, mIsAudioDataAudible(AbstractThread::MainThread(), false,
"MediaDecoder::mIsAudioDataAudible (Mirror)")
, mVolume(AbstractThread::MainThread(), 0.0,
"MediaDecoder::mVolume (Canonical)")
, mPlaybackRate(AbstractThread::MainThread(), 1.0,
@ -592,6 +594,8 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
// mIgnoreProgressData
mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
mWatchManager.Watch(mIsAudioDataAudible, &MediaDecoder::NotifyAudibleStateChanged);
MediaShutdownManager::Instance().Register(this);
}
@ -623,6 +627,8 @@ MediaDecoder::Shutdown()
mOnSeekingStart.Disconnect();
mOnMediaNotSeekable.Disconnect();
mWatchManager.Unwatch(mIsAudioDataAudible, &MediaDecoder::NotifyAudibleStateChanged);
shutdown = mDecoderStateMachine->BeginShutdown()
->Then(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::FinishShutdown,
@ -1473,6 +1479,7 @@ MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
mNextFrameStatus.Connect(mDecoderStateMachine->CanonicalNextFrameStatus());
mCurrentPosition.Connect(mDecoderStateMachine->CanonicalCurrentPosition());
mPlaybackPosition.Connect(mDecoderStateMachine->CanonicalPlaybackOffset());
mIsAudioDataAudible.Connect(mDecoderStateMachine->CanonicalIsAudioDataAudible());
} else {
mStateMachineDuration.DisconnectIfConnected();
mBuffered.DisconnectIfConnected();
@ -1480,6 +1487,7 @@ MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
mNextFrameStatus.DisconnectIfConnected();
mCurrentPosition.DisconnectIfConnected();
mPlaybackPosition.DisconnectIfConnected();
mIsAudioDataAudible.DisconnectIfConnected();
}
}
@ -1831,6 +1839,13 @@ MediaDecoder::NextFrameBufferedStatus()
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
}
void
MediaDecoder::NotifyAudibleStateChanged()
{
MOZ_ASSERT(!mShuttingDown);
mOwner->NotifyAudibleStateChanged(mIsAudioDataAudible);
}
MediaMemoryTracker::MediaMemoryTracker()
{
}

View File

@ -777,6 +777,9 @@ protected:
// start playing back again.
Mirror<int64_t> mPlaybackPosition;
// Used to distiguish whether the audio is producing sound.
Mirror<bool> mIsAudioDataAudible;
// Volume of playback. 0.0 = muted. 1.0 = full volume.
Canonical<double> mVolume;
@ -872,6 +875,9 @@ public:
}
private:
// Notify owner when the audible state changed
void NotifyAudibleStateChanged();
/* Functions called by ResourceCallback */
// A media stream is assumed to be infinite if the metadata doesn't

View File

@ -130,6 +130,9 @@ public:
// when the connection between Rtsp server and client gets lost.
virtual void ResetConnectionState() = 0;
// Called by media decoder when the audible state changed
virtual void NotifyAudibleStateChanged(bool aAudible) = 0;
#ifdef MOZ_EME
// Dispatches a "encrypted" event to the HTMLMediaElement, with the
// provided init data. Actual dispatch may be delayed until HAVE_METADATA.

View File

@ -116,6 +116,11 @@ static const int AUDIO_DURATION_USECS = 40000;
// increase it by more.
static const int THRESHOLD_FACTOR = 2;
// When the continuous silent data is over this threshold, means the a/v does
// not produce any sound. This time is decided by UX suggestion, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1235612#c18
static const uint32_t SILENT_DATA_THRESHOLD_USECS = 10000000;
namespace detail {
// If we have less than this much undecoded data available, we'll consider
@ -236,6 +241,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mOutputStreamManager(new OutputStreamManager()),
mResource(aDecoder->GetResource()),
mAudioOffloading(false),
mSilentDataDuration(0),
mBuffered(mTaskQueue, TimeIntervals(),
"MediaDecoderStateMachine::mBuffered (Mirror)"),
mEstimatedDuration(mTaskQueue, NullableTimeUnit(),
@ -272,7 +278,9 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mCurrentPosition(mTaskQueue, 0,
"MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
mPlaybackOffset(mTaskQueue, 0,
"MediaDecoderStateMachine::mPlaybackOffset (Canonical)")
"MediaDecoderStateMachine::mPlaybackOffset (Canonical)"),
mIsAudioDataAudible(mTaskQueue, false,
"MediaDecoderStateMachine::mIsAudioDataAudible (Canonical)")
{
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -709,14 +717,36 @@ MediaDecoderStateMachine::PushFront(MediaData* aSample, MediaData::Type aSampleT
UpdateNextFrameStatus();
}
void
MediaDecoderStateMachine::CheckIsAudible(const MediaData* aSample)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(aSample->mType == MediaData::AUDIO_DATA);
const AudioData* data = aSample->As<AudioData>();
bool isAudible = data->IsAudible();
if (isAudible && !mIsAudioDataAudible) {
mIsAudioDataAudible = true;
mSilentDataDuration = 0;
} else if (isAudible && mIsAudioDataAudible) {
mSilentDataDuration += data->mDuration;
if (mSilentDataDuration > SILENT_DATA_THRESHOLD_USECS) {
mIsAudioDataAudible = false;
mSilentDataDuration = 0;
}
}
}
void
MediaDecoderStateMachine::OnAudioPopped(const RefPtr<MediaData>& aSample)
{
MOZ_ASSERT(OnTaskQueue());
mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
UpdateNextFrameStatus();
DispatchAudioDecodeTaskIfNeeded();
MaybeStartBuffering();
CheckIsAudible(aSample);
}
void
@ -2168,6 +2198,7 @@ MediaDecoderStateMachine::FinishShutdown()
mNextFrameStatus.DisconnectAll();
mCurrentPosition.DisconnectAll();
mPlaybackOffset.DisconnectAll();
mIsAudioDataAudible.DisconnectAll();
// Shut down the watch manager before shutting down our task queue.
mWatchManager.Shutdown();

View File

@ -405,6 +405,7 @@ protected:
void OnAudioPopped(const RefPtr<MediaData>& aSample);
void OnVideoPopped(const RefPtr<MediaData>& aSample);
void CheckIsAudible(const MediaData* aSample);
void VolumeChanged();
void LogicalPlaybackRateChanged();
void PreservesPitchChanged();
@ -1195,6 +1196,9 @@ private:
// Playback will not start when audio is offloading.
bool mAudioOffloading;
// Duration of the continuous silent data.
uint32_t mSilentDataDuration;
#ifdef MOZ_EME
void OnCDMProxyReady(RefPtr<CDMProxy> aProxy);
void OnCDMProxyNotReady();
@ -1263,6 +1267,9 @@ private:
// Current playback position in the stream in bytes.
Canonical<int64_t> mPlaybackOffset;
// Used to distiguish whether the audio is producing sound.
Canonical<bool> mIsAudioDataAudible;
public:
AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() {
return mReader->CanonicalBuffered();
@ -1282,6 +1289,9 @@ public:
AbstractCanonical<int64_t>* CanonicalPlaybackOffset() {
return &mPlaybackOffset;
}
AbstractCanonical<bool>* CanonicalIsAudioDataAudible() {
return &mIsAudioDataAudible;
}
};
} // namespace mozilla

View File

@ -47,6 +47,7 @@ public:
return nullptr;
}
void ResetConnectionState() override {}
void NotifyAudibleStateChanged(bool aAudible) override {}
};
}

View File

@ -9,6 +9,9 @@
#ifdef XP_WIN
#include "WMFDecoderModule.h"
#endif
#ifdef MOZ_FFVPX
#include "FFVPXRuntimeLinker.h"
#endif
#ifdef MOZ_FFMPEG
#include "FFmpegRuntimeLinker.h"
#endif
@ -53,6 +56,10 @@ bool PDMFactory::sAndroidMCDecoderEnabled = false;
bool PDMFactory::sAndroidMCDecoderPreferred = false;
#endif
bool PDMFactory::sGMPDecoderEnabled = false;
#ifdef MOZ_FFVPX
bool PDMFactory::sFFVPXDecoderEnabled = false;
using namespace ffvpx;
#endif
#ifdef MOZ_FFMPEG
bool PDMFactory::sFFmpegDecoderEnabled = false;
#endif
@ -94,6 +101,10 @@ PDMFactory::Init()
Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled,
"media.ffmpeg.enabled", false);
#endif
#ifdef MOZ_FFVPX
Preferences::AddBoolVarCache(&sFFVPXDecoderEnabled,
"media.ffvpx.enabled", false);
#endif
#ifdef XP_WIN
Preferences::AddBoolVarCache(&sWMFDecoderEnabled,
"media.wmf.enabled", false);
@ -112,6 +123,9 @@ PDMFactory::Init()
#ifdef MOZ_APPLEMEDIA
AppleDecoderModule::Init();
#endif
#ifdef MOZ_FFVPX
FFVPXRuntimeLinker::Link();
#endif
#ifdef MOZ_FFMPEG
FFmpegRuntimeLinker::Link();
#endif
@ -262,6 +276,12 @@ PDMFactory::CreatePDMs()
StartupPDM(m);
}
#endif
#ifdef MOZ_FFVPX
if (sFFVPXDecoderEnabled) {
m = FFVPXRuntimeLinker::CreateDecoderModule();
StartupPDM(m);
}
#endif
#ifdef MOZ_FFMPEG
if (sFFmpegDecoderEnabled) {
m = FFmpegRuntimeLinker::CreateDecoderModule();

View File

@ -73,6 +73,9 @@ private:
static bool sAndroidMCDecoderEnabled;
#endif
static bool sGMPDecoderEnabled;
#ifdef MOZ_FFVPX
static bool sFFVPXDecoderEnabled;
#endif
#ifdef MOZ_FFMPEG
static bool sFFmpegDecoderEnabled;
#endif

View File

@ -101,7 +101,7 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
AVPacket packet;
av_init_packet(&packet);
AV_CALL(av_init_packet(&packet));
packet.data = const_cast<uint8_t*>(aSample->Data());
packet.size = aSample->Size();
@ -118,7 +118,7 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
while (packet.size > 0) {
int decoded;
int bytesConsumed =
avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet);
AV_CALL(avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet));
if (bytesConsumed < 0) {
NS_WARNING("FFmpeg audio decoder error.");

View File

@ -54,7 +54,7 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
StaticMutexAutoLock mon(sMonitor);
if (!(mCodecContext = avcodec_alloc_context3(codec))) {
if (!(mCodecContext = AV_CALL(avcodec_alloc_context3(codec)))) {
NS_WARNING("Couldn't init ffmpeg context");
return NS_ERROR_FAILURE;
}
@ -77,10 +77,10 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
}
if (avcodec_open2(mCodecContext, codec, nullptr) < 0) {
if (AV_CALL(avcodec_open2(mCodecContext, codec, nullptr)) < 0) {
NS_WARNING("Couldn't initialise ffmpeg decoder");
avcodec_close(mCodecContext);
av_freep(&mCodecContext);
AV_CALL(avcodec_close(mCodecContext));
AV_CALL(av_freep(&mCodecContext));
return NS_ERROR_FAILURE;
}
@ -141,7 +141,7 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (mCodecContext) {
avcodec_flush_buffers(mCodecContext);
AV_CALL(avcodec_flush_buffers(mCodecContext));
}
MonitorAutoLock mon(mMonitor);
mIsFlushing = false;
@ -154,12 +154,12 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
StaticMutexAutoLock mon(sMonitor);
if (sFFmpegInitDone && mCodecContext) {
avcodec_close(mCodecContext);
av_freep(&mCodecContext);
AV_CALL(avcodec_close(mCodecContext));
AV_CALL(av_freep(&mCodecContext));
#if LIBAVCODEC_VERSION_MAJOR >= 55
av_frame_free(&mFrame);
AV_CALL(av_frame_free(&mFrame));
#elif LIBAVCODEC_VERSION_MAJOR == 54
avcodec_free_frame(&mFrame);
AV_CALL(avcodec_free_frame(&mFrame));
#else
delete mFrame;
mFrame = nullptr;
@ -173,20 +173,20 @@ FFmpegDataDecoder<LIBAV_VER>::PrepareFrame()
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
#if LIBAVCODEC_VERSION_MAJOR >= 55
if (mFrame) {
av_frame_unref(mFrame);
AV_CALL(av_frame_unref(mFrame));
} else {
mFrame = av_frame_alloc();
mFrame = AV_CALL(av_frame_alloc());
}
#elif LIBAVCODEC_VERSION_MAJOR == 54
if (mFrame) {
avcodec_get_frame_defaults(mFrame);
AV_CALL(avcodec_get_frame_defaults(mFrame));
} else {
mFrame = avcodec_alloc_frame();
mFrame = AV_CALL(avcodec_alloc_frame());
}
#else
delete mFrame;
mFrame = new AVFrame;
avcodec_get_frame_defaults(mFrame);
AV_CALL(avcodec_get_frame_defaults(mFrame));
#endif
return mFrame;
}
@ -196,13 +196,13 @@ FFmpegDataDecoder<LIBAV_VER>::FindAVCodec(AVCodecID aCodec)
{
StaticMutexAutoLock mon(sMonitor);
if (!sFFmpegInitDone) {
avcodec_register_all();
AV_CALL(avcodec_register_all());
#ifdef DEBUG
av_log_set_level(AV_LOG_DEBUG);
AV_CALL(av_log_set_level(AV_LOG_DEBUG));
#endif
sFFmpegInitDone = true;
}
return avcodec_find_decoder(aCodec);
return AV_CALL(avcodec_find_decoder(aCodec));
}
} // namespace mozilla

View File

@ -9,7 +9,7 @@
#include "PlatformDecoderModule.h"
#include "FFmpegAudioDecoder.h"
#include "FFmpegH264Decoder.h"
#include "FFmpegVideoDecoder.h"
namespace mozilla
{
@ -37,8 +37,8 @@ public:
MediaDataDecoderCallback* aCallback) override
{
RefPtr<MediaDataDecoder> decoder =
new FFmpegH264Decoder<V>(aVideoTaskQueue, aCallback, aConfig,
aImageContainer);
new FFmpegVideoDecoder<V>(aVideoTaskQueue, aCallback, aConfig,
aImageContainer);
return decoder.forget();
}
@ -47,15 +47,23 @@ public:
FlushableTaskQueue* aAudioTaskQueue,
MediaDataDecoderCallback* aCallback) override
{
#ifdef USING_MOZFFVPX
return nullptr;
#else
RefPtr<MediaDataDecoder> decoder =
new FFmpegAudioDecoder<V>(aAudioTaskQueue, aCallback, aConfig);
return decoder.forget();
#endif
}
bool SupportsMimeType(const nsACString& aMimeType) const override
{
#ifdef USING_MOZFFVPX
AVCodecID audioCodec = AV_CODEC_ID_NONE;
#else
AVCodecID audioCodec = FFmpegAudioDecoder<V>::GetCodecId(aMimeType);
AVCodecID videoCodec = FFmpegH264Decoder<V>::GetCodecId(aMimeType);
#endif
AVCodecID videoCodec = FFmpegVideoDecoder<V>::GetCodecId(aMimeType);
if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) {
return false;
}

View File

@ -31,14 +31,29 @@ extern "C" {
typedef CodecID AVCodecID;
#endif
#ifdef FFVPX_VERSION
enum { LIBAV_VER = FFVPX_VERSION };
#else
enum { LIBAV_VER = LIBAVCODEC_VERSION_MAJOR };
#endif
namespace mozilla {
#ifdef USING_MOZFFVPX
namespace ffvpx {
#endif
#define AV_FUNC(func, ver) extern decltype(func)* func;
#include "FFmpegFunctionList.h"
#undef AV_FUNC
#ifdef USING_MOZFFVPX
} // namespace ffvpx
#define AV_CALL(func) mozilla::ffvpx::func
#else
#define AV_CALL(func) mozilla::func
#endif
}
#endif // __FFmpegLibs_h__

View File

@ -7,18 +7,9 @@
#include "FFmpegRuntimeLinker.h"
#include "mozilla/ArrayUtils.h"
#include "FFmpegLog.h"
#include "mozilla/Preferences.h"
#include "mozilla/Types.h"
#include "nsIFile.h"
#include "nsXPCOMPrivate.h" // for XUL_DLL
#include "prmem.h"
#include "prlink.h"
#if defined(XP_WIN)
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#endif
namespace mozilla
{
@ -77,7 +68,6 @@ FFmpegRuntimeLinker::Link()
if (sLinkStatus) {
return sLinkStatus == LinkStatus_SUCCEEDED;
}
MOZ_ASSERT(NS_IsMainThread());
for (size_t i = 0; i < ArrayLength(sLibs); i++) {
@ -100,54 +90,6 @@ FFmpegRuntimeLinker::Link()
}
FFMPEG_LOG(" ]\n");
#ifdef MOZ_FFVPX
// We retrieve the path of the XUL library as this is where mozavcodec and
// mozavutil libs are located.
char* path =
PR_GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFmpegRuntimeLinker::Link);
if (!path) {
return false;
}
nsCOMPtr<nsIFile> xulFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
if (!xulFile ||
NS_FAILED(xulFile->InitWithNativePath(nsDependentCString(path)))) {
PR_Free(path);
return false;
}
PR_Free(path);
nsCOMPtr<nsIFile> rootDir;
if (NS_FAILED(xulFile->GetParent(getter_AddRefs(rootDir))) || !rootDir) {
return false;
}
nsAutoCString rootPath;
if (NS_FAILED(rootDir->GetNativePath(rootPath))) {
return false;
}
char* libname = NULL;
/* Get the platform-dependent library name of the module */
libname = PR_GetLibraryName(rootPath.get(), "mozavutil");
if (!libname) {
return false;
}
sLinkedUtilLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
libname = PR_GetLibraryName(rootPath.get(), "mozavcodec");
if (!libname) {
Unlink();
return false;
}
sLinkedLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
if (sLinkedLib && sLinkedUtilLib) {
if (Bind("mozavcodec")) {
sLinkStatus = LinkStatus_SUCCEEDED;
return true;
}
}
#endif
Unlink();
sLinkStatus = LinkStatus_FAILED;
@ -218,12 +160,10 @@ FFmpegRuntimeLinker::CreateDecoderModule()
RefPtr<PlatformDecoderModule> module;
switch (major) {
#ifndef XP_WIN
case 53: module = FFmpegDecoderModule<53>::Create(); break;
case 54: module = FFmpegDecoderModule<54>::Create(); break;
case 55:
case 56: module = FFmpegDecoderModule<55>::Create(); break;
#endif
case 57: module = FFmpegDecoderModule<57>::Create(); break;
default: module = nullptr;
}

View File

@ -12,7 +12,7 @@
#include "MediaInfo.h"
#include "FFmpegH264Decoder.h"
#include "FFmpegVideoDecoder.h"
#include "FFmpegLog.h"
#include "mozilla/PodOperations.h"
@ -59,7 +59,7 @@ ChoosePixelFormat(AVCodecContext* aCodecContext, const AVPixelFormat* aFormats)
return AV_PIX_FMT_NONE;
}
FFmpegH264Decoder<LIBAV_VER>::PtsCorrectionContext::PtsCorrectionContext()
FFmpegVideoDecoder<LIBAV_VER>::PtsCorrectionContext::PtsCorrectionContext()
: mNumFaultyPts(0)
, mNumFaultyDts(0)
, mLastPts(INT64_MIN)
@ -68,7 +68,7 @@ FFmpegH264Decoder<LIBAV_VER>::PtsCorrectionContext::PtsCorrectionContext()
}
int64_t
FFmpegH264Decoder<LIBAV_VER>::PtsCorrectionContext::GuessCorrectPts(int64_t aPts, int64_t aDts)
FFmpegVideoDecoder<LIBAV_VER>::PtsCorrectionContext::GuessCorrectPts(int64_t aPts, int64_t aDts)
{
int64_t pts = AV_NOPTS_VALUE;
@ -90,7 +90,7 @@ FFmpegH264Decoder<LIBAV_VER>::PtsCorrectionContext::GuessCorrectPts(int64_t aPts
}
void
FFmpegH264Decoder<LIBAV_VER>::PtsCorrectionContext::Reset()
FFmpegVideoDecoder<LIBAV_VER>::PtsCorrectionContext::Reset()
{
mNumFaultyPts = 0;
mNumFaultyDts = 0;
@ -98,7 +98,7 @@ FFmpegH264Decoder<LIBAV_VER>::PtsCorrectionContext::Reset()
mLastDts = INT64_MIN;
}
FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
FFmpegVideoDecoder<LIBAV_VER>::FFmpegVideoDecoder(
FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
const VideoInfo& aConfig,
ImageContainer* aImageContainer)
@ -108,14 +108,14 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
, mImage(aConfig.mImage)
, mCodecParser(nullptr)
{
MOZ_COUNT_CTOR(FFmpegH264Decoder);
MOZ_COUNT_CTOR(FFmpegVideoDecoder);
// Use a new MediaByteBuffer as the object will be modified during initialization.
mExtraData = new MediaByteBuffer;
mExtraData->AppendElements(*aConfig.mExtraData);
}
RefPtr<MediaDataDecoder::InitPromise>
FFmpegH264Decoder<LIBAV_VER>::Init()
FFmpegVideoDecoder<LIBAV_VER>::Init()
{
if (NS_FAILED(InitDecoder())) {
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
@ -125,7 +125,7 @@ FFmpegH264Decoder<LIBAV_VER>::Init()
}
void
FFmpegH264Decoder<LIBAV_VER>::InitCodecContext()
FFmpegVideoDecoder<LIBAV_VER>::InitCodecContext()
{
mCodecContext->width = mImage.width;
mCodecContext->height = mImage.height;
@ -151,14 +151,14 @@ FFmpegH264Decoder<LIBAV_VER>::InitCodecContext()
// FFmpeg will call back to this to negotiate a video pixel format.
mCodecContext->get_format = ChoosePixelFormat;
mCodecParser = av_parser_init(mCodecID);
mCodecParser = AV_CALL(av_parser_init(mCodecID));
if (mCodecParser) {
mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
}
}
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
FFmpegVideoDecoder<LIBAV_VER>::DecodeResult
FFmpegVideoDecoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
@ -175,10 +175,10 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
while (inputSize) {
uint8_t* data;
int size;
int len = av_parser_parse2(mCodecParser, mCodecContext, &data, &size,
inputData, inputSize,
aSample->mTime, aSample->mTimecode,
aSample->mOffset);
int len = AV_CALL(av_parser_parse2(mCodecParser, mCodecContext, &data, &size,
inputData, inputSize,
aSample->mTime, aSample->mTimecode,
aSample->mOffset));
if (size_t(len) > inputSize) {
mCallback->Error();
return DecodeResult::DECODE_ERROR;
@ -203,14 +203,14 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
return DoDecodeFrame(aSample, inputData, inputSize);
}
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
FFmpegVideoDecoder<LIBAV_VER>::DecodeResult
FFmpegVideoDecoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
uint8_t* aData, int aSize)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
AVPacket packet;
av_init_packet(&packet);
AV_CALL(av_init_packet(&packet));
packet.data = aData;
packet.size = aSize;
@ -237,7 +237,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
int decoded;
int bytesConsumed =
avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet);
AV_CALL(avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet));
FFMPEG_LOG("DoDecodeFrame:decode_video: rv=%d decoded=%d "
"(Input: pts(%lld) dts(%lld) Output: pts(%lld) "
@ -317,7 +317,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
}
void
FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(MediaRawData* aSample)
FFmpegVideoDecoder<LIBAV_VER>::DecodeFrame(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
@ -328,11 +328,11 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(MediaRawData* aSample)
}
nsresult
FFmpegH264Decoder<LIBAV_VER>::Input(MediaRawData* aSample)
FFmpegVideoDecoder<LIBAV_VER>::Input(MediaRawData* aSample)
{
nsCOMPtr<nsIRunnable> runnable(
NS_NewRunnableMethodWithArg<RefPtr<MediaRawData>>(
this, &FFmpegH264Decoder<LIBAV_VER>::DecodeFrame,
this, &FFmpegVideoDecoder<LIBAV_VER>::DecodeFrame,
RefPtr<MediaRawData>(aSample)));
mTaskQueue->Dispatch(runnable.forget());
@ -340,7 +340,7 @@ FFmpegH264Decoder<LIBAV_VER>::Input(MediaRawData* aSample)
}
void
FFmpegH264Decoder<LIBAV_VER>::ProcessDrain()
FFmpegVideoDecoder<LIBAV_VER>::ProcessDrain()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
RefPtr<MediaRawData> empty(new MediaRawData());
@ -350,24 +350,24 @@ FFmpegH264Decoder<LIBAV_VER>::ProcessDrain()
}
void
FFmpegH264Decoder<LIBAV_VER>::ProcessFlush()
FFmpegVideoDecoder<LIBAV_VER>::ProcessFlush()
{
mPtsContext.Reset();
mDurationMap.Clear();
FFmpegDataDecoder::ProcessFlush();
}
FFmpegH264Decoder<LIBAV_VER>::~FFmpegH264Decoder()
FFmpegVideoDecoder<LIBAV_VER>::~FFmpegVideoDecoder()
{
MOZ_COUNT_DTOR(FFmpegH264Decoder);
MOZ_COUNT_DTOR(FFmpegVideoDecoder);
if (mCodecParser) {
av_parser_close(mCodecParser);
AV_CALL(av_parser_close(mCodecParser));
mCodecParser = nullptr;
}
}
AVCodecID
FFmpegH264Decoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
FFmpegVideoDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
{
if (aMimeType.EqualsLiteral("video/avc") || aMimeType.EqualsLiteral("video/mp4")) {
return AV_CODEC_ID_H264;

View File

@ -4,8 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __FFmpegH264Decoder_h__
#define __FFmpegH264Decoder_h__
#ifndef __FFmpegVideoDecoder_h__
#define __FFmpegVideoDecoder_h__
#include "FFmpegDataDecoder.h"
#include "mozilla/Pair.h"
@ -15,12 +15,12 @@ namespace mozilla
{
template <int V>
class FFmpegH264Decoder : public FFmpegDataDecoder<V>
class FFmpegVideoDecoder : public FFmpegDataDecoder<V>
{
};
template <>
class FFmpegH264Decoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
class FFmpegVideoDecoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
{
typedef mozilla::layers::Image Image;
typedef mozilla::layers::ImageContainer ImageContainer;
@ -32,11 +32,11 @@ class FFmpegH264Decoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
};
public:
FFmpegH264Decoder(FlushableTaskQueue* aTaskQueue,
FFmpegVideoDecoder(FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
const VideoInfo& aConfig,
ImageContainer* aImageContainer);
virtual ~FFmpegH264Decoder();
virtual ~FFmpegVideoDecoder();
RefPtr<InitPromise> Init() override;
nsresult Input(MediaRawData* aSample) override;
@ -122,4 +122,4 @@ private:
} // namespace mozilla
#endif // __FFmpegH264Decoder_h__
#endif // __FFmpegVideoDecoder_h__

View File

@ -8,7 +8,7 @@ UNIFIED_SOURCES += [
'../FFmpegAudioDecoder.cpp',
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegH264Decoder.cpp',
'../FFmpegVideoDecoder.cpp',
]
LOCAL_INCLUDES += [
'..',
@ -21,9 +21,5 @@ if CONFIG['CLANG_CXX']:
CXXFLAGS += [
'-Wno-unknown-attributes',
]
if CONFIG['_MSC_VER']:
CXXFLAGS += [
'-wd4996', # deprecated declaration
]
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,162 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "FFVPXRuntimeLinker.h"
#include "FFmpegRuntimeLinker.h"
#include "FFmpegLog.h"
#include "mozilla/Types.h"
#include "nsIFile.h"
#include "nsXPCOMPrivate.h" // for XUL_DLL
#include "prmem.h"
#include "prlink.h"
#if defined(XP_WIN)
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#endif
namespace mozilla
{
template <int V> class FFmpegDecoderModule
{
public:
static already_AddRefed<PlatformDecoderModule> Create();
};
namespace ffvpx
{
FFVPXRuntimeLinker::LinkStatus FFVPXRuntimeLinker::sLinkStatus =
LinkStatus_INIT;
PRLibrary* FFVPXRuntimeLinker::sLinkedLib = nullptr;
PRLibrary* FFVPXRuntimeLinker::sLinkedUtilLib = nullptr;
static unsigned (*avcodec_version)() = nullptr;
#ifdef __GNUC__
#define AV_FUNC(func, ver) void (*func)();
#define LIBAVCODEC_ALLVERSION
#else
#define AV_FUNC(func, ver) decltype(func)* func;
#endif
#include "FFmpegFunctionList.h"
#undef AV_FUNC
static PRLibrary*
MozAVLink(const char* aName)
{
PRLibSpec lspec;
lspec.type = PR_LibSpec_Pathname;
lspec.value.pathname = aName;
return PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
}
/* static */ bool
FFVPXRuntimeLinker::Link()
{
if (sLinkStatus) {
return sLinkStatus == LinkStatus_SUCCEEDED;
}
MOZ_ASSERT(NS_IsMainThread());
// We retrieve the path of the XUL library as this is where mozavcodec and
// mozavutil libs are located.
char* path =
PR_GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Link);
if (!path) {
return false;
}
nsCOMPtr<nsIFile> xulFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
if (!xulFile ||
NS_FAILED(xulFile->InitWithNativePath(nsDependentCString(path)))) {
PR_Free(path);
return false;
}
PR_Free(path);
nsCOMPtr<nsIFile> rootDir;
if (NS_FAILED(xulFile->GetParent(getter_AddRefs(rootDir))) || !rootDir) {
return false;
}
nsAutoCString rootPath;
if (NS_FAILED(rootDir->GetNativePath(rootPath))) {
return false;
}
char* libname = NULL;
/* Get the platform-dependent library name of the module */
libname = PR_GetLibraryName(rootPath.get(), "mozavutil");
if (!libname) {
return false;
}
sLinkedUtilLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
libname = PR_GetLibraryName(rootPath.get(), "mozavcodec");
if (libname) {
sLinkedLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
if (sLinkedLib && sLinkedUtilLib) {
if (Bind("mozavcodec")) {
sLinkStatus = LinkStatus_SUCCEEDED;
return true;
}
}
}
Unlink();
sLinkStatus = LinkStatus_FAILED;
return false;
}
/* static */ bool
FFVPXRuntimeLinker::Bind(const char* aLibName)
{
int version = AV_FUNC_57;
#define AV_FUNC(func, ver) \
if ((ver) & version) { \
if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? sLinkedUtilLib : sLinkedLib, #func))) { \
FFMPEG_LOG("Couldn't load function " #func " from %s.", aLibName); \
return false; \
} \
} else { \
func = (decltype(func))nullptr; \
}
#include "FFmpegFunctionList.h"
#undef AV_FUNC
return true;
}
/* static */ already_AddRefed<PlatformDecoderModule>
FFVPXRuntimeLinker::CreateDecoderModule()
{
if (!Link()) {
return nullptr;
}
return FFmpegDecoderModule<FFVPX_VERSION>::Create();
}
/* static */ void
FFVPXRuntimeLinker::Unlink()
{
if (sLinkedUtilLib && sLinkedUtilLib != sLinkedLib) {
PR_UnloadLibrary(sLinkedUtilLib);
}
if (sLinkedLib) {
PR_UnloadLibrary(sLinkedLib);
sLinkedLib = nullptr;
sLinkStatus = LinkStatus_INIT;
avcodec_version = nullptr;
}
sLinkedUtilLib = nullptr;
}
#undef LIBAVCODEC_ALLVERSION
} // namespace ffvpx
} // namespace mozilla

View File

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __FFVPXRuntimeLinker_h__
#define __FFVPXRuntimeLinker_h__
#include "PlatformDecoderModule.h"
struct PRLibrary;
namespace mozilla
{
namespace ffvpx
{
class FFVPXRuntimeLinker
{
public:
static bool Link();
static void Unlink();
static already_AddRefed<PlatformDecoderModule> CreateDecoderModule();
private:
static PRLibrary* sLinkedLib;
static PRLibrary* sLinkedUtilLib;
static enum LinkStatus {
LinkStatus_INIT = 0,
LinkStatus_FAILED,
LinkStatus_SUCCEEDED
} sLinkStatus;
static bool Bind(const char* aLibName);
};
}
}
#endif /* __FFVPXRuntimeLinker_h__ */

View File

@ -0,0 +1,44 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
LOCAL_INCLUDES += ['/xpcom/build']
EXPORTS += [
'FFVPXRuntimeLinker.h',
]
UNIFIED_SOURCES += [
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegVideoDecoder.cpp',
]
SOURCES += [
'FFVPXRuntimeLinker.cpp',
]
LOCAL_INCLUDES += [
'..',
'../ffmpeg57/include',
]
if CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'../ffmpeg57/include',
]
if CONFIG['GNU_CXX']:
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
if CONFIG['CLANG_CXX']:
CXXFLAGS += [
'-Wno-unknown-attributes',
]
if CONFIG['_MSC_VER']:
CXXFLAGS += [
'-wd4996', # deprecated declaration
]
DEFINES['FFVPX_VERSION'] = 46465650
DEFINES['USING_MOZFFVPX'] = True
FINAL_LIBRARY = 'xul'

View File

@ -8,7 +8,7 @@ UNIFIED_SOURCES += [
'../FFmpegAudioDecoder.cpp',
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegH264Decoder.cpp',
'../FFmpegVideoDecoder.cpp',
]
LOCAL_INCLUDES += [
'..',

View File

@ -8,7 +8,7 @@ UNIFIED_SOURCES += [
'../FFmpegAudioDecoder.cpp',
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegH264Decoder.cpp',
'../FFmpegVideoDecoder.cpp',
]
LOCAL_INCLUDES += [
'..',

View File

@ -8,7 +8,7 @@ UNIFIED_SOURCES += [
'../FFmpegAudioDecoder.cpp',
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegH264Decoder.cpp',
'../FFmpegVideoDecoder.cpp',
]
LOCAL_INCLUDES += [
'..',
@ -21,9 +21,5 @@ if CONFIG['CLANG_CXX']:
CXXFLAGS += [
'-Wno-unknown-attributes',
]
if CONFIG['_MSC_VER']:
CXXFLAGS += [
'-wd4996', # deprecated declaration
]
FINAL_LIBRARY = 'xul'

View File

@ -38,26 +38,22 @@ if CONFIG['MOZ_WMF']:
if CONFIG['MOZ_EME']:
DIRS += ['agnostic/eme']
if CONFIG['MOZ_FFVPX']:
DIRS += [
'ffmpeg/ffvpx',
]
if CONFIG['MOZ_FFMPEG']:
LOCAL_INCLUDES += ['/xpcom/build']
EXPORTS += [
'ffmpeg/FFmpegRuntimeLinker.h',
]
UNIFIED_SOURCES += [
'ffmpeg/FFmpegRuntimeLinker.cpp',
]
if CONFIG['OS_ARCH'] != 'WINNT':
DIRS += [
'ffmpeg/libav53',
'ffmpeg/libav54',
'ffmpeg/libav55',
]
else:
LOCAL_INCLUDES += [
'ffmpeg/ffmpeg57/include',
]
DIRS += [
'ffmpeg/libav53',
'ffmpeg/libav54',
'ffmpeg/libav55',
'ffmpeg/ffmpeg57',
]

View File

@ -36,7 +36,6 @@ const kSmsDeletedObserverTopic = "sms-deleted";
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
const kNetworkConnStateChangedTopic = "network-connection-state-changed";
const kPrefRilRadioDisabled = "ril.radio.disabled";
const kPrefMmsDebuggingEnabled = "mms.debugging.enabled";
// HTTP status codes:
@ -194,18 +193,12 @@ function getDefaultServiceId() {
}
/**
* Return Radio disabled state.
* Return radio disabled state.
*/
function getRadioDisabledState() {
let state;
try {
state = Services.prefs.getBoolPref(kPrefRilRadioDisabled);
} catch (e) {
if (DEBUG) debug("Getting preference 'ril.radio.disabled' fails.");
state = false;
}
return state;
function isRadioOff(aServiceId) {
let connection = gMobileConnectionService.getItemByServiceId(aServiceId);
return connection.radioState
!== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED;
}
/**
@ -422,7 +415,7 @@ MmsConnection.prototype = {
this.pendingCallbacks.push(callback);
let errorStatus;
if (getRadioDisabledState()) {
if (isRadioOff(this.serviceId)) {
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
errorStatus = _HTTP_STATUS_RADIO_DISABLED;
} else if (this.getCardState() != Ci.nsIIcc.CARD_STATE_READY) {
@ -993,7 +986,8 @@ function CancellableTransaction(cancellableId, serviceId) {
this.isCancelled = false;
}
CancellableTransaction.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsIMobileConnectionListener]),
// The timer for retrying sending or retrieving process.
timer: null,
@ -1010,8 +1004,9 @@ CancellableTransaction.prototype = {
if (!this.isObserversAdded) {
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
Services.obs.addObserver(this, kSmsDeletedObserverTopic, false);
Services.prefs.addObserver(kPrefRilRadioDisabled, this, false);
Services.prefs.addObserver(kPrefDefaultServiceId, this, false);
gMobileConnectionService
.getItemByServiceId(this.serviceId).registerListener(this);
this.isObserversAdded = true;
}
@ -1023,8 +1018,9 @@ CancellableTransaction.prototype = {
if (this.isObserversAdded) {
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
Services.obs.removeObserver(this, kSmsDeletedObserverTopic);
Services.prefs.removeObserver(kPrefRilRadioDisabled, this);
Services.prefs.removeObserver(kPrefDefaultServiceId, this);
gMobileConnectionService
.getItemByServiceId(this.serviceId).unregisterListener(this);
this.isObserversAdded = false;
}
},
@ -1080,18 +1076,35 @@ CancellableTransaction.prototype = {
break;
}
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: {
if (data == kPrefRilRadioDisabled) {
if (getRadioDisabledState()) {
this.cancelRunning(_MMS_ERROR_RADIO_DISABLED);
}
} else if (data === kPrefDefaultServiceId &&
if (data === kPrefDefaultServiceId &&
this.serviceId != getDefaultServiceId()) {
this.cancelRunning(_MMS_ERROR_SIM_CARD_CHANGED);
}
break;
}
}
}
},
// nsIMobileConnectionListener
notifyVoiceChanged: function() {},
notifyDataChanged: function() {},
notifyDataError: function(message) {},
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
notifyOtaStatusChanged: function(status) {},
notifyRadioStateChanged: function() {
if (isRadioOff(this.serviceId)) {
this.cancelRunning(_MMS_ERROR_RADIO_DISABLED);
}
},
notifyClirModeChanged: function(mode) {},
notifyLastKnownNetworkChanged: function() {},
notifyLastKnownHomeNetworkChanged: function() {},
notifyNetworkSelectionModeChanged: function() {},
notifyDeviceIdentitiesChanged: function() {}
};
/**
@ -2388,7 +2401,7 @@ MmsService.prototype = {
}
// Check radio state in prior to default service Id.
if (getRadioDisabledState()) {
if (isRadioOff(aServiceId)) {
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
sendTransactionCb(mmsMessage,
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR,
@ -2502,7 +2515,13 @@ MmsService.prototype = {
// Hence, for manual retrieving, instead of checking radio state later
// in MmsConnection.acquire(), We have to check radio state in prior to
// iccId to return the error correctly.
if (getRadioDisabledState()) {
let numRadioInterfaces = gMobileConnectionService.numItems;
let isAllRadioOff = true;
for (let serviceId = 0; serviceId < numRadioInterfaces; serviceId++) {
isAllRadioOff &= isRadioOff(serviceId);
}
if (isAllRadioOff) {
if (DEBUG) debug("Error! Radio is disabled when retrieving MMS.");
aRequest.notifyGetMessageFailed(
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR);

View File

@ -663,3 +663,60 @@ function runIfMultiSIM(aTest) {
return Promise.resolve();
}
}
/**
* Helper to enable/disable connection radio state.
*
* @param aConnection
* connection to enable / disable
* @param aEnabled
* True to enable the radio.
* @return a Promise object.
*/
function setRadioEnabled(aConnection, aEnabled) {
log("setRadioEnabled to " + aEnabled);
let deferred = Promise.defer();
let finalState = (aEnabled) ? "enabled" : "disabled";
if (aConnection.radioState == finalState) {
return deferred.resolve(aConnection);
}
aConnection.onradiostatechange = function() {
log("Received 'radiostatechange', radioState: " + aConnection.radioState);
if (aConnection.radioState == finalState) {
deferred.resolve(aConnection);
aConnection.onradiostatechange = null;
}
};
let req = aConnection.setRadioEnabled(aEnabled);
req.onsuccess = function() {
log("setRadioEnabled success");
};
req.onerror = function() {
ok(false, "setRadioEnabled should not fail");
deferred.reject();
};
return deferred.promise;
}
/**
* Helper to enable/disable all connections radio state.
*
* @param aEnabled
* True to enable the radio.
* @return a Promise object.
*/
function setAllRadioEnabled(aEnabled) {
let promises = []
for (let i = 0; i < window.navigator.mozMobileConnections.length; ++i) {
promises.push(ensureMobileConnection(i)
.then((connection) => setRadioEnabled(connection, aEnabled)));
}
return Promise.all(promises);
}

View File

@ -2,6 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
// We apply "chrome" context to be more flexible to
// specify the content of M-Notification.ind such as iccId
// for different kinds of testing.
@ -17,11 +18,17 @@ var gMobileMessageDatabaseService =
.getService(Ci.nsIGonkMobileMessageDatabaseService);
var gUuidGenerator =
Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
var gMmsService = Cc["@mozilla.org/mms/gonkmmsservice;1"]
.getService(Ci.nsIMmsService);
var gMmsService =
Cc["@mozilla.org/mms/gonkmmsservice;1"].getService(Ci.nsIMmsService);
var gMobileConnectionService =
Cc["@mozilla.org/mobileconnection/mobileconnectionservice;1"]
.getService(Ci.nsIMobileConnectionService);
var gIccService =
Cc["@mozilla.org/icc/gonkiccservice;1"].getService(Ci.nsIIccService);
function saveMmsNotification() {
log("saveMmsNotification()");
@ -101,23 +108,111 @@ function retrieveMmsWithFailure(aId) {
return deferred.promise;
}
function testRetrieve(aCause, aInit, aCleanup) {
function testRetrieve(aCause) {
log("testRetrieve: aCause = " + aCause);
return Promise.resolve()
.then(() => { if (aInit) aInit(); })
.then(saveMmsNotification)
.then((message) => retrieveMmsWithFailure(message.id))
.then((response) => verifyErrorCause(response, aCause))
.then(() => { if (aCleanup) aCleanup(); });
.then((response) => verifyErrorCause(response, aCause));
}
var setRadioDisabled = function(aDisabled) {
log("set ril.radio.disabled to " + aDisabled);
Services.prefs.setBoolPref("ril.radio.disabled", aDisabled);
};
function setRadioEnabled(aConnection, aEnabled) {
let deferred = Promise.defer();
let finalState = (aEnabled) ?
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED :
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED;
testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR,
setRadioDisabled.bind(null, true),
setRadioDisabled.bind(null, false))
if (aConnection.radioState == finalState) {
return deferred.resolve(aConnection);
}
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionListener]),
notifyVoiceChanged: function() {},
notifyDataChanged: function() {},
notifyDataError: function(message) {},
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
notifyOtaStatusChanged: function(status) {},
notifyRadioStateChanged: function() {
log("setRadioEnabled state changed to " + aConnection.radioState);
if (aConnection.radioState == finalState) {
aConnection.unregisterListener(listener);
deferred.resolve(aConnection);
}
},
notifyClirModeChanged: function(mode) {},
notifyLastKnownNetworkChanged: function() {},
notifyLastKnownHomeNetworkChanged: function() {},
notifyNetworkSelectionModeChanged: function() {},
notifyDeviceIdentitiesChanged: function() {}
};
let callback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
notifySuccess() {},
notifySuccessWithBoolean(result) {},
notifyGetNetworksSuccess(count, networks) {},
notifyGetCallForwardingSuccess(count, results) {},
notifyGetCallBarringSuccess(program, enabled, serviceClass) {},
notifyGetCallWaitingSuccess(serviceClass) {},
notifyGetClirStatusSuccess(n, m) {},
notifyGetPreferredNetworkTypeSuccess(type) {},
notifyGetRoamingPreferenceSuccess(mode) {},
notifyError(name) {
log("setRadioEnabled reject");
aConnection.unregisterListener(listener);
deferred.reject();
}
};
aConnection.registerListener(listener);
aConnection.setRadioEnabled(aEnabled, callback);
return deferred.promise;
}
function setAllRadioEnabled(aEnabled) {
log("setAllRadioEnabled connection number = " +
gMobileConnectionService.numItems);
let promises = [];
for (let i = 0; i < gMobileConnectionService.numItems; ++i) {
promises.push(setRadioEnabled(
gMobileConnectionService.getItemByServiceId(i), aEnabled));
}
return Promise.all(promises);
}
function waitIccReady(aIcc) {
let deferred = Promise.defer();
if (aIcc.cardState == Ci.nsIIcc.CARD_STATE_READY) {
return deferred.resolve(aIcc);
}
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccListener]),
notifyStkCommand(aStkProactiveCmd) {},
notifyStkSessionEnd() {},
notifyCardStateChanged() {
if (aIcc.cardState == Ci.nsIIcc.CARD_STATE_READY) {
aIcc.unregisterListener(listener);
deferred.resolve(aIcc);
}
},
notifyIccInfoChanged() {}
};
aIcc.registerListener(listener);
return deferred.promise;
}
function waitAllIccReady() {
let promises = [];
for (let i = 0; i < gMobileConnectionService.numItems; ++i) {
let icc = gIccService.getIccByServiceId(i);
promises.push(waitIccReady(icc));
}
return Promise.all(promises);
}
setAllRadioEnabled(false)
.then(() => testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR))
.then(() => setAllRadioEnabled(true))
.then(() => waitAllIccReady())
.then(() => testRetrieve(Ci.nsIMobileMessageCallback.SIM_NOT_MATCHED_ERROR))
.then(finish);

View File

@ -4,8 +4,6 @@
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const kPrefRilRadioDisabled = "ril.radio.disabled";
function testSendFailed(aCause, aServiceId) {
log("testSendFailed, aCause: " + aCause + ", aServiceId: " + aServiceId);
let sendParameters;
@ -44,13 +42,9 @@ function testSendFailed(aCause, aServiceId) {
startTestCommon(function testCaseMain() {
return Promise.resolve()
.then(() => {
SpecialPowers.setBoolPref(kPrefRilRadioDisabled, true);
})
.then(() => testSendFailed("RadioDisabledError"))
.then(() => {
SpecialPowers.setBoolPref(kPrefRilRadioDisabled, false);
})
.then(() => setAllRadioEnabled(false))
.then(() => testSendFailed("RadioDisabledError"), 0)
.then(() => setAllRadioEnabled(true))
.then(() => runIfMultiSIM(
() => testSendFailed("NonActiveSimCardError", 1)));
});

View File

@ -4,79 +4,6 @@
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const kPrefRilRadioDisabled = "ril.radio.disabled";
var connection;
function ensureMobileConnection() {
let deferred = Promise.defer();
let permissions = [{
"type": "mobileconnection",
"allow": true,
"context": document,
}];
SpecialPowers.pushPermissions(permissions, function() {
ok(true, "permissions pushed: " + JSON.stringify(permissions));
connection = window.navigator.mozMobileConnections[0];
if (connection) {
log("navigator.mozMobileConnections[0] is instance of " + connection.constructor);
} else {
log("navigator.mozMobileConnections[0] is undefined.");
}
if (connection instanceof MozMobileConnection) {
deferred.resolve(connection);
} else {
deferred.reject();
}
});
return deferred.promise;
}
function waitRadioState(state) {
let deferred = Promise.defer();
waitFor(function() {
deferred.resolve();
}, function() {
return connection.radioState == state;
});
return deferred.promise;
}
function setRadioEnabled(enabled) {
log("setRadioEnabled to " + enabled);
let deferred = Promise.defer();
let finalState = (enabled) ? "enabled" : "disabled";
connection.onradiostatechange = function() {
let state = connection.radioState;
log("Received 'radiostatechange' event, radioState: " + state);
if (state == finalState) {
deferred.resolve();
connection.onradiostatechange = null;
}
};
let req = connection.setRadioEnabled(enabled);
req.onsuccess = function() {
log("setRadioEnabled success");
};
req.onerror = function() {
ok(false, "setRadioEnabled should not fail");
deferred.reject();
};
return deferred.promise;
}
function testSendFailed(aCause) {
log("testSendFailed, aCause: " + aCause);
@ -98,8 +25,7 @@ function testSendFailed(aCause) {
startTestCommon(function testCaseMain() {
return ensureMobileConnection()
.then(() => waitRadioState("enabled"))
.then(() => setRadioEnabled(false))
.then(() => setRadioEnabled(mobileConnection, false))
.then(() => testSendFailed("RadioDisabledError"))
.then(() => setRadioEnabled(true));
.then(() => setRadioEnabled(mobileConnection, true));
});

View File

@ -1,6 +1,6 @@
en_US-mozilla Hunspell Dictionary
Generated from SCOWL Version 2015.08.24
Sun Jan 10 15:07:17 EST 2016
Generated from SCOWL Version 2016.01.19
Thu Jan 21 14:36:28 EST 2016
http://wordlist.sourceforge.net
@ -24,9 +24,12 @@ The normal (non-large) dictionaries correspond to SCOWL size 60 and,
to encourage consistent spelling, generally only include one spelling
variant for a word. The large dictionaries correspond to SCOWL size
70 and may include multiple spelling for a word when both variants are
considered almost equal. Also, the general quality of the larger
dictionaries may also be less as they are not as carefully checked for
errors as the normal dictionaries.
considered almost equal. The larger dictionaries however (1) have not
been as carefully checked for errors as the normal dictionaries and
thus may contain misspelled or invalid words; and (2) contain
uncommon, yet valid, words that might cause problems as they are
likely to be misspellings of more common words (for example, "ort" and
"calender").
To get an idea of the difference in size, here are 25 random words
only found in the large dictionary for American English:
@ -42,7 +45,7 @@ basis. If you find them useful please send me a quick email at
kevina@gnu.org.
If none of these dictionaries suite you (for example, maybe you want
the larger dictionary but only use spelling of a word) additional
the normal dictionary that also includes common variants) additional
dictionaries can be generated at http://app.aspell.net/create or by
modifying speller/make-hunspell-dict in SCOWL. Please do let me know
if you end up publishing a customized dictionary.
@ -57,11 +60,16 @@ kevina@gnu.org or to the wordlist-devel mailing lists
have specific issues with any of these dictionaries please file a bug
report at https://github.com/kevina/wordlist/issues.
IMPORTANT CHANGES FROM 2015.02.15:
IMPORTANT CHANGES INTRODUCED IN 2015.04.24:
The dictionaries are now in UTF-8 format instead of ISO-8859-1. This
was required to handle smart quotes correctly.
IMPORTANT CHANGES INTRODUCED IN 2016.01.19:
"SET UTF8" was changes to "SET UTF-8" in the affix file as some
versions of Hunspell do not recognize "UTF8".
ADDITIONAL NOTES:
The NOSUGGEST flag was added to certain taboo words. While I made an
@ -311,4 +319,4 @@ from the Ispell distribution they are under the Ispell copyright:
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Build Date: Sun Jan 10 15:07:17 EST 2016
Build Date: Thu Jan 21 14:36:28 EST 2016

Some files were not shown because too many files have changed in this diff Show More