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

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

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

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

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets 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="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -494,7 +494,7 @@
</div> </div>
<div id="learnMoreContainer"> <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>
<div id="buttonContainer"> <div id="buttonContainer">

View File

@ -272,7 +272,7 @@
</div> </div>
<p id="badStsCertExplanation">&certerror.whatShouldIDo.badStsCertExplanation;</p> <p id="badStsCertExplanation">&certerror.whatShouldIDo.badStsCertExplanation;</p>
<div> <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>
<div id="buttonContainer"> <div id="buttonContainer">

View File

@ -463,14 +463,19 @@ endif
endif endif
ifdef SYMBOLS_FILE 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 ifdef GCC_USE_GNU_LD
EXTRA_DSO_LDOPTS += -Wl,--version-script,$(SYMBOLS_FILE) EXTRA_DSO_LDOPTS += -Wl,--version-script,$(SYMBOLS_FILE)
else else
ifeq ($(OS_TARGET),Darwin) ifeq ($(OS_TARGET),Darwin)
EXTRA_DSO_LDOPTS += -Wl,-exported_symbols_list,$(SYMBOLS_FILE) EXTRA_DSO_LDOPTS += -Wl,-exported_symbols_list,$(SYMBOLS_FILE)
endif endif
ifeq ($(OS_TARGET),WINNT)
EXTRA_DSO_LDOPTS += -DEF:$(call normalizepath,$(SYMBOLS_FILE))
endif endif
endif endif
EXTRA_DEPS += $(SYMBOLS_FILE) EXTRA_DEPS += $(SYMBOLS_FILE)

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ class nsDOMNavigationTiming;
[ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming); [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming);
[ref] native nsIContentViewerTArray(nsTArray<nsCOMPtr<nsIContentViewer> >); [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 interface nsIContentViewer : nsISupports
{ {
[noscript] void init(in nsIWidgetPtr aParentWidget, [noscript] void init(in nsIWidgetPtr aParentWidget,
@ -229,6 +229,18 @@ interface nsIContentViewer : nsISupports
*/ */
[noscript] void appendSubtree(in nsIContentViewerTArray array); [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 * Render the document as if being viewed on a device with the specified
* media type. This will cause a reflow. * media type. This will cause a reflow.

View File

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

View File

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

View File

@ -1,26 +1,15 @@
function test() { add_task(function* test() {
waitForExplicitFinish(); 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; const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
var newBrowser; .getService(Ci.nsIScriptSecurityManager);
const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); is(secMan.isSystemPrincipal(prin), false,
"Loaded principal must not be system");
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);
}

View File

@ -1,174 +1,116 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */ * http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); add_task(function* runTests() {
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() {
yield setup(); yield setup();
let browser = gBrowser.selectedBrowser; 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. // Check if all history listeners are always notified.
info("# part 1"); info("# part 1");
browser.loadURI("http://www.example.com/"); yield whenPageShown(browser, () => browser.loadURI("http://www.example.com/"));
yield whenPageShown(browser); yield checkListeners("newentry", "shistory has a new entry");
checkListeners("newentry", "shistory has a new entry");
ok(browser.canGoBack, "we can go back"); ok(browser.canGoBack, "we can go back");
browser.goBack(); yield whenPageShown(browser, () => browser.goBack());
yield whenPageShown(browser); yield checkListeners("goback", "back to the first shentry");
checkListeners("goback", "back to the first shentry");
ok(browser.canGoForward, "we can go forward"); ok(browser.canGoForward, "we can go forward");
browser.goForward(); yield whenPageShown(browser, () => browser.goForward());
yield whenPageShown(browser); yield checkListeners("goforward", "forward to the second shentry");
checkListeners("goforward", "forward to the second shentry");
browser.reload(); yield whenPageShown(browser, () => browser.reload());
yield whenPageShown(browser); yield checkListeners("reload", "current shentry reloaded");
checkListeners("reload", "current shentry reloaded");
browser.gotoIndex(0); yield whenPageShown(browser, () => browser.gotoIndex(0));
yield whenPageShown(browser); yield checkListeners("gotoindex", "back to the first index");
checkListeners("gotoindex", "back to the first index");
// Check nsISHistoryInternal.notifyOnHistoryReload // Check nsISHistoryInternal.notifyOnHistoryReload
info("# part 2"); info("# part 2");
ok(notifyReload(), "reloading has not been canceled"); ok((yield notifyReload()), "reloading has not been canceled");
checkListeners("reload", "saw the reload notification"); yield checkListeners("reload", "saw the reload notification");
// Let the first listener cancel the reload action. // Let the first listener cancel the reload action.
info("# part 3"); info("# part 3");
resetListeners(); yield resetListeners();
gFirstListener.retval = false; yield setListenerRetval(0, false);
ok(!notifyReload(), "reloading has been canceled"); ok(!(yield notifyReload()), "reloading has been canceled");
checkListeners("reload", "saw the reload notification"); yield checkListeners("reload", "saw the reload notification");
// Let both listeners cancel the reload action. // Let both listeners cancel the reload action.
info("# part 4"); info("# part 4");
resetListeners(); yield resetListeners();
gSecondListener.retval = false; yield setListenerRetval(1, false);
ok(!notifyReload(), "reloading has been canceled"); ok(!(yield notifyReload()), "reloading has been canceled");
checkListeners("reload", "saw the reload notification"); yield checkListeners("reload", "saw the reload notification");
// Let the second listener cancel the reload action. // Let the second listener cancel the reload action.
info("# part 5"); info("# part 5");
resetListeners(); yield resetListeners();
gFirstListener.retval = true; yield setListenerRetval(0, true);
ok(!notifyReload(), "reloading has been canceled"); ok(!(yield notifyReload()), "reloading has been canceled");
checkListeners("reload", "saw the reload notification"); yield checkListeners("reload", "saw the reload notification");
} });
function checkListeners(aLast, aMessage) { function listenOnce(message, arg = {}) {
is(gFirstListener.last, aLast, aMessage); return new Promise(resolve => {
is(gSecondListener.last, aLast, aMessage); let mm = gBrowser.selectedBrowser.messageManager;
} mm.addMessageListener(message + ":return", function listener(msg) {
mm.removeMessageListener(message + ":return", listener);
function resetListeners() { resolve(msg.data);
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);
}); });
(aCallback || TestRunner.next)(); mm.sendAsyncMessage(message, arg);
}); });
} }
function whenPageShown(aBrowser, aCallback) { function checkListeners(aLast, aMessage) {
aBrowser.addEventListener("pageshow", function onLoad() { return listenOnce("bug422543:getListenerStatus").then((listenerStatuses) => {
aBrowser.removeEventListener("pageshow", onLoad, true); is(listenerStatuses[0], aLast, aMessage);
executeSoon(aCallback || TestRunner.next); is(listenerStatuses[1], aLast, aMessage);
}, true); });
} }
var TestRunner = { function resetListeners() {
run: function () { return listenOnce("bug422543:resetListeners");
waitForExplicitFinish(); }
this._iter = runTests();
this.next();
},
next: function () { function notifyReload() {
try { return listenOnce("bug422543:notifyReload").then(({ rval }) => {
TestRunner._iter.next(); return rval;
} catch (e if e instanceof StopIteration) { });
TestRunner.finish(); }
}
},
finish: function () { function setListenerRetval(num, val) {
finish(); return listenOnce("bug422543:setRetval", { num, val });
} }
};
function setup() {
return BrowserTestUtils.openNewForegroundTab(gBrowser,
"http://mochi.test:8888")
.then(function (tab) {
let browser = tab.linkedBrowser;
registerCleanupFunction(function* () {
yield listenOnce("bug422543:cleanup");
gBrowser.removeTab(tab);
});
browser.messageManager
.loadFrameScript(getRootDirectory(gTestPath) + "file_bug422543_script.js", false);
});
}
function whenPageShown(aBrowser, aNavigation) {
let listener = ContentTask.spawn(aBrowser, null, function () {
return new Promise(resolve => {
addEventListener("pageshow", function onLoad() {
removeEventListener("pageshow", onLoad, true);
resolve();
}, true);
});
});
aNavigation();
return listener;
}

View File

@ -10,51 +10,53 @@
const URL = "http://mochi.test:8888/browser/docshell/test/browser/file_bug670318.html"; const URL = "http://mochi.test:8888/browser/docshell/test/browser/file_bug670318.html";
function test() { add_task(function* test() {
waitForExplicitFinish(); 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 = { let listener = {
OnHistoryNewEntry: function (aNewURI) { OnHistoryNewEntry: function (aNewURI) {
if (aNewURI.spec == URL && 5 == ++count) { if (aNewURI.spec == URL && 5 == ++count) {
browser.addEventListener("load", function onLoad() { addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true); removeEventListener("load", onLoad, true);
ok(history.index < history.count, "history.index is valid"); ok(history.index < history.count, "history.index is valid");
finish(); testDone.resolve();
}, true); }, true);
history.removeSHistoryListener(listener); history.removeSHistoryListener(listener);
historyListenerRemoved = true; 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, QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
OnHistoryGoBack: () => true, Ci.nsISupportsWeakReference])
OnHistoryGoForward: () => true, };
OnHistoryGotoIndex: () => true,
OnHistoryPurge: () => true,
OnHistoryReplaceEntry: () => true,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener, history.addSHistoryListener(listener);
Ci.nsISupportsWeakReference]) content.location = URL;
}; yield testDone.promise;
});
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);
}); });
} });

View File

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

View File

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

View File

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

View File

@ -4,14 +4,6 @@
var testPath = "http://mochi.test:8888/browser/docshell/test/navigation/"; var testPath = "http://mochi.test:8888/browser/docshell/test/navigation/";
var ctx = {}; 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, // 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 // 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 // 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); 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 // Entry point from Mochikit
function test() { function test() {
@ -49,15 +47,13 @@ function step1() {
// Get a handle on the initial tab // Get a handle on the initial tab
ctx.tab0 = gBrowser.selectedTab; ctx.tab0 = gBrowser.selectedTab;
ctx.tab0Browser = gBrowser.getBrowserForTab(ctx.tab0); ctx.tab0Browser = gBrowser.getBrowserForTab(ctx.tab0);
ctx.tab0Window = ctx.tab0Browser.contentWindow;
// Our current tab should be active // 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 // Open a New Tab
ctx.tab1 = gBrowser.addTab(testPath + "bug343515_pg1.html"); ctx.tab1 = gBrowser.addTab(testPath + "bug343515_pg1.html");
ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1); ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1);
ctx.tab1Window = ctx.tab1Browser.contentWindow;
oneShotListener(ctx.tab1Browser, "load", step2); oneShotListener(ctx.tab1Browser, "load", step2);
} }
@ -66,24 +62,23 @@ function step2() {
"Got expected tab 1 url in step 2"); "Got expected tab 1 url in step 2");
// Our current tab should still be active // Our current tab should still be active
ok(isActive(ctx.tab0Window), "Tab 0 should still be active"); ok(ctx.tab0Browser.docShellIsActive, "Tab 0 should still be active");
ok(!isActive(ctx.tab1Window), "Tab 1 should not be active"); ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should not be active");
// Switch to tab 1 // 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 // Open another tab
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive"); ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html");
ok(isActive(ctx.tab1Window), "Tab 1 should be active"); ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2);
// Open another tab // bug343515_pg2.html consists of a page with two iframes,
ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html"); // which will therefore generate 3 load events.
ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2); nShotsListener(ctx.tab2Browser, "load", step3, 3);
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);
} }
function step3() { function step3() {
@ -91,115 +86,169 @@ function step3() {
"Got expected tab 2 url in step 3"); "Got expected tab 2 url in step 3");
// Tab 0 should be inactive, Tab 1 should be active // Tab 0 should be inactive, Tab 1 should be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive"); ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
// Tab 2's window _and_ its iframes should be inactive // Tab 2's window _and_ its iframes should be inactive
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive"); ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive");
is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes"); ContentTask.spawn(ctx.tab2Browser, null, function* () {
for (var i = 0; i < ctx.tab2Window.frames.length; i++) is(content.frames.length, 2, "Tab 2 should have 2 iframes");
info("step 3, frame " + i + " info: " + ctx.tab2Window.frames[i].location); for (var i = 0; i < content.frames.length; i++) {
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive"); info("step 3, frame " + i + " info: " + content.frames[i].location);
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive"); let docshell = content.frames[i].QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
// Navigate tab 2 to a different page ok(!docShell.isActive, `Tab2 iframe ${i} should be inactive`);
ctx.tab2Window.location = testPath + "bug343515_pg3.html"; }
}).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 // 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 // contains another iframe, so there'll be a total of 4 load events
nShotsListener(ctx.tab2Browser, "load", step4, 4); nShotsListener(ctx.tab2Browser, "load", step4, 4);
});
} }
function step4() { 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, is(testPath + "bug343515_pg3.html", ctx.tab2Browser.currentURI.spec,
"Got expected tab 2 url in step 4"); "Got expected tab 2 url in step 4");
// Tab 0 should be inactive, Tab 1 should be active // Tab 0 should be inactive, Tab 1 should be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive"); ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
// Tab2 and all descendants should be inactive // Tab2 and all descendants should be inactive
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive"); checkTab2Active(false).then(() => {
is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes"); // Switch to Tab 2
for (var i = 0; i < ctx.tab2Window.frames.length; i++) return BrowserTestUtils.switchTab(gBrowser, ctx.tab2);
info("step 4, frame " + i + " info: " + ctx.tab2Window.frames[i].location); }).then(() => {
is(ctx.tab2Window.frames[0].frames.length, 1, "Tab 2 iframe 0 should have 1 iframes"); // Check everything
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive"); ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be inactive"); ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive"); ok(ctx.tab2Browser.docShellIsActive, "Tab 2 should be active");
// 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();
return checkTab2Active(true);
}).then(() => {
// Go back
waitForPageshow(ctx.tab2Browser, step5);
ctx.tab2Browser.goBack();
});
} }
function step5() { function step5() {
// Check everything // Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive"); ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(!isActive(ctx.tab1Window), "Tab 1 should be inactive"); ok(!ctx.tab1Browser.docShellIsActive, "Tab 1 should be inactive");
ok(isActive(ctx.tab2Window), "Tab 2 should be active"); ok(ctx.tab2Browser.docShellIsActive, "Tab 2 should be active");
ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active"); ContentTask.spawn(ctx.tab2Browser, null, function* () {
ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active"); 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 ok(docShell.isActive, `Tab2 iframe ${i} should be active`);
gBrowser.selectedTab = ctx.tab1; }
}).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 // bug343515_pg3.html consists of a page with two iframes, one of which
ctx.tab1Window.location = testPath + "bug343515_pg3.html"; // 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() { function step6() {
// Check everything // Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive"); ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active"); ContentTask.spawn(ctx.tab1Browser, null, function* () {
ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active"); function isActive(aWindow) {
ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active"); var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive"); .getInterface(Ci.nsIWebNavigation)
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive"); .QueryInterface(Ci.nsIDocShell);
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive"); return docshell.isActive;
}
// Go forward on tab 2 ok(isActive(content.frames[0]), "Tab1 iframe 0 should be active");
oneShotListener(ctx.tab2Browser, "pageshow", step7); ok(isActive(content.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
var tab2docshell = ctx.tab2Window.QueryInterface(Ci.nsIInterfaceRequestor) ok(isActive(content.frames[1]), "Tab1 iframe 1 should be active");
.getInterface(Ci.nsIWebNavigation); }).then(() => {
tab2docshell.goForward(); 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 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 // Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive"); ok(!ctx.tab0Browser.docShellIsActive, "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active"); ok(ctx.tab1Browser.docShellIsActive, "Tab 1 should be active");
ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active"); checkBrowser(ctx.tab1Browser, 1, true).then(() => {
ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active"); ok(!ctx.tab2Browser.docShellIsActive, "Tab 2 should be inactive");
ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active"); return checkBrowser(ctx.tab2Browser, 2, false);
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive"); }).then(() => {
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive"); // That's probably enough
ok(!isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be inactive"); allDone();
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive"); });
// That's probably enough
allDone();
} }
function allDone() { function allDone() {

View File

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

View File

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

View File

@ -67,9 +67,6 @@ GetSriLog()
return gSriPRLog; 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) NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
nsScriptLoadRequestList::~nsScriptLoadRequestList() nsScriptLoadRequestList::~nsScriptLoadRequestList()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -389,26 +389,39 @@ BluetoothGattManager::Get()
NS_ENSURE_FALSE(mInShutdown, nullptr); NS_ENSURE_FALSE(mInShutdown, nullptr);
// Create a new instance, register, and return // Create a new instance, register, and return
BluetoothGattManager* manager = new BluetoothGattManager(); RefPtr<BluetoothGattManager> manager = new BluetoothGattManager();
NS_ENSURE_TRUE(manager->Init(), nullptr); NS_ENSURE_SUCCESS(manager->Init(), nullptr);
sBluetoothGattManager = manager; sBluetoothGattManager = manager;
return sBluetoothGattManager; return sBluetoothGattManager;
} }
bool nsresult
BluetoothGattManager::Init() BluetoothGattManager::Init()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 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!"); 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 class BluetoothGattManager::RegisterModuleResultHandler final
@ -569,6 +582,11 @@ public:
sBluetoothGattInterface->SetNotificationHandler(nullptr); sBluetoothGattInterface->SetNotificationHandler(nullptr);
sBluetoothGattInterface = nullptr; sBluetoothGattInterface = nullptr;
sClients = nullptr;
sServers = nullptr;
sBluetoothGattManager->Uninit();
sBluetoothGattManager = nullptr;
if (mRes) { if (mRes) {
mRes->OnError(NS_ERROR_FAILURE); mRes->OnError(NS_ERROR_FAILURE);
@ -584,6 +602,9 @@ public:
sClients = nullptr; sClients = nullptr;
sServers = nullptr; sServers = nullptr;
sBluetoothGattManager->Uninit();
sBluetoothGattManager = nullptr;
if (mRes) { if (mRes) {
mRes->Deinit(); mRes->Deinit();
} }
@ -4090,13 +4111,7 @@ BluetoothGattManager::BluetoothGattManager()
{ } { }
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 NS_IMETHODIMP
BluetoothGattManager::Observe(nsISupports* aSubject, BluetoothGattManager::Observe(nsISupports* aSubject,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1316,15 +1316,50 @@ WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei he
} }
static bool static bool
IsFormatAndTypeUnpackable(GLenum format, GLenum type) IsFormatAndTypeUnpackable(GLenum format, GLenum type, bool isWebGL2)
{ {
switch (type) { switch (type) {
case LOCAL_GL_UNSIGNED_BYTE: 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_FLOAT:
case LOCAL_GL_HALF_FLOAT: case LOCAL_GL_HALF_FLOAT:
case LOCAL_GL_HALF_FLOAT_OES: case LOCAL_GL_HALF_FLOAT_OES:
switch (format) { switch (format) {
case LOCAL_GL_ALPHA: case LOCAL_GL_RED:
case LOCAL_GL_RG:
case LOCAL_GL_RGB: case LOCAL_GL_RGB:
case LOCAL_GL_RGBA: case LOCAL_GL_RGBA:
return true; return true;
@ -1348,14 +1383,28 @@ static bool
IsIntegerFormatAndTypeUnpackable(GLenum format, GLenum type) IsIntegerFormatAndTypeUnpackable(GLenum format, GLenum type)
{ {
switch (type) { switch (type) {
case LOCAL_GL_UNSIGNED_SHORT:
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_INT: case LOCAL_GL_UNSIGNED_INT:
case LOCAL_GL_INT: case LOCAL_GL_INT:
switch (format) { switch (format) {
case LOCAL_GL_RED_INTEGER:
case LOCAL_GL_RG_INTEGER:
case LOCAL_GL_RGB_INTEGER:
case LOCAL_GL_RGBA_INTEGER: case LOCAL_GL_RGBA_INTEGER:
return true; return true;
default: default:
return false; 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: default:
return false; return false;
} }
@ -1418,7 +1467,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
return ErrorInvalidValue("readPixels: null destination buffer"); return ErrorInvalidValue("readPixels: null destination buffer");
if (!(IsWebGL2() && IsIntegerFormatAndTypeUnpackable(format, type)) && if (!(IsWebGL2() && IsIntegerFormatAndTypeUnpackable(format, type)) &&
!IsFormatAndTypeUnpackable(format, type)) { !IsFormatAndTypeUnpackable(format, type, IsWebGL2())) {
return ErrorInvalidEnum("readPixels: Bad format or type."); 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 // Check the format param
switch (format) { switch (format) {
case LOCAL_GL_ALPHA: case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_RED:
case LOCAL_GL_RED_INTEGER:
channels = 1; channels = 1;
break; 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:
case LOCAL_GL_RGB_INTEGER:
channels = 3; channels = 3;
break; break;
case LOCAL_GL_RGBA: case LOCAL_GL_RGBA:
@ -1445,11 +1503,22 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
int bytesPerPixel; int bytesPerPixel;
int requiredDataType; int requiredDataType;
switch (type) { switch (type) {
case LOCAL_GL_BYTE:
bytesPerPixel = 1*channels;
requiredDataType = js::Scalar::Int8;
break;
case LOCAL_GL_UNSIGNED_BYTE: case LOCAL_GL_UNSIGNED_BYTE:
bytesPerPixel = 1*channels; bytesPerPixel = 1*channels;
requiredDataType = js::Scalar::Uint8; requiredDataType = js::Scalar::Uint8;
break; 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_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
case LOCAL_GL_UNSIGNED_SHORT_5_6_5: 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; requiredDataType = js::Scalar::Uint16;
break; 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; bytesPerPixel = 4;
requiredDataType = js::Scalar::Uint32; requiredDataType = js::Scalar::Uint32;
break; break;
case LOCAL_GL_UNSIGNED_INT:
bytesPerPixel = 4*channels;
requiredDataType = js::Scalar::Uint32;
break;
case LOCAL_GL_INT: case LOCAL_GL_INT:
bytesPerPixel = 4; bytesPerPixel = 4*channels;
requiredDataType = js::Scalar::Int32; requiredDataType = js::Scalar::Int32;
break; break;
@ -1524,14 +1601,28 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight)) if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
return; 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) // Check the format and type params to assure they are an acceptable pair (as per spec)
auto srcType = srcFormat->format->componentType;
const GLenum mainReadFormat = LOCAL_GL_RGBA; GLenum mainReadFormat;
const GLenum mainReadType = isSrcTypeFloat ? LOCAL_GL_FLOAT GLenum mainReadType;
: LOCAL_GL_UNSIGNED_BYTE; 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 auxReadFormat = mainReadFormat;
GLenum auxReadType = mainReadType; 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 mainMatches = (format == mainReadFormat && type == mainReadType);
const bool auxMatches = (format == auxReadFormat && type == auxReadType); 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) if (!isValid)
return ErrorInvalidOperation("readPixels: Invalid format/type pair"); return ErrorInvalidOperation("readPixels: Invalid format/type pair");

View File

@ -310,6 +310,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
} else { } else {
i = LOCAL_GL_UNSIGNED_BYTE; i = LOCAL_GL_UNSIGNED_BYTE;
} }
return JS::NumberValue(uint32_t(i)); return JS::NumberValue(uint32_t(i));
} }
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: { case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
@ -330,6 +331,14 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
} else { } else {
i = LOCAL_GL_RGBA; 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)); return JS::NumberValue(uint32_t(i));
} }
// int // int

View File

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

View File

@ -989,7 +989,13 @@ WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName)
} }
// Clear! // 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) { if (hasDrawBuffers) {
fnDrawBuffers(mDrawBuffers); fnDrawBuffers(mDrawBuffers);

View File

@ -14,6 +14,15 @@ namespace mozilla {
WebGLSampler::WebGLSampler(WebGLContext* webgl, GLuint sampler) WebGLSampler::WebGLSampler(WebGLContext* webgl, GLuint sampler)
: WebGLContextBoundObject(webgl) : WebGLContextBoundObject(webgl)
, mGLName(sampler) , 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); mContext->mSamplers.insertBack(this);
} }
@ -44,6 +53,72 @@ WebGLSampler::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
return dom::WebGLSamplerBinding::Wrap(cx, this, 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_WRAPPERCACHE_0(WebGLSampler)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLSampler, AddRef) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLSampler, AddRef)

View File

@ -19,6 +19,7 @@ class WebGLSampler final
, public WebGLContextBoundObject , public WebGLContextBoundObject
{ {
friend class WebGLContext2; friend class WebGLContext2;
friend class WebGLTexture;
public: public:
explicit WebGLSampler(WebGLContext* webgl, GLuint sampler); explicit WebGLSampler(WebGLContext* webgl, GLuint sampler);
@ -30,11 +31,24 @@ public:
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override; virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
void SamplerParameter1i(GLenum pname, GLint param);
void SamplerParameter1f(GLenum pname, GLfloat param);
private: private:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler) NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(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: private:
~WebGLSampler(); ~WebGLSampler();
}; };

View File

@ -269,6 +269,22 @@ STRONG_GLENUM_BEGIN(TexWrap)
STRONG_GLENUM_VALUE(MIRRORED_REPEAT), STRONG_GLENUM_VALUE(MIRRORED_REPEAT),
STRONG_GLENUM_END(TexWrap) 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_BEGIN(TexFormat)
STRONG_GLENUM_VALUE(NONE), // 0x0000 STRONG_GLENUM_VALUE(NONE), // 0x0000
STRONG_GLENUM_VALUE(DEPTH_COMPONENT), // 0x1902 STRONG_GLENUM_VALUE(DEPTH_COMPONENT), // 0x1902

View File

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

View File

@ -284,7 +284,7 @@ protected:
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel); 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) { static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
GLenum rawTexImageTarget = texImageTarget.get(); GLenum rawTexImageTarget = texImageTarget.get();
@ -369,11 +369,11 @@ public:
bool AreAllLevel0ImageInfosEqual() const; bool AreAllLevel0ImageInfosEqual() const;
bool IsMipmapComplete() const; bool IsMipmapComplete(uint32_t texUnit) const;
bool IsCubeComplete() 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; bool IsMipmapCubeComplete() const;

View File

@ -11265,22 +11265,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 1,1, 0,255,0,255, 0); isPixel(ctx, 1,1, 0,255,0,255, 0);
isPixel(ctx, 98,1, 0,255,0,255, 0); isPixel(ctx, 98,1, 0,255,0,255, 0);
isPixel(ctx, 1,48, 0,255,0,255, 0); isPixel(ctx, 1,48, 0,255,0,255, 0);
// Fails on Linux with Azure/Cairo only isPixel(ctx, 20,48, 0,255,0,255, 0);
// 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, 98,48, 0,255,0,255, 0); isPixel(ctx, 98,48, 0,255,0,255, 0);
} }

View File

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

View File

@ -397,6 +397,9 @@ public:
// when the connection between Rtsp server and client gets lost. // when the connection between Rtsp server and client gets lost.
virtual void ResetConnectionState() final override; 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 // XPCOM GetPreload() is OK
void SetPreload(const nsAString& aValue, ErrorResult& aRv) 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 // initially be set to zero seconds. This time is used to allow the element to
// be seeked even before the media is loaded. // be seeked even before the media is loaded.
double mDefaultPlaybackStartPosition; double mDefaultPlaybackStartPosition;
// True if the audio track is producing audible sound.
bool mIsAudioTrackAudible;
}; };
} // namespace dom } // namespace dom

View File

@ -1934,6 +1934,21 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
// be set later with the updated mValueBeingSet. // be set later with the updated mValueBeingSet.
return true; 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 // If there is composition, need to commit composition first because
// other browsers do that. // other browsers do that.
// NOTE: We don't need to block nested calls of this because input nor // NOTE: We don't need to block nested calls of this because input nor

View File

@ -54,6 +54,23 @@ AudioData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
return size; 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 */ /* static */
already_AddRefed<AudioData> already_AddRefed<AudioData>
AudioData::TransferAndUpdateTimestampAndDuration(AudioData* aOther, AudioData::TransferAndUpdateTimestampAndDuration(AudioData* aOther,

View File

@ -149,6 +149,10 @@ public:
// If mAudioBuffer is null, creates it from mAudioData. // If mAudioBuffer is null, creates it from mAudioData.
void EnsureAudioBuffer(); 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 mChannels;
const uint32_t mRate; const uint32_t mRate;
// At least one of mAudioBuffer/mAudioData must be non-null. // At least one of mAudioBuffer/mAudioData must be non-null.

View File

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

View File

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

View File

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

View File

@ -116,6 +116,11 @@ static const int AUDIO_DURATION_USECS = 40000;
// increase it by more. // increase it by more.
static const int THRESHOLD_FACTOR = 2; 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 { namespace detail {
// If we have less than this much undecoded data available, we'll consider // If we have less than this much undecoded data available, we'll consider
@ -236,6 +241,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mOutputStreamManager(new OutputStreamManager()), mOutputStreamManager(new OutputStreamManager()),
mResource(aDecoder->GetResource()), mResource(aDecoder->GetResource()),
mAudioOffloading(false), mAudioOffloading(false),
mSilentDataDuration(0),
mBuffered(mTaskQueue, TimeIntervals(), mBuffered(mTaskQueue, TimeIntervals(),
"MediaDecoderStateMachine::mBuffered (Mirror)"), "MediaDecoderStateMachine::mBuffered (Mirror)"),
mEstimatedDuration(mTaskQueue, NullableTimeUnit(), mEstimatedDuration(mTaskQueue, NullableTimeUnit(),
@ -272,7 +278,9 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mCurrentPosition(mTaskQueue, 0, mCurrentPosition(mTaskQueue, 0,
"MediaDecoderStateMachine::mCurrentPosition (Canonical)"), "MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
mPlaybackOffset(mTaskQueue, 0, mPlaybackOffset(mTaskQueue, 0,
"MediaDecoderStateMachine::mPlaybackOffset (Canonical)") "MediaDecoderStateMachine::mPlaybackOffset (Canonical)"),
mIsAudioDataAudible(mTaskQueue, false,
"MediaDecoderStateMachine::mIsAudioDataAudible (Canonical)")
{ {
MOZ_COUNT_CTOR(MediaDecoderStateMachine); MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -709,14 +717,36 @@ MediaDecoderStateMachine::PushFront(MediaData* aSample, MediaData::Type aSampleT
UpdateNextFrameStatus(); 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 void
MediaDecoderStateMachine::OnAudioPopped(const RefPtr<MediaData>& aSample) MediaDecoderStateMachine::OnAudioPopped(const RefPtr<MediaData>& aSample)
{ {
MOZ_ASSERT(OnTaskQueue()); MOZ_ASSERT(OnTaskQueue());
mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset); mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
UpdateNextFrameStatus(); UpdateNextFrameStatus();
DispatchAudioDecodeTaskIfNeeded(); DispatchAudioDecodeTaskIfNeeded();
MaybeStartBuffering(); MaybeStartBuffering();
CheckIsAudible(aSample);
} }
void void
@ -2168,6 +2198,7 @@ MediaDecoderStateMachine::FinishShutdown()
mNextFrameStatus.DisconnectAll(); mNextFrameStatus.DisconnectAll();
mCurrentPosition.DisconnectAll(); mCurrentPosition.DisconnectAll();
mPlaybackOffset.DisconnectAll(); mPlaybackOffset.DisconnectAll();
mIsAudioDataAudible.DisconnectAll();
// Shut down the watch manager before shutting down our task queue. // Shut down the watch manager before shutting down our task queue.
mWatchManager.Shutdown(); mWatchManager.Shutdown();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,18 +7,9 @@
#include "FFmpegRuntimeLinker.h" #include "FFmpegRuntimeLinker.h"
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "FFmpegLog.h" #include "FFmpegLog.h"
#include "mozilla/Preferences.h"
#include "mozilla/Types.h" #include "mozilla/Types.h"
#include "nsIFile.h"
#include "nsXPCOMPrivate.h" // for XUL_DLL
#include "prmem.h"
#include "prlink.h" #include "prlink.h"
#if defined(XP_WIN)
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#endif
namespace mozilla namespace mozilla
{ {
@ -77,7 +68,6 @@ FFmpegRuntimeLinker::Link()
if (sLinkStatus) { if (sLinkStatus) {
return sLinkStatus == LinkStatus_SUCCEEDED; return sLinkStatus == LinkStatus_SUCCEEDED;
} }
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
for (size_t i = 0; i < ArrayLength(sLibs); i++) { for (size_t i = 0; i < ArrayLength(sLibs); i++) {
@ -100,54 +90,6 @@ FFmpegRuntimeLinker::Link()
} }
FFMPEG_LOG(" ]\n"); 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(); Unlink();
sLinkStatus = LinkStatus_FAILED; sLinkStatus = LinkStatus_FAILED;
@ -218,12 +160,10 @@ FFmpegRuntimeLinker::CreateDecoderModule()
RefPtr<PlatformDecoderModule> module; RefPtr<PlatformDecoderModule> module;
switch (major) { switch (major) {
#ifndef XP_WIN
case 53: module = FFmpegDecoderModule<53>::Create(); break; case 53: module = FFmpegDecoderModule<53>::Create(); break;
case 54: module = FFmpegDecoderModule<54>::Create(); break; case 54: module = FFmpegDecoderModule<54>::Create(); break;
case 55: case 55:
case 56: module = FFmpegDecoderModule<55>::Create(); break; case 56: module = FFmpegDecoderModule<55>::Create(); break;
#endif
case 57: module = FFmpegDecoderModule<57>::Create(); break; case 57: module = FFmpegDecoderModule<57>::Create(); break;
default: module = nullptr; default: module = nullptr;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,44 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
LOCAL_INCLUDES += ['/xpcom/build']
EXPORTS += [
'FFVPXRuntimeLinker.h',
]
UNIFIED_SOURCES += [
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegVideoDecoder.cpp',
]
SOURCES += [
'FFVPXRuntimeLinker.cpp',
]
LOCAL_INCLUDES += [
'..',
'../ffmpeg57/include',
]
if CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'../ffmpeg57/include',
]
if CONFIG['GNU_CXX']:
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
if CONFIG['CLANG_CXX']:
CXXFLAGS += [
'-Wno-unknown-attributes',
]
if CONFIG['_MSC_VER']:
CXXFLAGS += [
'-wd4996', # deprecated declaration
]
DEFINES['FFVPX_VERSION'] = 46465650
DEFINES['USING_MOZFFVPX'] = True
FINAL_LIBRARY = 'xul'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,6 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */ * http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000; MARIONETTE_TIMEOUT = 60000;
// We apply "chrome" context to be more flexible to // We apply "chrome" context to be more flexible to
// specify the content of M-Notification.ind such as iccId // specify the content of M-Notification.ind such as iccId
// for different kinds of testing. // for different kinds of testing.
@ -17,11 +18,17 @@ var gMobileMessageDatabaseService =
.getService(Ci.nsIGonkMobileMessageDatabaseService); .getService(Ci.nsIGonkMobileMessageDatabaseService);
var gUuidGenerator = var gUuidGenerator =
Cc["@mozilla.org/uuid-generator;1"] Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
.getService(Ci.nsIUUIDGenerator);
var gMmsService = Cc["@mozilla.org/mms/gonkmmsservice;1"] var gMmsService =
.getService(Ci.nsIMmsService); 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() { function saveMmsNotification() {
log("saveMmsNotification()"); log("saveMmsNotification()");
@ -101,23 +108,111 @@ function retrieveMmsWithFailure(aId) {
return deferred.promise; return deferred.promise;
} }
function testRetrieve(aCause, aInit, aCleanup) { function testRetrieve(aCause) {
log("testRetrieve: aCause = " + aCause); log("testRetrieve: aCause = " + aCause);
return Promise.resolve() return Promise.resolve()
.then(() => { if (aInit) aInit(); })
.then(saveMmsNotification) .then(saveMmsNotification)
.then((message) => retrieveMmsWithFailure(message.id)) .then((message) => retrieveMmsWithFailure(message.id))
.then((response) => verifyErrorCause(response, aCause)) .then((response) => verifyErrorCause(response, aCause));
.then(() => { if (aCleanup) aCleanup(); });
} }
var setRadioDisabled = function(aDisabled) { function setRadioEnabled(aConnection, aEnabled) {
log("set ril.radio.disabled to " + aDisabled); let deferred = Promise.defer();
Services.prefs.setBoolPref("ril.radio.disabled", aDisabled); let finalState = (aEnabled) ?
}; Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED :
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED;
testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR, if (aConnection.radioState == finalState) {
setRadioDisabled.bind(null, true), return deferred.resolve(aConnection);
setRadioDisabled.bind(null, false)) }
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(() => testRetrieve(Ci.nsIMobileMessageCallback.SIM_NOT_MATCHED_ERROR))
.then(finish); .then(finish);

View File

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

View File

@ -4,79 +4,6 @@
MARIONETTE_TIMEOUT = 60000; MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js'; 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) { function testSendFailed(aCause) {
log("testSendFailed, aCause: " + aCause); log("testSendFailed, aCause: " + aCause);
@ -98,8 +25,7 @@ function testSendFailed(aCause) {
startTestCommon(function testCaseMain() { startTestCommon(function testCaseMain() {
return ensureMobileConnection() return ensureMobileConnection()
.then(() => waitRadioState("enabled")) .then(() => setRadioEnabled(mobileConnection, false))
.then(() => setRadioEnabled(false))
.then(() => testSendFailed("RadioDisabledError")) .then(() => testSendFailed("RadioDisabledError"))
.then(() => setRadioEnabled(true)); .then(() => setRadioEnabled(mobileConnection, true));
}); });

View File

@ -1,6 +1,6 @@
en_US-mozilla Hunspell Dictionary en_US-mozilla Hunspell Dictionary
Generated from SCOWL Version 2015.08.24 Generated from SCOWL Version 2016.01.19
Sun Jan 10 15:07:17 EST 2016 Thu Jan 21 14:36:28 EST 2016
http://wordlist.sourceforge.net 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 to encourage consistent spelling, generally only include one spelling
variant for a word. The large dictionaries correspond to SCOWL size variant for a word. The large dictionaries correspond to SCOWL size
70 and may include multiple spelling for a word when both variants are 70 and may include multiple spelling for a word when both variants are
considered almost equal. Also, the general quality of the larger considered almost equal. The larger dictionaries however (1) have not
dictionaries may also be less as they are not as carefully checked for been as carefully checked for errors as the normal dictionaries and
errors as the normal dictionaries. 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 To get an idea of the difference in size, here are 25 random words
only found in the large dictionary for American English: 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. kevina@gnu.org.
If none of these dictionaries suite you (for example, maybe you want 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 dictionaries can be generated at http://app.aspell.net/create or by
modifying speller/make-hunspell-dict in SCOWL. Please do let me know modifying speller/make-hunspell-dict in SCOWL. Please do let me know
if you end up publishing a customized dictionary. 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 have specific issues with any of these dictionaries please file a bug
report at https://github.com/kevina/wordlist/issues. 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 The dictionaries are now in UTF-8 format instead of ISO-8859-1. This
was required to handle smart quotes correctly. 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: ADDITIONAL NOTES:
The NOSUGGEST flag was added to certain taboo words. While I made an 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 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. 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