mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team, a=merge
This commit is contained in:
commit
8dfdddf741
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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)
|
||||
|
12
configure.in
12
configure.in
@ -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=,
|
||||
|
@ -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){
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
98
docshell/test/browser/file_bug422543_script.js
Normal file
98
docshell/test/browser/file_bug422543_script.js
Normal 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();
|
@ -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;
|
||||
|
@ -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]
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
void FireScriptAvailable(nsresult aResult)
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ private:
|
||||
|
||||
BluetoothA2dpManager();
|
||||
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ private:
|
||||
|
||||
BluetoothAvrcpManager();
|
||||
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
void NotifyConnectionStatusChanged();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -216,8 +216,9 @@ private:
|
||||
class ServerSendIndicationResultHandler;
|
||||
|
||||
BluetoothGattManager();
|
||||
bool Init();
|
||||
|
||||
nsresult Init();
|
||||
void Uninit();
|
||||
void HandleShutdown();
|
||||
|
||||
void RegisterClientNotification(BluetoothGattStatus aStatus,
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -176,6 +176,8 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
sBluetoothHfpManager = nullptr;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* Implement DeinitHfpInterface() for applications that want to create SCO
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -22,6 +22,8 @@ public:
|
||||
aName.AssignLiteral("HID");
|
||||
}
|
||||
|
||||
static void InitHidInterface(BluetoothProfileResultHandler* aRes);
|
||||
static void DeinitHidInterface(BluetoothProfileResultHandler* aRes);
|
||||
static BluetoothHidManager* Get();
|
||||
|
||||
// HID-specific functions
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -332,6 +332,8 @@ public:
|
||||
return ActiveBoundTextureForTarget(texTarget);
|
||||
}
|
||||
|
||||
void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
|
||||
|
||||
already_AddRefed<Layer>
|
||||
GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
|
||||
LayerManager* manager) override;
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
void ResetConnectionState() override {}
|
||||
void NotifyAudibleStateChanged(bool aAudible) override {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
@ -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__
|
@ -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'
|
||||
|
162
dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
Normal file
162
dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
Normal 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
|
43
dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.h
Normal file
43
dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.h
Normal 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__ */
|
44
dom/media/platforms/ffmpeg/ffvpx/moz.build
Normal file
44
dom/media/platforms/ffmpeg/ffvpx/moz.build
Normal 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'
|
@ -8,7 +8,7 @@ UNIFIED_SOURCES += [
|
||||
'../FFmpegAudioDecoder.cpp',
|
||||
'../FFmpegDataDecoder.cpp',
|
||||
'../FFmpegDecoderModule.cpp',
|
||||
'../FFmpegH264Decoder.cpp',
|
||||
'../FFmpegVideoDecoder.cpp',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
|
@ -8,7 +8,7 @@ UNIFIED_SOURCES += [
|
||||
'../FFmpegAudioDecoder.cpp',
|
||||
'../FFmpegDataDecoder.cpp',
|
||||
'../FFmpegDecoderModule.cpp',
|
||||
'../FFmpegH264Decoder.cpp',
|
||||
'../FFmpegVideoDecoder.cpp',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
|
@ -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'
|
||||
|
@ -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',
|
||||
]
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)));
|
||||
});
|
||||
|
@ -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));
|
||||
});
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user