mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
641e64fe3f
@ -4,9 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'IA2Marshal'
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
SharedLibrary('IA2Marshal')
|
||||
|
||||
DEFINES['REGISTER_PROXY_DLL'] = True
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'AccessibleMarshal'
|
||||
SharedLibrary('AccessibleMarshal')
|
||||
|
||||
GENERATED_SOURCES += [
|
||||
'dlldata.c',
|
||||
@ -16,8 +16,6 @@ GENERATED_SOURCES += [
|
||||
'ISimpleDOMText_p.c',
|
||||
]
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
|
||||
DEFINES['REGISTER_PROXY_DLL'] = True
|
||||
|
||||
DEFFILE = SRCDIR + '/AccessibleMarshal.def'
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
if not CONFIG['LIBXUL_SDK']:
|
||||
if CONFIG['GAIADIR']:
|
||||
PROGRAM = CONFIG['MOZ_APP_NAME'] + "-bin"
|
||||
Program(CONFIG['MOZ_APP_NAME'] + "-bin")
|
||||
else:
|
||||
PROGRAM = CONFIG['MOZ_APP_NAME']
|
||||
Program(CONFIG['MOZ_APP_NAME'])
|
||||
if CONFIG['MOZ_B2G_LOADER']:
|
||||
SOURCES += [
|
||||
'B2GLoader.cpp',
|
||||
|
@ -513,6 +513,10 @@ let settingsToObserve = {
|
||||
prefName: 'dom.sms.strict7BitEncoding',
|
||||
defaultValue: false
|
||||
},
|
||||
'ril.sms.maxReadAheadEntries': {
|
||||
prefName: 'dom.sms.maxReadAheadEntries',
|
||||
defaultValue: 7
|
||||
},
|
||||
'ui.touch.radius.leftmm': {
|
||||
resetToPref: true
|
||||
},
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="68af8bfafdf9e35f4db0ae60e087cbf8f6d7ee6d"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="68af8bfafdf9e35f4db0ae60e087cbf8f6d7ee6d"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "7448e582578f9d88a6d24a8f372cb7a6343e25e3",
|
||||
"revision": "9c3a4beb0c7c08c6a20dd406210f3c671557e121",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="68af8bfafdf9e35f4db0ae60e087cbf8f6d7ee6d"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="008026e932b64b4a70b9931c3da96986583bc8d4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="de59e0c3614dd0061881fe284e9f2d74fa0d1d5d"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
PROGRAM = CONFIG['MOZ_APP_NAME']
|
||||
Program(CONFIG['MOZ_APP_NAME'])
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
SOURCES += [
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
DIRS += ['profile/extensions']
|
||||
|
||||
PROGRAM = CONFIG['MOZ_APP_NAME']
|
||||
Program(CONFIG['MOZ_APP_NAME'])
|
||||
|
||||
SOURCES += [
|
||||
'nsBrowserApp.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
PROGRAM = 'CommandExecuteHandler'
|
||||
Program('CommandExecuteHandler')
|
||||
|
||||
SOURCES += [
|
||||
'CEHHelper.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
PROGRAM = 'linktool'
|
||||
Program('linktool')
|
||||
|
||||
SOURCES += [
|
||||
'linktool.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
PROGRAM = 'metrotestharness'
|
||||
Program('metrotestharness')
|
||||
|
||||
SOURCES += [
|
||||
'metrotestharness.cpp',
|
||||
|
@ -108,7 +108,7 @@ libs:: $(topsrcdir)/tools/rb/fix_macosx_stack.py
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
libs:: $(topsrcdir)/tools/rb/fix-linux-stack.pl
|
||||
libs:: $(topsrcdir)/tools/rb/fix_linux_stack.py
|
||||
$(INSTALL) $< $(DIST)/bin
|
||||
endif
|
||||
|
||||
|
@ -68,7 +68,6 @@ _IS_CYGWIN = False
|
||||
#endif
|
||||
#expand _IS_CAMINO = __IS_CAMINO__ != 0
|
||||
#expand _BIN_SUFFIX = __BIN_SUFFIX__
|
||||
#expand _PERL = __PERL__
|
||||
|
||||
#expand _DEFAULT_APP = "./" + __BROWSER_PATH__
|
||||
#expand _CERTS_SRC_DIR = __CERTS_SRC_DIR__
|
||||
@ -143,7 +142,6 @@ class Automation(object):
|
||||
IS_CYGWIN = _IS_CYGWIN
|
||||
IS_CAMINO = _IS_CAMINO
|
||||
BIN_SUFFIX = _BIN_SUFFIX
|
||||
PERL = _PERL
|
||||
|
||||
UNIXISH = not IS_WIN32 and not IS_MAC
|
||||
|
||||
@ -671,7 +669,6 @@ class Automation(object):
|
||||
|
||||
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):
|
||||
""" Look for timeout or crashes and return the status after the process terminates """
|
||||
stackFixerProcess = None
|
||||
stackFixerFunction = None
|
||||
didTimeout = False
|
||||
hitMaxTime = False
|
||||
@ -694,12 +691,12 @@ class Automation(object):
|
||||
stackFixerFunction = lambda line: stackFixerModule.fixSymbols(line)
|
||||
del sys.path[0]
|
||||
elif self.IS_DEBUG_BUILD and self.IS_LINUX:
|
||||
# Run logsource through fix-linux-stack.pl (uses addr2line)
|
||||
# Run each line through a function in fix_linux_stack.py (uses addr2line)
|
||||
# This method is preferred for developer machines, so we don't have to run "make buildsymbols".
|
||||
stackFixerProcess = self.Process([self.PERL, os.path.join(utilityPath, "fix-linux-stack.pl")],
|
||||
stdin=logsource,
|
||||
stdout=subprocess.PIPE)
|
||||
logsource = stackFixerProcess.stdout
|
||||
sys.path.insert(0, utilityPath)
|
||||
import fix_linux_stack as stackFixerModule
|
||||
stackFixerFunction = lambda line: stackFixerModule.fixSymbols(line)
|
||||
del sys.path[0]
|
||||
|
||||
# With metro browser runs this script launches the metro test harness which launches the browser.
|
||||
# The metro test harness hands back the real browser process id via log output which we need to
|
||||
@ -725,7 +722,7 @@ class Automation(object):
|
||||
self.log.info("INFO | automation.py | metro browser sub process id detected: %s", browserProcessId)
|
||||
|
||||
if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
|
||||
# Kill the application, but continue reading from stack fixer so as not to deadlock on stackFixerProcess.wait().
|
||||
# Kill the application.
|
||||
hitMaxTime = True
|
||||
self.log.info("TEST-UNEXPECTED-FAIL | %s | application ran for longer than allowed maximum time of %d seconds", self.lastTestSeen, int(maxTime))
|
||||
self.killAndGetStack(proc.pid, utilityPath, debuggerInfo)
|
||||
@ -743,11 +740,6 @@ class Automation(object):
|
||||
self.lastTestSeen = "Main app process exited normally"
|
||||
if status != 0 and not didTimeout and not hitMaxTime:
|
||||
self.log.info("TEST-UNEXPECTED-FAIL | %s | Exited with code %d during test run", self.lastTestSeen, status)
|
||||
if stackFixerProcess is not None:
|
||||
fixerStatus = stackFixerProcess.wait()
|
||||
automationutils.printstatus(status, "stackFixerProcess")
|
||||
if fixerStatus != 0 and not didTimeout and not hitMaxTime:
|
||||
self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", fixerStatus)
|
||||
return status
|
||||
|
||||
def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
|
||||
|
@ -39,20 +39,20 @@ Static Libraries
|
||||
================
|
||||
|
||||
To build a static library, other than defining the source files (see above), one
|
||||
just needs to define a library name with the ``LIBRARY_NAME`` variable.
|
||||
just needs to define a library name with the ``Library`` template.
|
||||
|
||||
LIBRARY_NAME = 'foo'
|
||||
Library('foo')
|
||||
|
||||
The library file name will be ``libfoo.a`` on UNIX systems and ``foo.lib`` on
|
||||
Windows.
|
||||
|
||||
If the static library needs to aggregate other static libraries, a list of
|
||||
``LIBRARY_NAME`` can be added to the ``USE_LIBS`` variable. Like ``SOURCES``, it
|
||||
``Library`` names can be added to the ``USE_LIBS`` variable. Like ``SOURCES``, it
|
||||
requires the appended list to be alphanumerically ordered.
|
||||
|
||||
USE_LIBS += ['bar', 'baz']
|
||||
|
||||
If there are multiple directories containing the same ``LIBRARY_NAME``, it is
|
||||
If there are multiple directories containing the same ``Library`` name, it is
|
||||
possible to disambiguate by prefixing with the path to the wanted one (relative
|
||||
or absolute):
|
||||
|
||||
@ -61,7 +61,7 @@ or absolute):
|
||||
'../relative/baz',
|
||||
]
|
||||
|
||||
Note that the leaf name in those paths is the ``LIBRARY_NAME``, not an actual
|
||||
Note that the leaf name in those paths is the ``Library`` name, not an actual
|
||||
file name.
|
||||
|
||||
Note that currently, the build system may not create an actual library for
|
||||
@ -84,10 +84,10 @@ be linked to that bigger library, with the ``FINAL_LIBRARY`` variable.
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
The ``FINAL_LIBRARY`` value must match a unique ``LIBRARY_NAME`` somewhere
|
||||
The ``FINAL_LIBRARY`` value must match a unique ``Library`` name somewhere
|
||||
in the tree.
|
||||
|
||||
As a special rule, those intermediate libraries don't need a ``LIBRARY_NAME``
|
||||
As a special rule, those intermediate libraries don't need a ``Library`` name
|
||||
for themselves.
|
||||
|
||||
|
||||
@ -95,15 +95,15 @@ Shared Libraries
|
||||
================
|
||||
|
||||
Sometimes, we want shared libraries, a.k.a. dynamic libraries. Such libraries
|
||||
are defined with the same variables as static libraries, with the addition of
|
||||
the ``FORCE_SHARED_LIB`` boolean variable:
|
||||
are defined similarly to static libraries, using the ``SharedLibrary`` template
|
||||
instead of ``Library``.
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
SharedLibrary('foo')
|
||||
|
||||
When this variable is set, no static library is built. See further below to
|
||||
When this template is used, no static library is built. See further below to
|
||||
build both types of libraries.
|
||||
|
||||
With a ``LIBRARY_NAME`` of ``foo``, the library file name will be
|
||||
With a ``SharedLibrary`` name of ``foo``, the library file name will be
|
||||
``libfoo.dylib`` on OSX, ``libfoo.so`` on ELF systems (Linux, etc.), and
|
||||
``foo.dll`` on Windows. On Windows, there is also an import library named
|
||||
``foo.lib``, used on the linker command line. ``libfoo.dylib`` and
|
||||
@ -111,51 +111,61 @@ With a ``LIBRARY_NAME`` of ``foo``, the library file name will be
|
||||
systems.
|
||||
|
||||
On OSX, one may want to create a special kind of dynamic library: frameworks.
|
||||
This is done with the ``IS_FRAMEWORK`` boolean variable.
|
||||
This is done with the ``Framework`` template.
|
||||
|
||||
IS_FRAMEWORK = True
|
||||
Framework('foo')
|
||||
|
||||
With a ``LIBRARY_NAME`` of ``foo``, the framework file name will be ``foo``.
|
||||
This variable however affects the behavior on all platforms, so it needs to
|
||||
With a ``Framework`` name of ``foo``, the framework file name will be ``foo``.
|
||||
This template however affects the behavior on all platforms, so it needs to
|
||||
be set only on OSX.
|
||||
|
||||
Another special kind of library, XPCOM-specific, are XPCOM components. One can
|
||||
build such a component with the ``IS_COMPONENT`` boolean variable.
|
||||
build such a component with the ``XPCOMBinaryComponent`` template.
|
||||
|
||||
IS_COMPONENT = True
|
||||
XPCOMBinaryComponent('foo')
|
||||
|
||||
|
||||
Executables
|
||||
===========
|
||||
|
||||
Executables, a.k.a. programs, are, in the simplest form, defined with the
|
||||
``PROGRAM`` variable.
|
||||
``Program`` template.
|
||||
|
||||
PROGRAM = 'foobar'
|
||||
Program('foobar')
|
||||
|
||||
On UNIX systems, the executable file name will be ``foobar``, while on Windows,
|
||||
it will be ``foobar.exe``.
|
||||
|
||||
Like static and shared libraries, the build system can be instructed to link
|
||||
libraries to the executable with ``USE_LIBS``, listing various ``LIBRARY_NAME``.
|
||||
libraries to the executable with ``USE_LIBS``, listing various ``Library``
|
||||
names.
|
||||
|
||||
In some cases, we want to create an executable per source file in the current
|
||||
directory, in which case we can use the ``SIMPLE_PROGRAMS`` list:
|
||||
directory, in which case we can use the ``SimplePrograms`` template
|
||||
|
||||
SIMPLE_PROGRAMS = [
|
||||
SimplePrograms([
|
||||
'FirstProgram',
|
||||
'SecondProgram',
|
||||
]
|
||||
])
|
||||
|
||||
The corresponding ``SOURCES`` must match:
|
||||
Contrary to ``Program``, which requires corresponding ``SOURCES``, when using
|
||||
``SimplePrograms``, the corresponding ``SOURCES`` are implied. If the
|
||||
corresponding ``sources`` have an extension different from ``.cpp``, it is
|
||||
possible to specify the proper extension:
|
||||
|
||||
SOURCES += [
|
||||
'FirstProgram.cpp',
|
||||
'SecondProgram.c',
|
||||
]
|
||||
SimplePrograms([
|
||||
'ThirdProgram',
|
||||
'FourthProgram',
|
||||
], ext='.c')
|
||||
|
||||
Similar to ``SIMPLE_PROGRAMS``, is ``CPP_UNIT_TESTS``, which defines, with the
|
||||
same rules, C++ unit tests programs.
|
||||
Please note this construct was added for compatibility with what already lives
|
||||
in the mozilla tree ; it is recommended not to add new simple programs with
|
||||
sources with a different extension than ``.cpp``.
|
||||
|
||||
Similar to ``SimplePrograms``, is the ``CppUnitTests`` template, which defines,
|
||||
with the same rules, C++ unit tests programs. Like ``SimplePrograms``, it takes
|
||||
an ``ext`` argument to specify the extension for the corresponding ``SOURCES``,
|
||||
if it's different from ``.cpp``.
|
||||
|
||||
|
||||
Linking with system libraries
|
||||
@ -189,10 +199,10 @@ Libraries from third party build system
|
||||
=======================================
|
||||
|
||||
Some libraries in the tree are not built by the moz.build-governed build
|
||||
system, and there is no ``LIBRARY_NAME`` corresponding to them.
|
||||
system, and there is no ``Library`` corresponding to them.
|
||||
|
||||
However, ``USE_LIBS`` allows to reference such libraries by giving a full
|
||||
path (like when disambiguating identical ``LIBRARY_NAME``). The same naming
|
||||
path (like when disambiguating identical ``Library`` names). The same naming
|
||||
rules apply as other uses of ``USE_LIBS``, so only the library name without
|
||||
prefix and suffix shall be given.
|
||||
|
||||
@ -217,12 +227,12 @@ When both types of libraries are required, one needs to set both
|
||||
|
||||
But because static libraries and Windows import libraries have the same file
|
||||
names, either the static or the shared library name needs to be different
|
||||
than ``LIBRARY_NAME``.
|
||||
than the name given to the ``Library`` template.
|
||||
|
||||
The ``STATIC_LIBRARY_NAME`` and ``SHARED_LIBRARY_NAME`` variables can be used
|
||||
to change either the static or the shared library name.
|
||||
|
||||
LIBRARY_NAME = 'foo'
|
||||
Library('foo')
|
||||
STATIC_LIBRARY_NAME = 'foo_s'
|
||||
|
||||
With the above, on Windows, ``foo_s.lib`` will be the static library,
|
||||
@ -231,25 +241,25 @@ With the above, on Windows, ``foo_s.lib`` will be the static library,
|
||||
In some cases, for convenience, it is possible to set both
|
||||
``STATIC_LIBRARY_NAME`` and ``SHARED_LIBRARY_NAME``. For example:
|
||||
|
||||
LIBRARY_NAME = 'mylib'
|
||||
Library('mylib')
|
||||
STATIC_LIBRARY_NAME = 'mylib_s'
|
||||
SHARED_LIBRARY_NAME = CONFIG['SHARED_NAME']
|
||||
|
||||
This allows to use ``mylib`` in the ``USE_LIBS`` of another library or
|
||||
executable.
|
||||
|
||||
When refering to a ``LIBRARY_NAME`` building both types of libraries in
|
||||
When refering to a ``Library`` name building both types of libraries in
|
||||
``USE_LIBS``, the shared library is chosen to be linked. But sometimes,
|
||||
it is wanted to link the static version, in which case the ``LIBRARY_NAME``
|
||||
it is wanted to link the static version, in which case the ``Library`` name
|
||||
needs to be prefixed with ``static:`` in ``USE_LIBS``
|
||||
|
||||
a/moz.build:
|
||||
LIBRARY_NAME = 'mylib'
|
||||
Library('mylib')
|
||||
FORCE_SHARED_LIB = True
|
||||
FORCE_STATIC_LIB = True
|
||||
STATIC_LIBRARY_NAME = 'mylib_s'
|
||||
b/moz.build:
|
||||
PROGRAM = 'myprog'
|
||||
Program('myprog')
|
||||
USE_LIBS += [
|
||||
'static:mylib',
|
||||
]
|
||||
@ -262,18 +272,18 @@ The ``SDK_LIBRARY`` boolean variable defines whether the library in the current
|
||||
directory is going to be installed in the SDK.
|
||||
|
||||
The ``SONAME`` variable declares a "shared object name" for the library. It
|
||||
defaults to the ``LIBRARY_NAME`` or the ``SHARED_LIBRARY_NAME`` if set. When
|
||||
defaults to the ``Library`` name or the ``SHARED_LIBRARY_NAME`` if set. When
|
||||
linking to a library with a ``SONAME``, the resulting library or program will
|
||||
have a dependency on the library with the name corresponding to the ``SONAME``
|
||||
instead of ``LIBRARY_NAME``. This only impacts ELF systems.
|
||||
instead of the ``Library`` name. This only impacts ELF systems.
|
||||
|
||||
a/moz.build:
|
||||
LIBRARY_NAME = 'mylib'
|
||||
Library('mylib')
|
||||
b/moz.build:
|
||||
LIBRARY_NAME = 'otherlib'
|
||||
Library('otherlib')
|
||||
SONAME = 'foo'
|
||||
c/moz.build:
|
||||
PROGRAM = 'myprog'
|
||||
Program('myprog')
|
||||
USE_LIBS += [
|
||||
'mylib',
|
||||
'otherlib',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'stlport_static'
|
||||
Library('stlport_static')
|
||||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
|
@ -4,6 +4,105 @@
|
||||
# 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/.
|
||||
|
||||
@template
|
||||
def StdCppCompat():
|
||||
'''Template for libstdc++ compatibility for target binaries.'''
|
||||
|
||||
if CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION']:
|
||||
USE_LIBS += ['stdc++compat']
|
||||
|
||||
|
||||
@template
|
||||
def Program(name):
|
||||
'''Template for program executables.'''
|
||||
PROGRAM = name
|
||||
|
||||
StdCppCompat()
|
||||
|
||||
|
||||
@template
|
||||
def SimplePrograms(names, ext='.cpp'):
|
||||
'''Template for simple program executables.
|
||||
|
||||
Those have a single source with the same base name as the executable.
|
||||
'''
|
||||
SIMPLE_PROGRAMS += names
|
||||
SOURCES += ['%s%s' % (name, ext) for name in names]
|
||||
|
||||
StdCppCompat()
|
||||
|
||||
|
||||
@template
|
||||
def CppUnitTests(names, ext='.cpp'):
|
||||
'''Template for C++ unit tests.
|
||||
|
||||
Those have a single source with the same base name as the executable.
|
||||
'''
|
||||
CPP_UNIT_TESTS += names
|
||||
SOURCES += ['%s%s' % (name, ext) for name in names]
|
||||
|
||||
StdCppCompat()
|
||||
|
||||
|
||||
@template
|
||||
def Library(name):
|
||||
'''Template for libraries.'''
|
||||
LIBRARY_NAME = name
|
||||
|
||||
|
||||
@template
|
||||
def SharedLibrary(name):
|
||||
'''Template for shared libraries.'''
|
||||
Library(name)
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
|
||||
StdCppCompat()
|
||||
|
||||
|
||||
@template
|
||||
def Framework(name):
|
||||
'''Template for OSX Frameworks.'''
|
||||
SharedLibrary(name)
|
||||
|
||||
IS_FRAMEWORK = True
|
||||
|
||||
|
||||
@template
|
||||
def HostStdCppCompat():
|
||||
'''Template for libstdc++ compatibility for host binaries.'''
|
||||
|
||||
if CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']:
|
||||
HOST_USE_LIBS += ['host_stdc++compat']
|
||||
|
||||
|
||||
@template
|
||||
def HostProgram(name):
|
||||
'''Template for build tools executables.'''
|
||||
HOST_PROGRAM = name
|
||||
|
||||
HostStdCppCompat()
|
||||
|
||||
|
||||
@template
|
||||
def HostSimplePrograms(names, ext='.cpp'):
|
||||
'''Template for simple build tools executables.
|
||||
|
||||
Those have a single source with the same base name as the executable.
|
||||
'''
|
||||
HOST_SIMPLE_PROGRAMS += names
|
||||
HOST_SOURCES += ['%s%s' % (name.replace('host_', ''), ext)
|
||||
for name in names]
|
||||
|
||||
HostStdCppCompat()
|
||||
|
||||
|
||||
@template
|
||||
def HostLibrary(name):
|
||||
'''Template for build tools libraries.'''
|
||||
HOST_LIBRARY_NAME = name
|
||||
|
||||
|
||||
@template
|
||||
def GeckoBinary():
|
||||
'''Template for binaries using Gecko.
|
||||
@ -24,7 +123,7 @@ def XPCOMBinaryComponent(name):
|
||||
|
||||
name is the name of the component.
|
||||
'''
|
||||
LIBRARY_NAME = name
|
||||
SharedLibrary(name)
|
||||
|
||||
GeckoBinary()
|
||||
|
||||
|
@ -19,7 +19,7 @@ HOST_SOURCES += [
|
||||
'elfhack.cpp',
|
||||
]
|
||||
|
||||
HOST_PROGRAM = 'elfhack'
|
||||
HostProgram('elfhack')
|
||||
|
||||
DEFINES['ELFHACK_BUILD'] = True
|
||||
|
||||
|
@ -5,11 +5,11 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION']:
|
||||
LIBRARY_NAME = 'stdc++compat'
|
||||
Library('stdc++compat')
|
||||
SOURCES += ['stdc++compat.cpp']
|
||||
|
||||
if CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']:
|
||||
HOST_LIBRARY_NAME = 'host_stdc++compat'
|
||||
HostLibrary('host_stdc++compat')
|
||||
HOST_SOURCES += [
|
||||
'stdc++compat.cpp',
|
||||
]
|
||||
|
@ -8,9 +8,7 @@ SOURCES += [
|
||||
'crashinjectdll.cpp',
|
||||
]
|
||||
|
||||
LIBRARY_NAME = 'crashinjectdll'
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
SharedLibrary('crashinjectdll')
|
||||
|
||||
DEFFILE = SRCDIR + '/crashinjectdll.def'
|
||||
|
||||
|
@ -10,7 +10,7 @@ if CONFIG['_MSC_VER'] and CONFIG['OS_TEST'] != 'x86_64':
|
||||
TEST_DIRS += ['crashinjectdll']
|
||||
|
||||
if CONFIG['ENABLE_TESTS']:
|
||||
PROGRAM = 'crashinject'
|
||||
Program('crashinject')
|
||||
SOURCES += [
|
||||
'crashinject.cpp',
|
||||
]
|
||||
|
@ -8,9 +8,7 @@ SOURCES += [
|
||||
'vmwarerecordinghelper.cpp',
|
||||
]
|
||||
|
||||
LIBRARY_NAME = 'vmwarerecordinghelper'
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
SharedLibrary('vmwarerecordinghelper')
|
||||
|
||||
DEFFILE = '%s/%s.def' % (SRCDIR, LIBRARY_NAME)
|
||||
|
||||
|
@ -19,7 +19,7 @@ interface nsILoadContext;
|
||||
[ptr] native JSContextPtr(JSContext);
|
||||
[ptr] native JSObjectPtr(JSObject);
|
||||
|
||||
[scriptable, uuid(f6e1e37e-14d0-44fa-a9bb-712bfad6c5f7)]
|
||||
[scriptable, uuid(3b021962-975e-43b5-8a93-9fc2d20346e9)]
|
||||
interface nsIScriptSecurityManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -199,7 +199,13 @@ interface nsIScriptSecurityManager : nsISupports
|
||||
* channel owner if there is one, and the codebase principal for the
|
||||
* channel's URI otherwise. aChannel must not be null.
|
||||
*/
|
||||
nsIPrincipal getChannelPrincipal(in nsIChannel aChannel);
|
||||
nsIPrincipal getChannelResultPrincipal(in nsIChannel aChannel);
|
||||
|
||||
/**
|
||||
* Get the codebase principal for the channel's URI.
|
||||
* aChannel must not be null.
|
||||
*/
|
||||
nsIPrincipal getChannelURIPrincipal(in nsIChannel aChannel);
|
||||
|
||||
/**
|
||||
* Check whether a given principal is a system principal. This allows us
|
||||
|
@ -306,8 +306,8 @@ nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipal)
|
||||
nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipal)
|
||||
{
|
||||
NS_PRECONDITION(aChannel, "Must have channel!");
|
||||
nsCOMPtr<nsISupports> owner;
|
||||
@ -336,14 +336,21 @@ nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return GetChannelURIPrincipal(aChannel, aPrincipal);
|
||||
}
|
||||
|
||||
// OK, get the principal from the URI. Make sure this does the same thing
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipal)
|
||||
{
|
||||
NS_PRECONDITION(aChannel, "Must have channel!");
|
||||
|
||||
// Get the principal from the URI. Make sure this does the same thing
|
||||
// as nsDocument::Reset and XULDocument::StartDocumentLoad.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(aChannel, loadContext);
|
||||
|
||||
@ -1189,7 +1196,7 @@ nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel,
|
||||
nsIAsyncVerifyRedirectCallback *cb)
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> oldPrincipal;
|
||||
GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
|
||||
GetChannelResultPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
newChannel->GetURI(getter_AddRefs(newURI));
|
||||
|
2
config/external/ffi/moz.build
vendored
2
config/external/ffi/moz.build
vendored
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'ffi'
|
||||
Library('ffi')
|
||||
|
||||
if CONFIG['MOZ_NATIVE_FFI']:
|
||||
OS_LIBS += CONFIG['MOZ_FFI_LIBS']
|
||||
|
2
config/external/freetype2/moz.build
vendored
2
config/external/freetype2/moz.build
vendored
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'freetype'
|
||||
Library('freetype')
|
||||
|
||||
if CONFIG['MOZ_TREE_FREETYPE']:
|
||||
USE_LIBS += [
|
||||
|
2
config/external/icu/moz.build
vendored
2
config/external/icu/moz.build
vendored
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'icu'
|
||||
Library('icu')
|
||||
|
||||
if CONFIG['MOZ_NATIVE_ICU']:
|
||||
OS_LIBS += CONFIG['MOZ_ICU_LIBS']
|
||||
|
2
config/external/nspr/moz.build
vendored
2
config/external/nspr/moz.build
vendored
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'nspr'
|
||||
Library('nspr')
|
||||
|
||||
if CONFIG['MOZ_FOLD_LIBS']:
|
||||
# When folding libraries, nspr is actually in the nss library.
|
||||
|
2
config/external/nss/crmf/moz.build
vendored
2
config/external/nss/crmf/moz.build
vendored
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'crmf'
|
||||
Library('crmf')
|
||||
|
||||
if CONFIG['MOZ_NATIVE_NSS']:
|
||||
OS_LIBS += [l for l in CONFIG['NSS_LIBS'] if l.startswith('-L')]
|
||||
|
6
config/external/nss/moz.build
vendored
6
config/external/nss/moz.build
vendored
@ -4,17 +4,16 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'nss'
|
||||
|
||||
DIRS += ['crmf']
|
||||
|
||||
if CONFIG['MOZ_NATIVE_NSS']:
|
||||
Library('nss')
|
||||
OS_LIBS += CONFIG['NSS_LIBS']
|
||||
elif CONFIG['MOZ_FOLD_LIBS']:
|
||||
SharedLibrary('nss')
|
||||
# TODO: The library name can be changed when bug 845217 is fixed.
|
||||
SHARED_LIBRARY_NAME = 'nss3'
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
SDK_LIBRARY = True
|
||||
|
||||
# Normally, there should be /something/ to ensure nspr is built
|
||||
@ -38,6 +37,7 @@ elif CONFIG['MOZ_FOLD_LIBS']:
|
||||
if CONFIG['OS_ARCH'] == 'Linux' and CONFIG['GCC_USE_GNU_LD']:
|
||||
LD_VERSION_SCRIPT = 'nss3.def'
|
||||
else:
|
||||
Library('nss')
|
||||
USE_LIBS += [
|
||||
'/security/nss/lib/nss/nss3',
|
||||
'/security/nss/lib/smime/smime3',
|
||||
|
6
config/external/sqlite/moz.build
vendored
6
config/external/sqlite/moz.build
vendored
@ -4,19 +4,19 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'sqlite'
|
||||
|
||||
if CONFIG['MOZ_NATIVE_SQLITE']:
|
||||
Library('sqlite')
|
||||
OS_LIBS += CONFIG['SQLITE_LIBS']
|
||||
else:
|
||||
DIRS += ['../../../db/sqlite3/src']
|
||||
if CONFIG['MOZ_FOLD_LIBS']:
|
||||
Library('sqlite')
|
||||
# When folding libraries, sqlite is actually in the nss library.
|
||||
USE_LIBS += [
|
||||
'nss',
|
||||
]
|
||||
else:
|
||||
FORCE_SHARED_LIB = True
|
||||
SharedLibrary('sqlite')
|
||||
SHARED_LIBRARY_NAME = 'mozsqlite3'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux' and CONFIG['GCC_USE_GNU_LD']:
|
||||
|
2
config/external/zlib/moz.build
vendored
2
config/external/zlib/moz.build
vendored
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'zlib'
|
||||
Library('zlib')
|
||||
|
||||
if CONFIG['MOZ_NATIVE_ZLIB']:
|
||||
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
|
||||
|
@ -21,7 +21,7 @@ if CONFIG['HOST_OS_ARCH'] != 'WINNT':
|
||||
'nsinstall.c',
|
||||
'pathsub.c',
|
||||
]
|
||||
HOST_PROGRAM = 'nsinstall_real'
|
||||
HostProgram('nsinstall_real')
|
||||
|
||||
if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
|
||||
DEFINES['GKMEDIAS_SHARED_LIBRARY'] = True
|
||||
|
@ -343,8 +343,8 @@ ImportLoader::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
// We should never import non-system documents and run their scripts with system principal!
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->GetChannelPrincipal(channel,
|
||||
getter_AddRefs(channelPrincipal));
|
||||
nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(channel,
|
||||
getter_AddRefs(channelPrincipal));
|
||||
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -5670,7 +5670,7 @@ nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel
|
||||
|
||||
nsCOMPtr<nsIPrincipal> oldPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
|
||||
GetChannelResultPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
aNewChannel->GetURI(getter_AddRefs(newURI));
|
||||
|
@ -682,13 +682,15 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
|
||||
|
||||
if (mHasBeenCrossSite) {
|
||||
// Once we've been cross-site, cross-origin redirects reset our source
|
||||
// origin.
|
||||
// origin. Note that we need to call GetChannelURIPrincipal() because
|
||||
// we are looking for the principal that is actually being loaded and not
|
||||
// the principal that initiated the load.
|
||||
nsCOMPtr<nsIPrincipal> oldChannelPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelPrincipal(aOldChannel, getter_AddRefs(oldChannelPrincipal));
|
||||
GetChannelURIPrincipal(aOldChannel, getter_AddRefs(oldChannelPrincipal));
|
||||
nsCOMPtr<nsIPrincipal> newChannelPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelPrincipal(aNewChannel, getter_AddRefs(newChannelPrincipal));
|
||||
GetChannelURIPrincipal(aNewChannel, getter_AddRefs(newChannelPrincipal));
|
||||
if (!oldChannelPrincipal || !newChannelPrincipal) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -2208,15 +2208,15 @@ nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (aChannel) {
|
||||
// Note: this code is duplicated in XULDocument::StartDocumentLoad and
|
||||
// nsScriptSecurityManager::GetChannelPrincipal.
|
||||
// nsScriptSecurityManager::GetChannelResultPrincipal.
|
||||
// Note: this should match nsDocShell::OnLoadingSite
|
||||
NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
|
||||
nsIScriptSecurityManager *securityManager =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
if (securityManager) {
|
||||
securityManager->GetChannelPrincipal(aChannel,
|
||||
getter_AddRefs(principal));
|
||||
securityManager->GetChannelResultPrincipal(aChannel,
|
||||
getter_AddRefs(principal));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1461,7 +1461,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||
// principal as the origin principal
|
||||
if (aRequest->mCORSMode == CORS_NONE) {
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
GetChannelPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
|
||||
GetChannelResultPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,12 @@ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
||||
if CONFIG['OS_ARCH'] != 'Darwin':
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit_ipc/xpcshell.ini']
|
||||
|
||||
CPP_UNIT_TESTS += [
|
||||
CppUnitTests([
|
||||
'TestCSPParser',
|
||||
'TestGetURL',
|
||||
'TestNativeXMLHttpRequest',
|
||||
'TestPlainTextSerializer',
|
||||
]
|
||||
|
||||
SOURCES += sorted('%s.cpp' % t for t in CPP_UNIT_TESTS)
|
||||
])
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'chrome/mochitest.ini',
|
||||
|
@ -94,7 +94,7 @@ ImageListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
if (secMan) {
|
||||
secMan->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
|
||||
secMan->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
|
||||
}
|
||||
|
||||
int16_t decision = nsIContentPolicy::ACCEPT;
|
||||
|
@ -534,7 +534,7 @@ ChannelMediaResource::OnDataAvailable(nsIRequest* aRequest,
|
||||
CopySegmentClosure closure;
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
if (secMan && mChannel) {
|
||||
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(closure.mPrincipal));
|
||||
secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(closure.mPrincipal));
|
||||
}
|
||||
closure.mResource = this;
|
||||
|
||||
@ -1406,7 +1406,7 @@ already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal()
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
if (!secMan || !mChannel)
|
||||
return nullptr;
|
||||
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(principal));
|
||||
secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
|
@ -740,7 +740,7 @@ already_AddRefed<nsIPrincipal> RtspMediaResource::GetCurrentPrincipal()
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
if (!secMan || !mChannel)
|
||||
return nullptr;
|
||||
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(principal));
|
||||
secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,10 @@
|
||||
# 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/.
|
||||
|
||||
CPP_UNIT_TESTS += [
|
||||
CppUnitTests([
|
||||
'TestAudioBuffers',
|
||||
'TestAudioMixer'
|
||||
]
|
||||
|
||||
SOURCES += sorted('%s.cpp' % t for t in CPP_UNIT_TESTS)
|
||||
])
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
|
@ -197,6 +197,7 @@ PlatformCallback(void* decompressionOutputRefCon,
|
||||
}
|
||||
if (flags & kVTDecodeInfo_FrameDropped) {
|
||||
NS_WARNING(" ...frame dropped...");
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(),
|
||||
"VideoToolbox returned an unexpected image type");
|
||||
|
@ -132,6 +132,27 @@ MediaSourceDecoder::CreateSubDecoder(const nsACString& aType)
|
||||
return mReader->CreateSubDecoder(aType);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::AddTrackBuffer(TrackBuffer* aTrackBuffer)
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
mReader->AddTrackBuffer(aTrackBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::RemoveTrackBuffer(TrackBuffer* aTrackBuffer)
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
mReader->RemoveTrackBuffer(aTrackBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo)
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
mReader->OnTrackBufferConfigured(aTrackBuffer, aInfo);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::Ended()
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ class MediaResource;
|
||||
class MediaDecoderStateMachine;
|
||||
class MediaSourceReader;
|
||||
class SourceBufferDecoder;
|
||||
class TrackBuffer;
|
||||
|
||||
namespace dom {
|
||||
|
||||
@ -46,6 +47,9 @@ public:
|
||||
void DetachMediaSource();
|
||||
|
||||
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
|
||||
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
|
||||
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
|
||||
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
|
||||
|
||||
void Ended();
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "MediaSourceUtils.h"
|
||||
#include "SourceBufferDecoder.h"
|
||||
#include "TrackBuffer.h"
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Decoder.h"
|
||||
@ -37,6 +38,8 @@ namespace mozilla {
|
||||
|
||||
MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder)
|
||||
, mLastAudioTime(-1)
|
||||
, mLastVideoTime(-1)
|
||||
, mTimeThreshold(-1)
|
||||
, mDropAudioBeforeThreshold(false)
|
||||
, mDropVideoBeforeThreshold(false)
|
||||
@ -49,25 +52,35 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
|
||||
bool
|
||||
MediaSourceReader::IsWaitingMediaResources()
|
||||
{
|
||||
return mDecoders.IsEmpty() && mPendingDecoders.IsEmpty();
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
if (!mTrackBuffers[i]->IsReady()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return mTrackBuffers.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestAudioData()
|
||||
{
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this);
|
||||
if (!mAudioReader) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this);
|
||||
MOZ_ASSERT(mPendingDecoders.IsEmpty());
|
||||
GetCallback()->OnDecodeError();
|
||||
return;
|
||||
}
|
||||
SwitchReaders(SWITCH_OPTIONAL);
|
||||
if (SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S)) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData switching audio reader", this);
|
||||
}
|
||||
mAudioReader->RequestAudioData();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
||||
{
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld mDuration=%lld d=%d",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropAudioBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
|
||||
@ -86,21 +99,22 @@ MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
||||
mAudioIsSeeking = false;
|
||||
aSample->mDiscontinuity = true;
|
||||
}
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
GetCallback()->OnAudioDecoded(aSample);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioEOS()
|
||||
{
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p (readers=%u)",
|
||||
this, mAudioReader.get(), mDecoders.Length());
|
||||
if (SwitchReaders(SWITCH_FORCED)) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p (decoders=%u)",
|
||||
this, mAudioReader.get(), mAudioTrack->Decoders().Length());
|
||||
if (SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S)) {
|
||||
// Success! Resume decoding with next audio decoder.
|
||||
RequestAudioData();
|
||||
} else if (IsEnded()) {
|
||||
// End of stream.
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p EOS (readers=%u)",
|
||||
this, mAudioReader.get(), mDecoders.Length());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p EOS (decoders=%u)",
|
||||
this, mAudioReader.get(), mAudioTrack->Decoders().Length());
|
||||
GetCallback()->OnAudioEOS();
|
||||
}
|
||||
}
|
||||
@ -108,26 +122,35 @@ MediaSourceReader::OnAudioEOS()
|
||||
void
|
||||
MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
|
||||
{
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestVideoData(%d, %lld)",
|
||||
this, aSkipToNextKeyframe, aTimeThreshold);
|
||||
if (!mVideoReader) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called with no video reader", this);
|
||||
MOZ_ASSERT(mPendingDecoders.IsEmpty());
|
||||
GetCallback()->OnDecodeError();
|
||||
return;
|
||||
}
|
||||
mTimeThreshold = aTimeThreshold;
|
||||
SwitchReaders(SWITCH_OPTIONAL);
|
||||
if (aSkipToNextKeyframe) {
|
||||
mTimeThreshold = aTimeThreshold;
|
||||
mDropAudioBeforeThreshold = true;
|
||||
mDropVideoBeforeThreshold = true;
|
||||
}
|
||||
if (SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S)) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestVideoData switching video reader", this);
|
||||
}
|
||||
mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
||||
{
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld mDuration=%lld d=%d",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropVideoBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
|
||||
this, aSample->mTime, mTimeThreshold);
|
||||
delete aSample;
|
||||
mVideoReader->RequestVideoData(false, mTimeThreshold);
|
||||
mVideoReader->RequestVideoData(false, 0);
|
||||
return;
|
||||
}
|
||||
mDropVideoBeforeThreshold = false;
|
||||
@ -140,7 +163,7 @@ MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
||||
mVideoIsSeeking = false;
|
||||
aSample->mDiscontinuity = true;
|
||||
}
|
||||
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
GetCallback()->OnVideoDecoded(aSample);
|
||||
}
|
||||
|
||||
@ -148,15 +171,15 @@ void
|
||||
MediaSourceReader::OnVideoEOS()
|
||||
{
|
||||
// End of stream. See if we can switch to another video decoder.
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p (readers=%u)",
|
||||
this, mVideoReader.get(), mDecoders.Length());
|
||||
if (SwitchReaders(SWITCH_FORCED)) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p (decoders=%u)",
|
||||
this, mVideoReader.get(), mVideoTrack->Decoders().Length());
|
||||
if (SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S)) {
|
||||
// Success! Resume decoding with next video decoder.
|
||||
RequestVideoData(false, mTimeThreshold);
|
||||
RequestVideoData(false, 0);
|
||||
} else if (IsEnded()) {
|
||||
// End of stream.
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p EOS (readers=%u)",
|
||||
this, mVideoReader.get(), mDecoders.Length());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p EOS (decoders=%u)",
|
||||
this, mVideoReader.get(), mVideoTrack->Decoders().Length());
|
||||
GetCallback()->OnVideoEOS();
|
||||
}
|
||||
}
|
||||
@ -164,6 +187,7 @@ MediaSourceReader::OnVideoEOS()
|
||||
void
|
||||
MediaSourceReader::OnDecodeError()
|
||||
{
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnDecodeError", this);
|
||||
GetCallback()->OnDecodeError();
|
||||
}
|
||||
|
||||
@ -171,171 +195,105 @@ void
|
||||
MediaSourceReader::Shutdown()
|
||||
{
|
||||
MediaDecoderReader::Shutdown();
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->Shutdown();
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->Shutdown();
|
||||
}
|
||||
mTrackBuffers.Clear();
|
||||
mAudioTrack = nullptr;
|
||||
mAudioReader = nullptr;
|
||||
mVideoTrack = nullptr;
|
||||
mVideoReader = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::BreakCycles()
|
||||
{
|
||||
MediaDecoderReader::BreakCycles();
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->BreakCycles();
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->BreakCycles();
|
||||
}
|
||||
mTrackBuffers.Clear();
|
||||
mAudioTrack = nullptr;
|
||||
mAudioReader = nullptr;
|
||||
mVideoTrack = nullptr;
|
||||
mVideoReader = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::SwitchAudioReader(MediaDecoderReader* aTargetReader)
|
||||
MediaSourceReader::SwitchAudioReader(double aTarget)
|
||||
{
|
||||
if (aTargetReader == mAudioReader) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding an audio track after ReadMetadata yet.
|
||||
if (!mAudioTrack) {
|
||||
return false;
|
||||
}
|
||||
if (mAudioReader) {
|
||||
AudioInfo targetInfo = aTargetReader->GetMediaInfo().mAudio;
|
||||
auto& decoders = mAudioTrack->Decoders();
|
||||
for (uint32_t i = 0; i < decoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
decoders[i]->GetBuffered(ranges);
|
||||
|
||||
MediaDecoderReader* newReader = decoders[i]->GetReader();
|
||||
MSE_DEBUGV("MediaDecoderReader(%p)::SwitchAudioReader(%f) audioReader=%p reader=%p ranges=%s",
|
||||
this, aTarget, mAudioReader.get(), newReader, DumpTimeRanges(ranges).get());
|
||||
|
||||
AudioInfo targetInfo = newReader->GetMediaInfo().mAudio;
|
||||
AudioInfo currentInfo = mAudioReader->GetMediaInfo().mAudio;
|
||||
|
||||
// TODO: We can't handle switching audio formats yet.
|
||||
if (currentInfo.mRate != targetInfo.mRate ||
|
||||
currentInfo.mChannels != targetInfo.mChannels) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
mAudioReader->SetIdle();
|
||||
if (ranges->Find(aTarget) != dom::TimeRanges::NoIndex) {
|
||||
if (newReader->AudioQueue().AtEndOfStream()) {
|
||||
continue;
|
||||
}
|
||||
if (mAudioReader) {
|
||||
mAudioReader->SetIdle();
|
||||
}
|
||||
mAudioReader = newReader;
|
||||
MSE_DEBUG("MediaDecoderReader(%p)::SwitchAudioReader(%f) switching to audio reader %p",
|
||||
this, aTarget, mAudioReader.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mAudioReader = aTargetReader;
|
||||
mDropAudioBeforeThreshold = true;
|
||||
MSE_DEBUG("MediaDecoderReader(%p)::SwitchReaders(%p) switching audio reader",
|
||||
this, mAudioReader.get());
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::SwitchVideoReader(MediaDecoderReader* aTargetReader)
|
||||
MediaSourceReader::SwitchVideoReader(double aTarget)
|
||||
{
|
||||
if (aTargetReader == mVideoReader) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding a video track after ReadMetadata yet.
|
||||
if (!mVideoTrack) {
|
||||
return false;
|
||||
}
|
||||
if (mVideoReader) {
|
||||
mVideoReader->SetIdle();
|
||||
}
|
||||
mVideoReader = aTargetReader;
|
||||
mDropVideoBeforeThreshold = true;
|
||||
MSE_DEBUG("MediaDecoderReader(%p)::SwitchVideoReader(%p) switching video reader",
|
||||
this, mVideoReader.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::SwitchReaders(SwitchType aType)
|
||||
{
|
||||
InitializePendingDecoders();
|
||||
|
||||
// This monitor must be held after the call to InitializePendingDecoders
|
||||
// as that method also obtains the lock, and then attempts to exit it
|
||||
// to call ReadMetadata on the readers. If we hold it before the call then
|
||||
// it remains held during the ReadMetadata call causing a deadlock.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
bool didSwitch = false;
|
||||
double decodeTarget = double(mTimeThreshold) / USECS_PER_S;
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
SourceBufferDecoder* decoder = mDecoders[i];
|
||||
const MediaInfo& info = decoder->GetReader()->GetMediaInfo();
|
||||
|
||||
auto& decoders = mVideoTrack->Decoders();
|
||||
for (uint32_t i = 0; i < decoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
decoder->GetBuffered(ranges);
|
||||
decoders[i]->GetBuffered(ranges);
|
||||
|
||||
MSE_DEBUGV("MediaDecoderReader(%p)::SwitchReaders(%d) decoder=%u (%p) discarded=%d"
|
||||
" reader=%p audioReader=%p videoReader=%p"
|
||||
" hasAudio=%d hasVideo=%d decodeTarget=%f ranges=%s",
|
||||
this, aType, i, decoder, decoder->IsDiscarded(),
|
||||
decoder->GetReader(), mAudioReader.get(), mVideoReader.get(),
|
||||
info.HasAudio(), info.HasVideo(), decodeTarget,
|
||||
DumpTimeRanges(ranges).get());
|
||||
MediaDecoderReader* newReader = decoders[i]->GetReader();
|
||||
MSE_DEBUGV("MediaDecoderReader(%p)::SwitchVideoReader(%f) videoReader=%p reader=%p ranges=%s",
|
||||
this, aTarget, mVideoReader.get(), newReader, DumpTimeRanges(ranges).get());
|
||||
|
||||
if (decoder->IsDiscarded()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aType == SWITCH_FORCED || ranges->Find(decodeTarget) != dom::TimeRanges::NoIndex) {
|
||||
if (info.HasAudio()) {
|
||||
didSwitch |= SwitchAudioReader(mDecoders[i]->GetReader());
|
||||
if (ranges->Find(aTarget) != dom::TimeRanges::NoIndex) {
|
||||
if (newReader->VideoQueue().AtEndOfStream()) {
|
||||
continue;
|
||||
}
|
||||
if (info.HasVideo()) {
|
||||
didSwitch |= SwitchVideoReader(mDecoders[i]->GetReader());
|
||||
if (mVideoReader) {
|
||||
mVideoReader->SetIdle();
|
||||
}
|
||||
mVideoReader = newReader;
|
||||
MSE_DEBUG("MediaDecoderReader(%p)::SwitchVideoReader(%f) switching to video reader %p",
|
||||
this, aTarget, mVideoReader.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return didSwitch;
|
||||
}
|
||||
|
||||
class ReleaseDecodersTask : public nsRunnable {
|
||||
public:
|
||||
explicit ReleaseDecodersTask(nsTArray<nsRefPtr<SourceBufferDecoder>>& aDecoders)
|
||||
{
|
||||
mDecoders.SwapElements(aDecoders);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
|
||||
mDecoders.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
|
||||
};
|
||||
|
||||
void
|
||||
MediaSourceReader::InitializePendingDecoders()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
for (uint32_t i = 0; i < mPendingDecoders.Length(); ++i) {
|
||||
nsRefPtr<SourceBufferDecoder> decoder = mPendingDecoders[i];
|
||||
MediaDecoderReader* reader = decoder->GetReader();
|
||||
MSE_DEBUG("MediaSourceReader(%p): Initializing subdecoder %p reader %p",
|
||||
this, decoder.get(), reader);
|
||||
|
||||
MediaInfo mi;
|
||||
nsAutoPtr<MetadataTags> tags; // TODO: Handle metadata.
|
||||
nsresult rv;
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
|
||||
}
|
||||
reader->SetIdle();
|
||||
if (NS_FAILED(rv)) {
|
||||
// XXX: Need to signal error back to owning SourceBuffer.
|
||||
MSE_DEBUG("MediaSourceReader(%p): Reader %p failed to initialize rv=%x", this, reader, rv);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool active = false;
|
||||
if (mi.HasVideo() || mi.HasAudio()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Reader %p has video=%d audio=%d",
|
||||
this, reader, mi.HasVideo(), mi.HasAudio());
|
||||
if (mi.HasVideo()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Reader %p video resolution=%dx%d",
|
||||
this, reader, mi.mVideo.mDisplay.width, mi.mVideo.mDisplay.height);
|
||||
}
|
||||
if (mi.HasAudio()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Reader %p audio sampleRate=%d channels=%d",
|
||||
this, reader, mi.mAudio.mRate, mi.mAudio.mChannels);
|
||||
}
|
||||
active = true;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
mDecoders.AppendElement(decoder);
|
||||
} else {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Reader %p not activated", this, reader);
|
||||
}
|
||||
}
|
||||
NS_DispatchToMainThread(new ReleaseDecodersTask(mPendingDecoders));
|
||||
MOZ_ASSERT(mPendingDecoders.IsEmpty());
|
||||
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
return false;
|
||||
}
|
||||
|
||||
MediaDecoderReader*
|
||||
@ -376,22 +334,51 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType)
|
||||
reader->SetCallback(callback);
|
||||
reader->SetTaskQueue(GetTaskQueue());
|
||||
reader->Init(nullptr);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::CreateSubDecoder subdecoder %p subreader %p",
|
||||
this, decoder.get(), reader.get());
|
||||
decoder->SetReader(reader);
|
||||
mPendingDecoders.AppendElement(decoder);
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &MediaSourceReader::InitializePendingDecoders);
|
||||
if (NS_FAILED(GetTaskQueue()->Dispatch(task))) {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this);
|
||||
return nullptr;
|
||||
}
|
||||
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
namespace {
|
||||
void
|
||||
MediaSourceReader::AddTrackBuffer(TrackBuffer* aTrackBuffer)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::AddTrackBuffer %p", this, aTrackBuffer);
|
||||
mTrackBuffers.AppendElement(aTrackBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RemoveTrackBuffer(TrackBuffer* aTrackBuffer)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RemoveTrackBuffer %p", this, aTrackBuffer);
|
||||
mTrackBuffers.RemoveElement(aTrackBuffer);
|
||||
if (mAudioTrack == aTrackBuffer) {
|
||||
mAudioTrack = nullptr;
|
||||
}
|
||||
if (mVideoTrack == aTrackBuffer) {
|
||||
mVideoTrack = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(mTrackBuffers.Contains(aTrackBuffer));
|
||||
if (aInfo.HasAudio() && !mAudioTrack) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnTrackBufferConfigured %p audio", this, aTrackBuffer);
|
||||
mAudioTrack = aTrackBuffer;
|
||||
}
|
||||
if (aInfo.HasVideo() && !mVideoTrack) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnTrackBufferConfigured %p video", this, aTrackBuffer);
|
||||
mVideoTrack = aTrackBuffer;
|
||||
}
|
||||
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
}
|
||||
|
||||
class ChangeToHaveMetadata : public nsRunnable {
|
||||
public:
|
||||
explicit ChangeToHaveMetadata(AbstractMediaDecoder* aDecoder) :
|
||||
@ -410,23 +397,18 @@ public:
|
||||
private:
|
||||
nsRefPtr<AbstractMediaDecoder> mDecoder;
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::DecodersContainTime(double aTime)
|
||||
MediaSourceReader::TrackBuffersContainTime(double aTime)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
if (!mDecoders[i]->IsDiscarded()) {
|
||||
if (!mDecoders[i]->ContainsTime(aTime)) {
|
||||
// No use to continue searching, one source buffer isn't ready yet
|
||||
return false;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mAudioTrack && !mAudioTrack->ContainsTime(aTime)) {
|
||||
return false;
|
||||
}
|
||||
return found;
|
||||
if (mVideoTrack && !mVideoTrack->ContainsTime(aTime)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -435,8 +417,18 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
{
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek(aTime=%lld, aStart=%lld, aEnd=%lld, aCurrent=%lld)",
|
||||
this, aTime, aStartTime, aEndTime, aCurrentTime);
|
||||
|
||||
ResetDecode();
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->ResetDecode();
|
||||
}
|
||||
|
||||
// Decoding discontinuity upon seek, reset last times to seek target.
|
||||
mLastAudioTime = aTime;
|
||||
mLastVideoTime = aTime;
|
||||
|
||||
double target = static_cast<double>(aTime) / USECS_PER_S;
|
||||
if (!DecodersContainTime(target)) {
|
||||
if (!TrackBuffersContainTime(target)) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek no active buffer contains target=%f", this, target);
|
||||
NS_DispatchToMainThread(new ChangeToHaveMetadata(mDecoder));
|
||||
}
|
||||
@ -444,28 +436,30 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
// Loop until we have the requested time range in the source buffers.
|
||||
// This is a workaround for our lack of async functionality in the
|
||||
// MediaDecoderStateMachine. Bug 979104 implements what we need and
|
||||
// we'll remove this for an async approach based on that in bug XXXXXXX.
|
||||
while (!DecodersContainTime(target) && !IsShutdown() && !IsEnded()) {
|
||||
// we'll remove this for an async approach based on that in bug 1056441.
|
||||
while (!TrackBuffersContainTime(target) && !IsShutdown() && !IsEnded()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek waiting for target=%f", this, target);
|
||||
static_cast<MediaSourceDecoder*>(mDecoder)->WaitForData();
|
||||
SwitchReaders(SWITCH_FORCED);
|
||||
}
|
||||
|
||||
if (IsShutdown()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ResetDecode();
|
||||
if (mAudioReader) {
|
||||
if (mAudioTrack) {
|
||||
mAudioIsSeeking = true;
|
||||
DebugOnly<bool> ok = SwitchAudioReader(target);
|
||||
MOZ_ASSERT(ok && static_cast<SourceBufferDecoder*>(mAudioReader->GetDecoder())->ContainsTime(target));
|
||||
nsresult rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p rv=%x", this, mAudioReader.get(), rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (mVideoReader) {
|
||||
if (mVideoTrack) {
|
||||
mVideoIsSeeking = true;
|
||||
DebugOnly<bool> ok = SwitchVideoReader(target);
|
||||
MOZ_ASSERT(ok && static_cast<SourceBufferDecoder*>(mVideoReader->GetDecoder())->ContainsTime(target));
|
||||
nsresult rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p rv=%x", this, mVideoReader.get(), rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -478,39 +472,41 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
nsresult
|
||||
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
||||
{
|
||||
InitializePendingDecoders();
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata tracks=%u", this, mTrackBuffers.Length());
|
||||
// ReadMetadata is called *before* checking IsWaitingMediaResources.
|
||||
if (IsWaitingMediaResources()) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!mAudioTrack && !mVideoTrack) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata missing track: mAudioTrack=%p mVideoTrack=%p",
|
||||
this, mAudioTrack.get(), mVideoTrack.get());
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata decoders=%u", this, mDecoders.Length());
|
||||
|
||||
// XXX: Make subdecoder setup async, so that use cases like bug 989888 can
|
||||
// work. This will require teaching the state machine about dynamic track
|
||||
// changes (and multiple tracks).
|
||||
// Shorter term, make this block until we've got at least one video track
|
||||
// and lie about having an audio track, then resample/remix as necessary
|
||||
// to match any audio track added later to fit the format we lied about
|
||||
// now. For now we just configure what we've got and cross our fingers.
|
||||
int64_t maxDuration = -1;
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
MediaDecoderReader* reader = mDecoders[i]->GetReader();
|
||||
|
||||
MediaInfo mi = reader->GetMediaInfo();
|
||||
if (mAudioTrack) {
|
||||
MOZ_ASSERT(mAudioTrack->IsReady());
|
||||
mAudioReader = mAudioTrack->Decoders()[0]->GetReader();
|
||||
|
||||
if (mi.HasVideo() && !mInfo.HasVideo()) {
|
||||
MOZ_ASSERT(!mVideoReader);
|
||||
mVideoReader = reader;
|
||||
mInfo.mVideo = mi.mVideo;
|
||||
maxDuration = std::max(maxDuration, mDecoders[i]->GetMediaDuration());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p maxDuration=%lld",
|
||||
this, reader, maxDuration);
|
||||
}
|
||||
if (mi.HasAudio() && !mInfo.HasAudio()) {
|
||||
MOZ_ASSERT(!mAudioReader);
|
||||
mAudioReader = reader;
|
||||
mInfo.mAudio = mi.mAudio;
|
||||
maxDuration = std::max(maxDuration, mDecoders[i]->GetMediaDuration());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p maxDuration=%lld",
|
||||
this, reader, maxDuration);
|
||||
}
|
||||
const MediaInfo& info = mAudioReader->GetMediaInfo();
|
||||
MOZ_ASSERT(info.HasAudio());
|
||||
mInfo.mAudio = info.mAudio;
|
||||
maxDuration = std::max(maxDuration, mAudioReader->GetDecoder()->GetMediaDuration());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p maxDuration=%lld",
|
||||
this, mAudioReader.get(), maxDuration);
|
||||
}
|
||||
|
||||
if (mVideoTrack) {
|
||||
MOZ_ASSERT(mVideoTrack->IsReady());
|
||||
mVideoReader = mVideoTrack->Decoders()[0]->GetReader();
|
||||
|
||||
const MediaInfo& info = mVideoReader->GetMediaInfo();
|
||||
MOZ_ASSERT(info.HasVideo());
|
||||
mInfo.mVideo = info.mVideo;
|
||||
maxDuration = std::max(maxDuration, mVideoReader->GetDecoder()->GetMediaDuration());
|
||||
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p maxDuration=%lld",
|
||||
this, mVideoReader.get(), maxDuration);
|
||||
}
|
||||
|
||||
if (maxDuration != -1) {
|
||||
|
@ -19,6 +19,7 @@ namespace mozilla {
|
||||
|
||||
class MediaSourceDecoder;
|
||||
class SourceBufferDecoder;
|
||||
class TrackBuffer;
|
||||
|
||||
namespace dom {
|
||||
|
||||
@ -70,22 +71,25 @@ public:
|
||||
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
|
||||
nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
int64_t aCurrentTime) MOZ_OVERRIDE;
|
||||
|
||||
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
|
||||
|
||||
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
|
||||
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
|
||||
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
virtual void BreakCycles();
|
||||
|
||||
void InitializePendingDecoders();
|
||||
|
||||
bool IsShutdown()
|
||||
{
|
||||
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
||||
return mDecoder->IsShutdown();
|
||||
}
|
||||
|
||||
// Return true if any of the active decoders contain data for the given time
|
||||
bool DecodersContainTime(double aTime);
|
||||
// Return true if all of the active tracks contain data for the specified time.
|
||||
bool TrackBuffersContainTime(double aTime);
|
||||
|
||||
// Mark the reader to indicate that EndOfStream has been called on our MediaSource
|
||||
void Ended();
|
||||
@ -94,27 +98,24 @@ public:
|
||||
bool IsEnded();
|
||||
|
||||
private:
|
||||
enum SwitchType {
|
||||
SWITCH_OPTIONAL,
|
||||
SWITCH_FORCED
|
||||
};
|
||||
|
||||
bool SwitchReaders(SwitchType aType);
|
||||
|
||||
bool SwitchAudioReader(MediaDecoderReader* aTargetReader);
|
||||
bool SwitchVideoReader(MediaDecoderReader* aTargetReader);
|
||||
|
||||
// These are read and written on the decode task queue threads.
|
||||
int64_t mTimeThreshold;
|
||||
bool mDropAudioBeforeThreshold;
|
||||
bool mDropVideoBeforeThreshold;
|
||||
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mPendingDecoders;
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
|
||||
bool SwitchAudioReader(double aTarget);
|
||||
bool SwitchVideoReader(double aTarget);
|
||||
|
||||
nsRefPtr<MediaDecoderReader> mAudioReader;
|
||||
nsRefPtr<MediaDecoderReader> mVideoReader;
|
||||
|
||||
nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
|
||||
nsRefPtr<TrackBuffer> mAudioTrack;
|
||||
nsRefPtr<TrackBuffer> mVideoTrack;
|
||||
|
||||
// These are read and written on the decode task queue threads.
|
||||
int64_t mLastAudioTime;
|
||||
int64_t mLastVideoTime;
|
||||
|
||||
int64_t mTimeThreshold;
|
||||
bool mDropAudioBeforeThreshold;
|
||||
bool mDropVideoBeforeThreshold;
|
||||
|
||||
bool mEnded;
|
||||
|
||||
// For a seek to complete we need to send a sample with
|
||||
|
@ -6,14 +6,14 @@
|
||||
#include "SourceBuffer.h"
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "MediaSourceUtils.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "TrackBuffer.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "WebMBufferedParser.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/MediaSourceBinding.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "mp4_demuxer/BufferStream.h"
|
||||
@ -23,10 +23,6 @@
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prlog.h"
|
||||
#include "SourceBufferDecoder.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "WebMBufferedParser.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
@ -335,19 +331,8 @@ SourceBuffer::GetBuffered(ErrorResult& aRv)
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
double highestEndTime = 0;
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
// TODO: Need to adjust mDecoders so it only tracks active decoders.
|
||||
// Once we have an abstraction for track buffers, this needs to report the
|
||||
// intersection of buffered ranges within those track buffers.
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
nsRefPtr<TimeRanges> r = new TimeRanges();
|
||||
mDecoders[i]->GetBuffered(r);
|
||||
if (r->Length() > 0) {
|
||||
highestEndTime = std::max(highestEndTime, r->GetEndTime());
|
||||
ranges->Union(r);
|
||||
}
|
||||
}
|
||||
double highestEndTime = mTrackBuffer->Buffered(ranges);
|
||||
if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
|
||||
// Set the end time on the last range to highestEndTime by adding a
|
||||
// new range spanning the current end time to highestEndTime, which
|
||||
@ -432,7 +417,7 @@ SourceBuffer::Abort(ErrorResult& aRv)
|
||||
mAppendWindowEnd = PositiveInfinity<double>();
|
||||
|
||||
MSE_DEBUG("SourceBuffer(%p)::Abort() Discarding decoder", this);
|
||||
DiscardDecoder();
|
||||
mTrackBuffer->DiscardDecoder();
|
||||
}
|
||||
|
||||
void
|
||||
@ -464,8 +449,10 @@ SourceBuffer::Detach()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("SourceBuffer(%p)::Detach", this);
|
||||
Ended();
|
||||
DiscardDecoder();
|
||||
if (mTrackBuffer) {
|
||||
mTrackBuffer->Detach();
|
||||
}
|
||||
mTrackBuffer = nullptr;
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
@ -473,36 +460,34 @@ void
|
||||
SourceBuffer::Ended()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IsAttached());
|
||||
MSE_DEBUG("SourceBuffer(%p)::Ended", this);
|
||||
if (mDecoder) {
|
||||
mDecoder->GetResource()->Ended();
|
||||
}
|
||||
mTrackBuffer->DiscardDecoder();
|
||||
}
|
||||
|
||||
SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
||||
: DOMEventTargetHelper(aMediaSource->GetParentObject())
|
||||
, mMediaSource(aMediaSource)
|
||||
, mType(aType)
|
||||
, mLastParsedTimestamp(UnspecifiedNaN<double>())
|
||||
, mAppendWindowStart(0)
|
||||
, mAppendWindowEnd(PositiveInfinity<double>())
|
||||
, mTimestampOffset(0)
|
||||
, mAppendMode(SourceBufferAppendMode::Segments)
|
||||
, mUpdating(false)
|
||||
, mDecoderInitialized(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aMediaSource);
|
||||
mParser = ContainerParser::CreateForMIMEType(aType);
|
||||
MSE_DEBUG("SourceBuffer(%p)::SourceBuffer: Creating initial decoder, mParser=%p", this, mParser.get());
|
||||
InitNewDecoder();
|
||||
mTrackBuffer = new TrackBuffer(aMediaSource->GetDecoder(), aType);
|
||||
MSE_DEBUG("SourceBuffer(%p)::SourceBuffer: Create mParser=%p mTrackBuffer=%p",
|
||||
this, mParser.get(), mTrackBuffer.get());
|
||||
}
|
||||
|
||||
SourceBuffer::~SourceBuffer()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mMediaSource);
|
||||
MSE_DEBUG("SourceBuffer(%p)::~SourceBuffer", this);
|
||||
DiscardDecoder();
|
||||
}
|
||||
|
||||
MediaSource*
|
||||
@ -533,37 +518,6 @@ SourceBuffer::QueueAsyncSimpleEvent(const char* aName)
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool
|
||||
SourceBuffer::InitNewDecoder()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("SourceBuffer(%p)::InitNewDecoder", this);
|
||||
MOZ_ASSERT(!mDecoder);
|
||||
MediaSourceDecoder* parentDecoder = mMediaSource->GetDecoder();
|
||||
nsRefPtr<SourceBufferDecoder> decoder = parentDecoder->CreateSubDecoder(mType);
|
||||
if (!decoder) {
|
||||
return false;
|
||||
}
|
||||
mDecoder = decoder;
|
||||
mDecoderInitialized = false;
|
||||
mDecoders.AppendElement(mDecoder);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::DiscardDecoder()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("SourceBuffer(%p)::DiscardDecoder mDecoder=%p", this, mDecoder.get());
|
||||
if (mDecoder) {
|
||||
mDecoder->SetDiscarded();
|
||||
}
|
||||
mDecoder = nullptr;
|
||||
mDecoderInitialized = false;
|
||||
// XXX: Parser reset may be required?
|
||||
mLastParsedTimestamp = UnspecifiedNaN<double>();
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::StartUpdating()
|
||||
{
|
||||
@ -610,21 +564,14 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
||||
// TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
|
||||
if (mParser->IsInitSegmentPresent(aData, aLength)) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
|
||||
if (mDecoderInitialized) {
|
||||
// Existing decoder has been used, time for a new one.
|
||||
DiscardDecoder();
|
||||
}
|
||||
|
||||
// If we've got a decoder here, it's not initialized, so we can use it
|
||||
// rather than creating a new one.
|
||||
if (!mDecoder && !InitNewDecoder()) {
|
||||
mTrackBuffer->DiscardDecoder();
|
||||
if (!mTrackBuffer->NewDecoder()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
|
||||
return;
|
||||
}
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
|
||||
mDecoderInitialized = true;
|
||||
} else if (!mDecoderInitialized) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Non-init segment appended during initialization.");
|
||||
} else if (!mTrackBuffer->HasInitSegment()) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
|
||||
Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
|
||||
ErrorResult dummy;
|
||||
mMediaSource->EndOfStream(decodeError, dummy);
|
||||
@ -633,37 +580,39 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
||||
}
|
||||
double start, end;
|
||||
if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
|
||||
double lastStart, lastEnd;
|
||||
mTrackBuffer->LastTimestamp(lastStart, lastEnd);
|
||||
if (mParser->IsMediaSegmentPresent(aData, aLength) &&
|
||||
(start < mLastParsedTimestamp || start - mLastParsedTimestamp > 0.1)) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Data (%f, %f) overlaps %f.",
|
||||
this, start, end, mLastParsedTimestamp);
|
||||
(start < lastEnd || start - lastEnd > 0.1)) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%f, %f] overlaps [%f, %f]",
|
||||
this, lastStart, lastEnd, start, end);
|
||||
|
||||
// This data is earlier in the timeline than data we have already
|
||||
// processed, so we must create a new decoder to handle the decoding.
|
||||
DiscardDecoder();
|
||||
mTrackBuffer->DiscardDecoder();
|
||||
|
||||
// If we've got a decoder here, it's not initialized, so we can use it
|
||||
// rather than creating a new one.
|
||||
if (!InitNewDecoder()) {
|
||||
if (!mTrackBuffer->NewDecoder()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
|
||||
return;
|
||||
}
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
|
||||
mDecoderInitialized = true;
|
||||
const nsTArray<uint8_t>& initData = mParser->InitData();
|
||||
mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(initData.Elements()),
|
||||
initData.Length(),
|
||||
0);
|
||||
mDecoder->GetResource()->AppendData(initData.Elements(), initData.Length());
|
||||
mTrackBuffer->AppendData(initData.Elements(), initData.Length());
|
||||
mTrackBuffer->SetLastStartTimestamp(start);
|
||||
}
|
||||
mLastParsedTimestamp = end;
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment start=%f end=%f", this, start, end);
|
||||
mTrackBuffer->SetLastEndTimestamp(end);
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%f, %f] [%f, %f]",
|
||||
this, lastStart, lastEnd, start, end);
|
||||
}
|
||||
if (!mTrackBuffer->AppendData(aData, aLength)) {
|
||||
Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
|
||||
ErrorResult dummy;
|
||||
mMediaSource->EndOfStream(decodeError, dummy);
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
// XXX: For future reference: NDA call must run on the main thread.
|
||||
mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
|
||||
aLength,
|
||||
mDecoder->GetResource()->GetLength());
|
||||
mDecoder->GetResource()->AppendData(aData, aLength);
|
||||
|
||||
// Eviction uses a byte threshold. If the buffer is greater than the
|
||||
// number of bytes then data is evicted. The time range for this
|
||||
@ -673,7 +622,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
||||
// TODO: Make the eviction threshold smaller for audio-only streams.
|
||||
// TODO: Drive evictions off memory pressure notifications.
|
||||
const uint32_t evict_threshold = 75 * (1 << 20);
|
||||
bool evicted = mDecoder->GetResource()->EvictData(evict_threshold);
|
||||
bool evicted = mTrackBuffer->EvictData(evict_threshold);
|
||||
if (evicted) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData Evict; current buffered start=%f",
|
||||
this, GetBufferedStart());
|
||||
@ -714,20 +663,13 @@ SourceBuffer::Evict(double aStart, double aEnd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("SourceBuffer(%p)::Evict(aStart=%f, aEnd=%f)", this, aStart, aEnd);
|
||||
if (!mDecoder) {
|
||||
return;
|
||||
}
|
||||
double currentTime = mMediaSource->GetDecoder()->GetCurrentTime();
|
||||
double evictTime = aEnd;
|
||||
const double safety_threshold = 5;
|
||||
if (currentTime + safety_threshold >= evictTime) {
|
||||
evictTime -= safety_threshold;
|
||||
}
|
||||
int64_t endOffset = mDecoder->ConvertToByteOffset(evictTime);
|
||||
if (endOffset > 0) {
|
||||
mDecoder->GetResource()->EvictBefore(endOffset);
|
||||
}
|
||||
MSE_DEBUG("SourceBuffer(%p)::Evict offset=%lld", this, endOffset);
|
||||
mTrackBuffer->EvictBefore(evictTime);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(SourceBuffer, DOMEventTargetHelper,
|
||||
|
@ -7,14 +7,13 @@
|
||||
#ifndef mozilla_dom_SourceBuffer_h_
|
||||
#define mozilla_dom_SourceBuffer_h_
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaSource.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/SourceBufferBinding.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@ -31,8 +30,7 @@ namespace mozilla {
|
||||
|
||||
class ContainerParser;
|
||||
class ErrorResult;
|
||||
class SourceBufferResource;
|
||||
class SourceBufferDecoder;
|
||||
class TrackBuffer;
|
||||
template <typename T> class AsyncEventRunner;
|
||||
|
||||
namespace dom {
|
||||
@ -139,10 +137,7 @@ private:
|
||||
|
||||
nsAutoPtr<ContainerParser> mParser;
|
||||
|
||||
double mLastParsedTimestamp;
|
||||
|
||||
nsRefPtr<SourceBufferDecoder> mDecoder;
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
|
||||
nsRefPtr<TrackBuffer> mTrackBuffer;
|
||||
|
||||
double mAppendWindowStart;
|
||||
double mAppendWindowEnd;
|
||||
@ -151,8 +146,6 @@ private:
|
||||
|
||||
SourceBufferAppendMode mAppendMode;
|
||||
bool mUpdating;
|
||||
|
||||
bool mDecoderInitialized;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -38,7 +38,6 @@ SourceBufferDecoder::SourceBufferDecoder(MediaResource* aResource,
|
||||
, mParentDecoder(aParentDecoder)
|
||||
, mReader(nullptr)
|
||||
, mMediaDuration(-1)
|
||||
, mDiscarded(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(SourceBufferDecoder);
|
||||
@ -147,6 +146,10 @@ SourceBufferDecoder::OnStateMachineThread() const
|
||||
bool
|
||||
SourceBufferDecoder::OnDecodeThread() const
|
||||
{
|
||||
// During initialization we run on our TrackBuffer's task queue.
|
||||
if (mTaskQueue) {
|
||||
return mTaskQueue->IsCurrentThreadIn();
|
||||
}
|
||||
return mParentDecoder->OnDecodeThread();
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,10 @@
|
||||
#define MOZILLA_SOURCEBUFFERDECODER_H_
|
||||
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "SourceBufferResource.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -74,33 +75,30 @@ public:
|
||||
return mReader;
|
||||
}
|
||||
|
||||
void SetTaskQueue(MediaTaskQueue* aTaskQueue)
|
||||
{
|
||||
MOZ_ASSERT((!mTaskQueue && aTaskQueue) || (mTaskQueue && !aTaskQueue));
|
||||
mTaskQueue = aTaskQueue;
|
||||
}
|
||||
|
||||
// Given a time convert it into an approximate byte offset from the
|
||||
// cached data. Returns -1 if no such value is computable.
|
||||
int64_t ConvertToByteOffset(double aTime);
|
||||
|
||||
bool IsDiscarded()
|
||||
{
|
||||
return mDiscarded;
|
||||
}
|
||||
|
||||
void SetDiscarded()
|
||||
{
|
||||
GetResource()->Ended();
|
||||
mDiscarded = true;
|
||||
}
|
||||
|
||||
// Returns true if the data buffered by this decoder contains the given time.
|
||||
bool ContainsTime(double aTime);
|
||||
|
||||
private:
|
||||
virtual ~SourceBufferDecoder();
|
||||
|
||||
// Our TrackBuffer's task queue, this is only non-null during initialization.
|
||||
RefPtr<MediaTaskQueue> mTaskQueue;
|
||||
|
||||
nsRefPtr<MediaResource> mResource;
|
||||
|
||||
AbstractMediaDecoder* mParentDecoder;
|
||||
nsRefPtr<MediaDecoderReader> mReader;
|
||||
int64_t mMediaDuration;
|
||||
bool mDiscarded;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
339
content/media/mediasource/TrackBuffer.cpp
Normal file
339
content/media/mediasource/TrackBuffer.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "TrackBuffer.h"
|
||||
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "SharedThreadPool.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "SourceBufferDecoder.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/dom/MediaSourceBinding.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prlog.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* GetMediaSourceLog();
|
||||
extern PRLogModuleInfo* GetMediaSourceAPILog();
|
||||
|
||||
#define MSE_DEBUG(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
|
||||
#define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#else
|
||||
#define MSE_DEBUG(...)
|
||||
#define MSE_DEBUGV(...)
|
||||
#define MSE_API(...)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType)
|
||||
: mParentDecoder(aParentDecoder)
|
||||
, mType(aType)
|
||||
, mLastStartTimestamp(0)
|
||||
, mLastEndTimestamp(UnspecifiedNaN<double>())
|
||||
, mHasInit(false)
|
||||
, mHasAudio(false)
|
||||
, mHasVideo(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TrackBuffer);
|
||||
mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
aParentDecoder->AddTrackBuffer(this);
|
||||
}
|
||||
|
||||
TrackBuffer::~TrackBuffer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TrackBuffer);
|
||||
}
|
||||
|
||||
class ReleaseDecoderTask : public nsRunnable {
|
||||
public:
|
||||
explicit ReleaseDecoderTask(nsRefPtr<SourceBufferDecoder> aDecoder)
|
||||
{
|
||||
mDecoders.AppendElement(aDecoder);
|
||||
}
|
||||
|
||||
explicit ReleaseDecoderTask(nsTArray<nsRefPtr<SourceBufferDecoder>>& aDecoders)
|
||||
{
|
||||
mDecoders.SwapElements(aDecoders);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
|
||||
mDecoders.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
|
||||
};
|
||||
|
||||
void
|
||||
TrackBuffer::Shutdown()
|
||||
{
|
||||
// Shutdown waits for any pending events, which may require the monitor,
|
||||
// so we must not hold the monitor during this call.
|
||||
mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
|
||||
mTaskQueue->Shutdown();
|
||||
mTaskQueue = nullptr;
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
DiscardDecoder();
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->Shutdown();
|
||||
}
|
||||
NS_DispatchToMainThread(new ReleaseDecoderTask(mDecoders));
|
||||
MOZ_ASSERT(mDecoders.IsEmpty());
|
||||
mParentDecoder = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mCurrentDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceBufferResource* resource = mCurrentDecoder->GetResource();
|
||||
// XXX: For future reference: NDA call must run on the main thread.
|
||||
mCurrentDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
|
||||
aLength, resource->GetLength());
|
||||
resource->AppendData(aData, aLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::EvictData(uint32_t aThreshold)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// XXX Call EvictData on mDecoders?
|
||||
return mCurrentDecoder->GetResource()->EvictData(aThreshold);
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::EvictBefore(double aTime)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// XXX Call EvictBefore on mDecoders?
|
||||
int64_t endOffset = mCurrentDecoder->ConvertToByteOffset(aTime);
|
||||
if (endOffset > 0) {
|
||||
mCurrentDecoder->GetResource()->EvictBefore(endOffset);
|
||||
}
|
||||
MSE_DEBUG("TrackBuffer(%p)::EvictBefore offset=%lld", this, endOffset);
|
||||
}
|
||||
|
||||
double
|
||||
TrackBuffer::Buffered(dom::TimeRanges* aRanges)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// XXX check default if mDecoders empty?
|
||||
double highestEndTime = 0;
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
|
||||
mDecoders[i]->GetBuffered(r);
|
||||
if (r->Length() > 0) {
|
||||
highestEndTime = std::max(highestEndTime, r->GetEndTime());
|
||||
aRanges->Union(r);
|
||||
}
|
||||
}
|
||||
|
||||
return highestEndTime;
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::NewDecoder()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mCurrentDecoder && mParentDecoder);
|
||||
|
||||
nsRefPtr<SourceBufferDecoder> decoder = mParentDecoder->CreateSubDecoder(mType);
|
||||
if (!decoder) {
|
||||
return false;
|
||||
}
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
mCurrentDecoder = decoder;
|
||||
|
||||
mLastStartTimestamp = 0;
|
||||
mLastEndTimestamp = UnspecifiedNaN<double>();
|
||||
mHasInit = true;
|
||||
|
||||
return QueueInitializeDecoder(decoder);
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::QueueInitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
|
||||
{
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<SourceBufferDecoder>>(this,
|
||||
&TrackBuffer::InitializeDecoder,
|
||||
aDecoder);
|
||||
aDecoder->SetTaskQueue(mTaskQueue);
|
||||
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
|
||||
MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::InitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
|
||||
{
|
||||
// ReadMetadata may block the thread waiting on data, so it must not be
|
||||
// called with the monitor held.
|
||||
mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
|
||||
|
||||
MediaDecoderReader* reader = aDecoder->GetReader();
|
||||
MSE_DEBUG("TrackBuffer(%p): Initializing subdecoder %p reader %p",
|
||||
this, aDecoder.get(), reader);
|
||||
|
||||
MediaInfo mi;
|
||||
nsAutoPtr<MetadataTags> tags; // TODO: Handle metadata.
|
||||
nsresult rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
|
||||
reader->SetIdle();
|
||||
if (NS_FAILED(rv) || (!mi.HasVideo() && !mi.HasAudio())) {
|
||||
// XXX: Need to signal error back to owning SourceBuffer.
|
||||
MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
|
||||
this, reader, rv, mi.HasAudio(), mi.HasVideo());
|
||||
aDecoder->SetTaskQueue(nullptr);
|
||||
NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mi.HasVideo()) {
|
||||
MSE_DEBUG("TrackBuffer(%p): Reader %p video resolution=%dx%d",
|
||||
this, reader, mi.mVideo.mDisplay.width, mi.mVideo.mDisplay.height);
|
||||
}
|
||||
if (mi.HasAudio()) {
|
||||
MSE_DEBUG("TrackBuffer(%p): Reader %p audio sampleRate=%d channels=%d",
|
||||
this, reader, mi.mAudio.mRate, mi.mAudio.mChannels);
|
||||
}
|
||||
|
||||
MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader);
|
||||
RegisterDecoder(aDecoder);
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
aDecoder->SetTaskQueue(nullptr);
|
||||
const MediaInfo& info = aDecoder->GetReader()->GetMediaInfo();
|
||||
// Initialize the track info since this is the first decoder.
|
||||
if (mDecoders.IsEmpty()) {
|
||||
mHasAudio = info.HasAudio();
|
||||
mHasVideo = info.HasVideo();
|
||||
mParentDecoder->OnTrackBufferConfigured(this, info);
|
||||
} else if ((info.HasAudio() && !mHasAudio) || (info.HasVideo() && !mHasVideo)) {
|
||||
MSE_DEBUG("TrackBuffer(%p)::RegisterDecoder with mismatched audio/video tracks", this);
|
||||
}
|
||||
mDecoders.AppendElement(aDecoder);
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::DiscardDecoder()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
if (mCurrentDecoder) {
|
||||
mCurrentDecoder->GetResource()->Ended();
|
||||
}
|
||||
mCurrentDecoder = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::Detach()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mCurrentDecoder) {
|
||||
DiscardDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::HasInitSegment()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
return mHasInit;
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::IsReady()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT((mHasAudio || mHasVideo) || mDecoders.IsEmpty());
|
||||
return HasInitSegment() && (mHasAudio || mHasVideo);
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::LastTimestamp(double& aStart, double& aEnd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aStart = mLastStartTimestamp;
|
||||
aEnd = mLastEndTimestamp;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::SetLastStartTimestamp(double aStart)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mLastStartTimestamp = aStart;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::SetLastEndTimestamp(double aEnd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mLastEndTimestamp = aEnd;
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::ContainsTime(double aTime)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
|
||||
mDecoders[i]->GetBuffered(r);
|
||||
if (r->Find(aTime) != dom::TimeRanges::NoIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::BreakCycles()
|
||||
{
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->BreakCycles();
|
||||
}
|
||||
mDecoders.Clear();
|
||||
mParentDecoder = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::ResetDecode()
|
||||
{
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->ResetDecode();
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>&
|
||||
TrackBuffer::Decoders()
|
||||
{
|
||||
// XXX assert OnDecodeThread
|
||||
return mDecoders;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
131
content/media/mediasource/TrackBuffer.h
Normal file
131
content/media/mediasource/TrackBuffer.h
Normal file
@ -0,0 +1,131 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 MOZILLA_TRACKBUFFER_H_
|
||||
#define MOZILLA_TRACKBUFFER_H_
|
||||
|
||||
#include "SourceBufferDecoder.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nscore.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaSourceDecoder;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class TimeRanges;
|
||||
|
||||
} // namespace dom
|
||||
|
||||
class TrackBuffer MOZ_FINAL {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffer);
|
||||
|
||||
TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
// Append data to the current decoder. Also responsible for calling
|
||||
// NotifyDataArrived on the decoder to keep buffered range computation up
|
||||
// to date. Returns false if the append failed.
|
||||
bool AppendData(const uint8_t* aData, uint32_t aLength);
|
||||
bool EvictData(uint32_t aThreshold);
|
||||
void EvictBefore(double aTime);
|
||||
|
||||
// Returns the highest end time of all of the buffered ranges in the
|
||||
// decoders managed by this TrackBuffer, and returns the union of the
|
||||
// decoders buffered ranges in aRanges.
|
||||
double Buffered(dom::TimeRanges* aRanges);
|
||||
|
||||
// Create a new decoder, set mCurrentDecoder to the new decoder, and queue
|
||||
// the decoder for initialization. The decoder is not considered
|
||||
// initialized until it is added to mDecoders.
|
||||
bool NewDecoder();
|
||||
|
||||
// Mark the current decoder's resource as ended, clear mCurrentDecoder and
|
||||
// reset mLast{Start,End}Timestamp.
|
||||
void DiscardDecoder();
|
||||
|
||||
void Detach();
|
||||
|
||||
// Returns true if an init segment has been appended.
|
||||
bool HasInitSegment();
|
||||
|
||||
// Returns true iff HasInitSegment() and the decoder using that init
|
||||
// segment has successfully initialized by setting mHas{Audio,Video}..
|
||||
bool IsReady();
|
||||
|
||||
// Query and update mLast{Start,End}Timestamp.
|
||||
void LastTimestamp(double& aStart, double& aEnd);
|
||||
void SetLastStartTimestamp(double aStart);
|
||||
void SetLastEndTimestamp(double aEnd);
|
||||
|
||||
// Returns true if any of the decoders managed by this track buffer
|
||||
// contain aTime in their buffered ranges.
|
||||
bool ContainsTime(double aTime);
|
||||
|
||||
void BreakCycles();
|
||||
|
||||
// Call ResetDecode() on each decoder in mDecoders.
|
||||
void ResetDecode();
|
||||
|
||||
// Returns a reference to mDecoders, used by MediaSourceReader to select
|
||||
// decoders.
|
||||
// TODO: Refactor to a clenaer interface between TrackBuffer and MediaSourceReader.
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& Decoders();
|
||||
|
||||
private:
|
||||
~TrackBuffer();
|
||||
|
||||
// Queue execution of InitializeDecoder on mTaskQueue.
|
||||
bool QueueInitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
|
||||
|
||||
// Runs decoder initialization including calling ReadMetadata. Runs as an
|
||||
// event on the decode thread pool.
|
||||
void InitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
|
||||
|
||||
// Adds a successfully initialized decoder to mDecoders and (if it's the
|
||||
// first decoder initialized), initializes mHasAudio/mHasVideo. Called
|
||||
// from the decode thread pool.
|
||||
void RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
|
||||
|
||||
// A task queue using the shared media thread pool. Used exclusively to
|
||||
// initialize (i.e. call ReadMetadata on) decoders as they are created via
|
||||
// NewDecoder.
|
||||
RefPtr<MediaTaskQueue> mTaskQueue;
|
||||
|
||||
// All of the initialized decoders managed by this TrackBuffer. Access
|
||||
// protected by mParentDecoder's monitor.
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
|
||||
|
||||
// The decoder that the owning SourceBuffer is currently appending data to.
|
||||
nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
|
||||
|
||||
nsRefPtr<MediaSourceDecoder> mParentDecoder;
|
||||
const nsCString mType;
|
||||
|
||||
// The last start and end timestamps added to the TrackBuffer via
|
||||
// AppendData. Accessed on the main thread only.
|
||||
double mLastStartTimestamp;
|
||||
double mLastEndTimestamp;
|
||||
|
||||
// Set when the initialization segment is first seen and cached (implied
|
||||
// by new decoder creation). Protected by mParentDecoder's monitor.
|
||||
bool mHasInit;
|
||||
|
||||
// Set when the first decoder used by this TrackBuffer is initialized.
|
||||
// Protected by mParentDecoder's monitor.
|
||||
bool mHasAudio;
|
||||
bool mHasVideo;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* MOZILLA_TRACKBUFFER_H_ */
|
@ -25,6 +25,7 @@ UNIFIED_SOURCES += [
|
||||
'SourceBufferDecoder.cpp',
|
||||
'SourceBufferList.cpp',
|
||||
'SourceBufferResource.cpp',
|
||||
'TrackBuffer.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -4,3 +4,9 @@ support-files = seek.webm seek.webm^headers^
|
||||
|
||||
[test_MediaSource.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
|
||||
[test_SplitAppend.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
|
||||
[test_SplitAppendDelay.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
|
83
content/media/mediasource/test/test_SplitAppend.html
Normal file
83
content/media/mediasource/test/test_SplitAppend.html
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test whether we can create an MediaSource interface</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
ok(!window.MediaSource, "MediaSource should be hidden behind a pref");
|
||||
var accessThrows = false;
|
||||
try {
|
||||
new MediaSource();
|
||||
} catch (e) {
|
||||
accessThrows = true;
|
||||
}
|
||||
ok(accessThrows, "MediaSource should be hidden behind a pref");
|
||||
SpecialPowers.pushPrefEnv({"set": [[ "media.mediasource.enabled", true ]]},
|
||||
function () {
|
||||
SpecialPowers.setBoolPref("media.mediasource.enabled", true);
|
||||
var ms = new MediaSource();
|
||||
ok(ms, "Create a MediaSource object");
|
||||
ok(ms instanceof EventTarget, "MediaSource must be an EventTarget");
|
||||
is(ms.readyState, "closed", "New MediaSource must be in closed state");
|
||||
// Force wrapper creation, tests for leaks.
|
||||
ms.foo = null;
|
||||
var o = URL.createObjectURL(ms);
|
||||
ok(o, "Create an objectURL from the MediaSource");
|
||||
var v = document.createElement("video");
|
||||
v.preload = "auto";
|
||||
document.body.appendChild(v);
|
||||
v.src = o;
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
ok(true, "Receive a sourceopen event");
|
||||
is(ms.readyState, "open", "MediaSource must be in open state after sourceopen");
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
ok(sb, "Create a SourceBuffer");
|
||||
is(ms.sourceBuffers.length, 1, "MediaSource.sourceBuffers is expected length");
|
||||
is(ms.sourceBuffers[0], sb, "SourceBuffer in list matches our SourceBuffer");
|
||||
fetch("seek.webm", function (blob) {
|
||||
var r = new FileReader();
|
||||
r.addEventListener("load", function (e) {
|
||||
sb.appendBuffer(new Uint8Array(e.target.result, 0, 318));
|
||||
sb.appendBuffer(new Uint8Array(e.target.result, 318));
|
||||
ms.endOfStream();
|
||||
v.play();
|
||||
});
|
||||
r.readAsArrayBuffer(blob);
|
||||
});
|
||||
});
|
||||
ms.addEventListener("sourceended", function () {
|
||||
ok(true, "Receive a sourceended event");
|
||||
is(ms.readyState, "ended", "MediaSource must be in ended state after sourceended");
|
||||
});
|
||||
v.addEventListener("ended", function () {
|
||||
is(v.duration, 4, "Video has correct duration");
|
||||
v.parentNode.removeChild(v);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function fetch(src, cb) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", src, true);
|
||||
xhr.responseType = "blob";
|
||||
xhr.addEventListener("load", function (e) {
|
||||
if (xhr.status != 200) {
|
||||
return false;
|
||||
}
|
||||
cb(xhr.response);
|
||||
});
|
||||
xhr.send();
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
85
content/media/mediasource/test/test_SplitAppendDelay.html
Normal file
85
content/media/mediasource/test/test_SplitAppendDelay.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test whether we can create an MediaSource interface</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
ok(!window.MediaSource, "MediaSource should be hidden behind a pref");
|
||||
var accessThrows = false;
|
||||
try {
|
||||
new MediaSource();
|
||||
} catch (e) {
|
||||
accessThrows = true;
|
||||
}
|
||||
ok(accessThrows, "MediaSource should be hidden behind a pref");
|
||||
SpecialPowers.pushPrefEnv({"set": [[ "media.mediasource.enabled", true ]]},
|
||||
function () {
|
||||
SpecialPowers.setBoolPref("media.mediasource.enabled", true);
|
||||
var ms = new MediaSource();
|
||||
ok(ms, "Create a MediaSource object");
|
||||
ok(ms instanceof EventTarget, "MediaSource must be an EventTarget");
|
||||
is(ms.readyState, "closed", "New MediaSource must be in closed state");
|
||||
// Force wrapper creation, tests for leaks.
|
||||
ms.foo = null;
|
||||
var o = URL.createObjectURL(ms);
|
||||
ok(o, "Create an objectURL from the MediaSource");
|
||||
var v = document.createElement("video");
|
||||
v.preload = "auto";
|
||||
document.body.appendChild(v);
|
||||
v.src = o;
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
ok(true, "Receive a sourceopen event");
|
||||
is(ms.readyState, "open", "MediaSource must be in open state after sourceopen");
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
ok(sb, "Create a SourceBuffer");
|
||||
is(ms.sourceBuffers.length, 1, "MediaSource.sourceBuffers is expected length");
|
||||
is(ms.sourceBuffers[0], sb, "SourceBuffer in list matches our SourceBuffer");
|
||||
fetch("seek.webm", function (blob) {
|
||||
var r = new FileReader();
|
||||
r.addEventListener("load", function (e) {
|
||||
sb.appendBuffer(new Uint8Array(e.target.result, 0, 318));
|
||||
window.setTimeout(function () {
|
||||
sb.appendBuffer(new Uint8Array(e.target.result, 318));
|
||||
ms.endOfStream();
|
||||
}, 1000);
|
||||
v.play();
|
||||
});
|
||||
r.readAsArrayBuffer(blob);
|
||||
});
|
||||
});
|
||||
ms.addEventListener("sourceended", function () {
|
||||
ok(true, "Receive a sourceended event");
|
||||
is(ms.readyState, "ended", "MediaSource must be in ended state after sourceended");
|
||||
});
|
||||
v.addEventListener("ended", function () {
|
||||
is(v.duration, 4, "Video has correct duration");
|
||||
v.parentNode.removeChild(v);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function fetch(src, cb) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", src, true);
|
||||
xhr.responseType = "blob";
|
||||
xhr.addEventListener("load", function (e) {
|
||||
if (xhr.status != 200) {
|
||||
return false;
|
||||
}
|
||||
cb(xhr.response);
|
||||
});
|
||||
xhr.send();
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -4,11 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
CPP_UNIT_TESTS += [
|
||||
CppUnitTests([
|
||||
'TestAudioEventTimeline',
|
||||
]
|
||||
|
||||
SOURCES += sorted('%s.cpp' % t for t in CPP_UNIT_TESTS)
|
||||
])
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
|
@ -2004,7 +2004,7 @@ XULDocument::PrepareToLoad(nsISupports* aContainer,
|
||||
// Get the document's principal
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelPrincipal(aChannel, getter_AddRefs(principal));
|
||||
GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
|
||||
return PrepareToLoadPrototype(mDocumentURI, aCommand, principal, aResult);
|
||||
}
|
||||
|
||||
@ -4516,7 +4516,7 @@ XULDocument::ParserObserver::OnStartRequest(nsIRequest *request,
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
if (channel && secMan) {
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
secMan->GetChannelPrincipal(channel, getter_AddRefs(principal));
|
||||
secMan->GetChannelResultPrincipal(channel, getter_AddRefs(principal));
|
||||
|
||||
// Failure there is ok -- it'll just set a (safe) null principal
|
||||
mPrototype->SetDocumentPrincipal(principal);
|
||||
|
@ -6580,7 +6580,7 @@ NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = secMan->GetChannelPrincipal(aChannel, getter_AddRefs(principal));
|
||||
rv = secMan->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SetupReferrerFromChannel(aChannel);
|
||||
|
@ -4,11 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
CPP_UNIT_TESTS += [
|
||||
CppUnitTests([
|
||||
'TestAudioChannelService',
|
||||
]
|
||||
|
||||
SOURCES += sorted('%s.cpp' % t for t in CPP_UNIT_TESTS)
|
||||
])
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
|
@ -12,7 +12,7 @@ DEFINES.update({
|
||||
# Do NOT export this library. We don't actually want our test code
|
||||
# being added to libxul or anything.
|
||||
|
||||
LIBRARY_NAME = 'dombindings_test_s'
|
||||
Library('dombindings_test_s')
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'TestInterfaceJS.js',
|
||||
|
@ -4,11 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
CPP_UNIT_TESTS += [
|
||||
CppUnitTests([
|
||||
'TestWebGLElementArrayCache',
|
||||
]
|
||||
|
||||
SOURCES += sorted('%s.cpp' % t for t in CPP_UNIT_TESTS)
|
||||
])
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
|
49
dom/icc/Assertions.cpp
Normal file
49
dom/icc/Assertions.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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 "mozilla/dom/MozIccBinding.h"
|
||||
#include "nsIIccProvider.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#define ASSERT_ICC_CARD_STATE_EQUALITY(webidlState, xpidlState) \
|
||||
static_assert(static_cast<uint32_t>(IccCardState::webidlState) == nsIIccProvider::xpidlState, \
|
||||
"IccCardState::" #webidlState " should equal to nsIIccProvider::" #xpidlState)
|
||||
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Unknown, CARD_STATE_UNKNOWN);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Ready, CARD_STATE_READY);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(PinRequired, CARD_STATE_PIN_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(PukRequired, CARD_STATE_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(PermanentBlocked, CARD_STATE_PERMANENT_BLOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(PersonalizationInProgress, CARD_STATE_PERSONALIZATION_IN_PROGRESS);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(PersonalizationReady, CARD_STATE_PERSONALIZATION_READY);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkLocked, CARD_STATE_NETWORK_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkSubsetLocked, CARD_STATE_NETWORK_SUBSET_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(CorporateLocked, CARD_STATE_CORPORATE_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(ServiceProviderLocked, CARD_STATE_SERVICE_PROVIDER_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(SimPersonalizationLocked, CARD_STATE_SIM_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkPukRequired, CARD_STATE_NETWORK_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(NetworkSubsetPukRequired, CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(CorporatePukRequired, CARD_STATE_CORPORATE_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(ServiceProviderPukRequired, CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(SimPersonalizationPukRequired, CARD_STATE_SIM_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Network1Locked, CARD_STATE_NETWORK1_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Network2Locked, CARD_STATE_NETWORK2_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(HrpdNetworkLocked, CARD_STATE_HRPD_NETWORK_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(RuimCorporateLocked, CARD_STATE_RUIM_CORPORATE_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(RuimServiceProviderLocked, CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(RuimPersonalizationLocked, CARD_STATE_RUIM_LOCKED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Network1PukRequired, CARD_STATE_NETWORK1_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Network2PukRequired, CARD_STATE_NETWORK2_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(HrpdNetworkPukRequired, CARD_STATE_HRPD_NETWORK_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(RuimCorporatePukRequired, CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(RuimServiceProviderPukRequired, CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(RuimPersonalizationPukRequired, CARD_STATE_RUIM_PUK_REQUIRED);
|
||||
ASSERT_ICC_CARD_STATE_EQUALITY(Illegal, CARD_STATE_ILLEGAL);
|
||||
|
||||
#undef ASSERT_ICC_CARD_STATE_EQUALITY
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -100,19 +100,20 @@ Icc::GetIccInfo() const
|
||||
return iccInfo.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Icc::GetCardState(nsString& aCardState) const
|
||||
Nullable<IccCardState>
|
||||
Icc::GetCardState() const
|
||||
{
|
||||
aCardState.SetIsVoid(true);
|
||||
Nullable<IccCardState> result;
|
||||
|
||||
if (!mProvider) {
|
||||
return;
|
||||
uint32_t cardState = nsIIccProvider::CARD_STATE_UNDETECTED;
|
||||
if (mProvider &&
|
||||
NS_SUCCEEDED(mProvider->GetCardState(mClientId, &cardState)) &&
|
||||
cardState != nsIIccProvider::CARD_STATE_UNDETECTED) {
|
||||
MOZ_ASSERT(cardState < static_cast<uint32_t>(IccCardState::EndGuard_));
|
||||
result.SetValue(static_cast<IccCardState>(cardState));
|
||||
}
|
||||
|
||||
nsresult rv = mProvider->GetCardState(mClientId, aCardState);
|
||||
if (NS_FAILED(rv)) {
|
||||
aCardState.SetIsVoid(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef mozilla_dom_Icc_h
|
||||
#define mozilla_dom_Icc_h
|
||||
|
||||
#include "mozilla/dom/MozIccBinding.h" // For IccCardState
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "nsIIccProvider.h"
|
||||
|
||||
@ -49,8 +50,8 @@ public:
|
||||
already_AddRefed<nsIDOMMozIccInfo>
|
||||
GetIccInfo() const;
|
||||
|
||||
void
|
||||
GetCardState(nsString& aCardState) const;
|
||||
Nullable<IccCardState>
|
||||
GetCardState() const;
|
||||
|
||||
void
|
||||
SendStkResponse(const JSContext* aCx, JS::Handle<JS::Value> aCommand,
|
||||
|
@ -20,9 +20,43 @@ interface nsIIccListener : nsISupports
|
||||
/**
|
||||
* XPCOM component (in the content process) that provides the ICC information.
|
||||
*/
|
||||
[scriptable, uuid(7c67ab92-52a3-4e11-995c-c0ad2f66c4cb)]
|
||||
[scriptable, uuid(aa404b6e-fcfa-4bd2-bc46-e4e94b603ca7)]
|
||||
interface nsIIccProvider : nsISupports
|
||||
{
|
||||
// MUST match enum IccCardState in MozIcc.webidl!
|
||||
const unsigned long CARD_STATE_UNKNOWN = 0;
|
||||
const unsigned long CARD_STATE_READY = 1;
|
||||
const unsigned long CARD_STATE_PIN_REQUIRED = 2;
|
||||
const unsigned long CARD_STATE_PUK_REQUIRED = 3;
|
||||
const unsigned long CARD_STATE_PERMANENT_BLOCKED = 4;
|
||||
const unsigned long CARD_STATE_PERSONALIZATION_IN_PROGRESS = 5;
|
||||
const unsigned long CARD_STATE_PERSONALIZATION_READY = 6;
|
||||
const unsigned long CARD_STATE_NETWORK_LOCKED = 7;
|
||||
const unsigned long CARD_STATE_NETWORK_SUBSET_LOCKED = 8;
|
||||
const unsigned long CARD_STATE_CORPORATE_LOCKED = 9;
|
||||
const unsigned long CARD_STATE_SERVICE_PROVIDER_LOCKED = 10;
|
||||
const unsigned long CARD_STATE_SIM_LOCKED = 11;
|
||||
const unsigned long CARD_STATE_NETWORK_PUK_REQUIRED = 12;
|
||||
const unsigned long CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED = 13;
|
||||
const unsigned long CARD_STATE_CORPORATE_PUK_REQUIRED = 14;
|
||||
const unsigned long CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED = 15;
|
||||
const unsigned long CARD_STATE_SIM_PUK_REQUIRED = 16;
|
||||
const unsigned long CARD_STATE_NETWORK1_LOCKED = 17;
|
||||
const unsigned long CARD_STATE_NETWORK2_LOCKED = 18;
|
||||
const unsigned long CARD_STATE_HRPD_NETWORK_LOCKED = 19;
|
||||
const unsigned long CARD_STATE_RUIM_CORPORATE_LOCKED = 20;
|
||||
const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED = 21;
|
||||
const unsigned long CARD_STATE_RUIM_LOCKED = 22;
|
||||
const unsigned long CARD_STATE_NETWORK1_PUK_REQUIRED = 23;
|
||||
const unsigned long CARD_STATE_NETWORK2_PUK_REQUIRED = 24;
|
||||
const unsigned long CARD_STATE_HRPD_NETWORK_PUK_REQUIRED = 25;
|
||||
const unsigned long CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED = 26;
|
||||
const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27;
|
||||
const unsigned long CARD_STATE_RUIM_PUK_REQUIRED = 28;
|
||||
const unsigned long CARD_STATE_ILLEGAL = 29;
|
||||
|
||||
const unsigned long CARD_STATE_UNDETECTED = 4294967295; // UINT32_MAX
|
||||
|
||||
/**
|
||||
* Called when a content process registers receiving unsolicited messages from
|
||||
* RadioInterfaceLayer in the chrome process. Only a content process that has
|
||||
@ -39,7 +73,7 @@ interface nsIIccProvider : nsISupports
|
||||
/**
|
||||
* Card State
|
||||
*/
|
||||
DOMString getCardState(in unsigned long clientId);
|
||||
unsigned long getCardState(in unsigned long clientId);
|
||||
|
||||
/**
|
||||
* STK interfaces.
|
||||
|
@ -11,6 +11,10 @@ EXPORTS.mozilla.dom += [
|
||||
'IccManager.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'Assertions.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'Icc.cpp',
|
||||
'IccListener.cpp',
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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 "base/linked_ptr.h"
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
|
@ -9,10 +9,9 @@ SOURCES += [
|
||||
'gmp-fake.cpp'
|
||||
]
|
||||
|
||||
LIBRARY_NAME = "fake"
|
||||
SharedLibrary("fake")
|
||||
|
||||
USE_STATIC_LIBS = True
|
||||
FORCE_SHARED_LIB = True
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
# Don't use STL wrappers; this isn't Gecko code
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
@ -8,11 +8,94 @@
|
||||
#include "nsIDOMDOMRequest.h"
|
||||
#include "nsIDOMMozSmsMessage.h"
|
||||
#include "nsIMobileMessageCallback.h"
|
||||
#include "DOMCursor.h"
|
||||
#include "nsServiceManagerUtils.h" // for do_GetService
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(MobileMessageCursor, DOMCursor,
|
||||
mPendingResults)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MobileMessageCursor)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMCursor)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MobileMessageCursor, DOMCursor)
|
||||
NS_IMPL_RELEASE_INHERITED(MobileMessageCursor, DOMCursor)
|
||||
|
||||
MobileMessageCursor::MobileMessageCursor(nsPIDOMWindow* aWindow,
|
||||
nsICursorContinueCallback* aCallback)
|
||||
: DOMCursor(aWindow, aCallback)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageCursor::Continue()
|
||||
{
|
||||
// We have originally:
|
||||
//
|
||||
// DOMCursor::Continue()
|
||||
// +-> DOMCursor::Continue(ErrorResult& aRv)
|
||||
//
|
||||
// Now it becomes:
|
||||
//
|
||||
// MobileMessageCursor::Continue()
|
||||
// +-> DOMCursor::Continue()
|
||||
// +-> MobileMessageCursor::Continue(ErrorResult& aRv)
|
||||
// o-> DOMCursor::Continue(ErrorResult& aRv)
|
||||
return DOMCursor::Continue();
|
||||
}
|
||||
|
||||
void
|
||||
MobileMessageCursor::Continue(ErrorResult& aRv)
|
||||
{
|
||||
// An ordinary DOMCursor works in following flow:
|
||||
//
|
||||
// DOMCursor::Continue()
|
||||
// +-> DOMCursor::Reset()
|
||||
// +-> nsICursorContinueCallback::HandleContinue()
|
||||
// +-> nsIMobileMessageCursorCallback::NotifyCursorResult()
|
||||
// +-> DOMCursor::FireSuccess()
|
||||
//
|
||||
// With no pending result, we call to |DOMCursor::Continue()| as usual.
|
||||
if (!mPendingResults.Length()) {
|
||||
DOMCursor::Continue(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, reset current result and fire a success event with the last
|
||||
// pending one.
|
||||
Reset();
|
||||
|
||||
nsresult rv = FireSuccessWithNextPendingResult();
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
MobileMessageCursor::FireSuccessWithNextPendingResult()
|
||||
{
|
||||
// We're going to pop the last element from mPendingResults, so it must not
|
||||
// be empty.
|
||||
MOZ_ASSERT(mPendingResults.Length());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(cx, mPendingResults.LastElement(), &val);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mPendingResults.RemoveElementAt(mPendingResults.Length() - 1);
|
||||
|
||||
FireSuccess(val);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace mobilemessage {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(MobileMessageCursorCallback, mDOMCursor)
|
||||
@ -55,21 +138,29 @@ MobileMessageCursorCallback::NotifyCursorError(int32_t aError)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageCursorCallback::NotifyCursorResult(nsISupports* aResult)
|
||||
MobileMessageCursorCallback::NotifyCursorResult(nsISupports** aResults,
|
||||
uint32_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(mDOMCursor);
|
||||
// We should only be notified with valid results. Or, either
|
||||
// |NotifyCursorDone()| or |NotifyCursorError()| should be called instead.
|
||||
MOZ_ASSERT(aResults && *aResults && aSize);
|
||||
// There shouldn't be unexpected notifications before |Continue()| is called.
|
||||
nsTArray<nsCOMPtr<nsISupports>>& pending = mDOMCursor->mPendingResults;
|
||||
MOZ_ASSERT(pending.Length() == 0);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mDOMCursor->GetOwner()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
// Push pending results in reversed order.
|
||||
pending.SetCapacity(pending.Length() + aSize);
|
||||
while (aSize) {
|
||||
--aSize;
|
||||
pending.AppendElement(aResults[aSize]);
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JS::Value> wrappedResult(cx);
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, aResult, &wrappedResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = mDOMCursor->FireSuccessWithNextPendingResult();
|
||||
if (NS_FAILED(rv)) {
|
||||
NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
mDOMCursor->FireSuccess(wrappedResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
#ifndef mozilla_dom_mobilemessage_MobileMessageCursorCallback_h
|
||||
#define mozilla_dom_mobilemessage_MobileMessageCursorCallback_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/DOMCursor.h"
|
||||
#include "nsIMobileMessageCursorCallback.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@ -16,12 +18,46 @@ class nsICursorContinueCallback;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DOMCursor;
|
||||
class MobileMessageManager;
|
||||
|
||||
namespace mobilemessage {
|
||||
class MobileMessageCursorCallback;
|
||||
} // namespace mobilemessage
|
||||
|
||||
class MobileMessageCursorCallback : public nsIMobileMessageCursorCallback
|
||||
class MobileMessageCursor MOZ_FINAL : public DOMCursor
|
||||
{
|
||||
friend class mobilemessage::MobileMessageCursorCallback;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MobileMessageCursor, DOMCursor)
|
||||
|
||||
MobileMessageCursor(nsPIDOMWindow* aWindow,
|
||||
nsICursorContinueCallback* aCallback);
|
||||
|
||||
// Override XPIDL continue function to suppress -Werror,-Woverloaded-virtual.
|
||||
NS_IMETHOD
|
||||
Continue(void) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
Continue(ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
|
||||
~MobileMessageCursor() {}
|
||||
|
||||
private:
|
||||
// List of read-ahead results in reversed order.
|
||||
nsTArray<nsCOMPtr<nsISupports>> mPendingResults;
|
||||
|
||||
nsresult
|
||||
FireSuccessWithNextPendingResult();
|
||||
};
|
||||
|
||||
namespace mobilemessage {
|
||||
|
||||
class MobileMessageCursorCallback MOZ_FINAL : public nsIMobileMessageCursorCallback
|
||||
{
|
||||
friend class mozilla::dom::MobileMessageManager;
|
||||
|
||||
@ -37,12 +73,13 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~MobileMessageCursorCallback()
|
||||
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
|
||||
~MobileMessageCursorCallback()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MobileMessageCursorCallback);
|
||||
}
|
||||
|
||||
nsRefPtr<DOMCursor> mDOMCursor;
|
||||
nsRefPtr<MobileMessageCursor> mDOMCursor;
|
||||
};
|
||||
|
||||
} // namespace mobilemessage
|
||||
|
@ -439,9 +439,10 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cursorCallback->mDOMCursor = new DOMCursor(GetOwner(), continueCallback);
|
||||
cursorCallback->mDOMCursor =
|
||||
new MobileMessageCursor(GetOwner(), continueCallback);
|
||||
|
||||
nsRefPtr<DOMCursor> cursor = cursorCallback->mDOMCursor;
|
||||
nsRefPtr<DOMCursor> cursor(cursorCallback->mDOMCursor);
|
||||
return cursor.forget();
|
||||
}
|
||||
|
||||
@ -491,9 +492,10 @@ MobileMessageManager::GetThreads(ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cursorCallback->mDOMCursor = new DOMCursor(GetOwner(), continueCallback);
|
||||
cursorCallback->mDOMCursor =
|
||||
new MobileMessageCursor(GetOwner(), continueCallback);
|
||||
|
||||
nsRefPtr<DOMCursor> cursor = cursorCallback->mDOMCursor;
|
||||
nsRefPtr<DOMCursor> cursor(cursorCallback->mDOMCursor);
|
||||
return cursor.forget();
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,9 @@ const COLLECT_ID_END = 0;
|
||||
const COLLECT_ID_ERROR = -1;
|
||||
const COLLECT_TIMESTAMP_UNUSED = 0;
|
||||
|
||||
// Default value for integer preference "dom.sms.maxReadAheadEntries".
|
||||
const DEFAULT_READ_AHEAD_ENTRIES = 7;
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
|
||||
"@mozilla.org/mobilemessage/mobilemessageservice;1",
|
||||
"nsIMobileMessageService");
|
||||
@ -3143,7 +3146,7 @@ MobileMessageDB.prototype = {
|
||||
|
||||
let self = this;
|
||||
self.newTxn(READ_ONLY, function(error, txn, stores) {
|
||||
let collector = cursor.collector;
|
||||
let collector = cursor.collector.idCollector;
|
||||
let collect = collector.collect.bind(collector);
|
||||
FilterSearcherHelper.transact(self, txn, error, filter, aReverse, collect);
|
||||
}, [MESSAGE_STORE_NAME, PARTICIPANT_STORE_NAME]);
|
||||
@ -3252,7 +3255,7 @@ MobileMessageDB.prototype = {
|
||||
|
||||
let cursor = new GetThreadsCursor(this, callback);
|
||||
this.newTxn(READ_ONLY, function(error, txn, threadStore) {
|
||||
let collector = cursor.collector;
|
||||
let collector = cursor.collector.idCollector;
|
||||
if (error) {
|
||||
collector.collect(null, COLLECT_ID_ERROR, COLLECT_TIMESTAMP_UNUSED);
|
||||
return;
|
||||
@ -3489,11 +3492,306 @@ let FilterSearcherHelper = {
|
||||
}
|
||||
};
|
||||
|
||||
function ResultsCollector() {
|
||||
/**
|
||||
* Collector class for read-ahead result objects. Mmdb may now try to fetch
|
||||
* message/thread records before it's requested explicitly.
|
||||
*
|
||||
* The read ahead behavior can be controlled by an integer mozSettings entry
|
||||
* "ril.sms.maxReadAheadEntries" as well as an integer holding preference
|
||||
* "dom.sms.maxReadAheadEntries". The meanings are:
|
||||
*
|
||||
* positive: finite read-ahead entries,
|
||||
* 0: don't read ahead unless explicitly requested, (default)
|
||||
* negative: read ahead all IDs if possible.
|
||||
*
|
||||
* The order of ID filtering objects are now:
|
||||
*
|
||||
* [UnionResultsCollector]
|
||||
* +-> [IntersectionResultsCollector]
|
||||
* +-> IDsCollector
|
||||
* +-> ResultsCollector
|
||||
*
|
||||
* ResultsCollector has basically similar behaviour with IDsCollector. When
|
||||
* RC::squeeze() is called, either RC::drip() is called instantly if we have
|
||||
* already fetched results available, or the request is kept and IC::squeeze()
|
||||
* is called.
|
||||
*
|
||||
* When RC::collect is called by IC::drip, it proceeds to fetch the
|
||||
* corresponding record given that collected ID is neither an error nor an end
|
||||
* mark. After the message/thread record being fetched, ResultsCollector::drip
|
||||
* is called if we have pending request. Anyway, RC::maybeSqueezeIdCollector is
|
||||
* called to determine whether we need to call IC::squeeze again.
|
||||
*
|
||||
* RC::squeeze is called when nsICursorContinueCallback::handleContinue() is
|
||||
* called. ResultsCollector::drip will call to
|
||||
* nsIMobileMessageCursorCallback::notifyFoo.
|
||||
*
|
||||
* In summary, the major call paths are:
|
||||
*
|
||||
* RC::squeeze
|
||||
* o-> RC::drip
|
||||
* +-> RC::notifyCallback
|
||||
* +-> nsIMobileMessageCursorCallback::notifyFoo
|
||||
* +-> RC::maybeSqueezeIdCollector
|
||||
* o-> IC::squeeze
|
||||
* o-> IC::drip
|
||||
* +-> RC::collect
|
||||
* o-> RC::readAhead
|
||||
* +-> RC::notifyResult
|
||||
* o-> RC::drip ...
|
||||
* +-> RC::maybeSqueezeIdCollector ...
|
||||
* o-> RC::notifyResult ...
|
||||
*/
|
||||
function ResultsCollector(readAheadFunc) {
|
||||
this.idCollector = new IDsCollector();
|
||||
this.results = [];
|
||||
this.readAhead = readAheadFunc;
|
||||
|
||||
this.maxReadAhead = DEFAULT_READ_AHEAD_ENTRIES;
|
||||
try {
|
||||
// positive: finite read-ahead entries,
|
||||
// 0: don't read ahead unless explicitly requested,
|
||||
// negative: read ahead all IDs if possible.
|
||||
this.maxReadAhead =
|
||||
Services.prefs.getIntPref("dom.sms.maxReadAheadEntries");
|
||||
} catch (e) {}
|
||||
}
|
||||
ResultsCollector.prototype = {
|
||||
/**
|
||||
* Underlying ID collector object.
|
||||
*/
|
||||
idCollector: null,
|
||||
|
||||
/**
|
||||
* An array keeping fetched result objects. Replaced by a new empty array
|
||||
* every time when |this.drip| is called.
|
||||
*/
|
||||
results: null,
|
||||
|
||||
/**
|
||||
* A function that takes (<txn>, <id>, <collector>). It fetches the object
|
||||
* specified by <id> and notify <collector> with that by calling
|
||||
* |<collector>.notifyResult()|. If <txn> is null, this function should
|
||||
* create a new read-only transaction itself. The returned result object may
|
||||
* be null to indicate an error during the fetch process.
|
||||
*/
|
||||
readAhead: null,
|
||||
|
||||
/**
|
||||
* A boolean value inidicating a readAhead call is ongoing. Set before calling
|
||||
* |this.readAhead| and reset in |this.notifyResult|.
|
||||
*/
|
||||
readingAhead: false,
|
||||
|
||||
/**
|
||||
* A numeric value read from preference "dom.sms.maxReadAheadEntries".
|
||||
*/
|
||||
maxReadAhead: 0,
|
||||
|
||||
/**
|
||||
* An active IDBTransaction object to be reused.
|
||||
*/
|
||||
activeTxn: null,
|
||||
|
||||
/**
|
||||
* A nsIMobileMessageCursorCallback.
|
||||
*/
|
||||
requestWaiting: null,
|
||||
|
||||
/**
|
||||
* A boolean value indicating either a COLLECT_ID_END or COLLECT_ID_ERROR has
|
||||
* been received.
|
||||
*/
|
||||
done: false,
|
||||
|
||||
/**
|
||||
* When |this.done|, it's either COLLECT_ID_END or COLLECT_ID_ERROR.
|
||||
*/
|
||||
lastId: null,
|
||||
|
||||
/**
|
||||
* Receive collected id from IDsCollector and fetch the correspond result
|
||||
* object if necessary.
|
||||
*
|
||||
* @param txn
|
||||
* An IDBTransaction object. Null if there is no active transaction in
|
||||
* IDsCollector. That is, the ID collecting transaction is completed.
|
||||
* @param id
|
||||
* A positive numeric id, COLLECT_ID_END(0), or COLLECT_ID_ERROR(-1).
|
||||
*/
|
||||
collect: function(txn, id) {
|
||||
if (this.done) {
|
||||
// If this callector has been terminated because of previous errors in
|
||||
// |this.readAhead|, ignore any further IDs from IDsCollector.
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) debug("ResultsCollector::collect ID = " + id);
|
||||
|
||||
// Reuse the active transaction cached if IDsCollector has no active
|
||||
// transaction.
|
||||
txn = txn || this.activeTxn;
|
||||
|
||||
if (id > 0) {
|
||||
this.readingAhead = true;
|
||||
this.readAhead(txn, id, this);
|
||||
} else {
|
||||
this.notifyResult(txn, id, null);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function for |this.readAhead|.
|
||||
*
|
||||
* This function pushes result object to |this.results| or updates
|
||||
* |this.done|, |this.lastId| if an end mark or an error is found. Since we
|
||||
* have already a valid result entry, check |this.requestWaiting| and deal
|
||||
* with it. At last, call to |this.maybeSqueezeIdCollector| to ask more id
|
||||
* again if necessary.
|
||||
*
|
||||
* @param txn
|
||||
* An IDBTransaction object. Null if caller has no active transaction.
|
||||
* @param id
|
||||
* A positive numeric id, COLLECT_ID_END(0), or COLLECT_ID_ERROR(-1).
|
||||
* @param result
|
||||
* An object associated with id. Null if |this.readAhead| failed.
|
||||
*/
|
||||
notifyResult: function(txn, id, result) {
|
||||
if (DEBUG) debug("notifyResult(txn, " + id + ", <result>)");
|
||||
|
||||
this.readingAhead = false;
|
||||
|
||||
if (id > 0) {
|
||||
if (result != null) {
|
||||
this.results.push(result);
|
||||
} else {
|
||||
id = COLLECT_ID_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (id <= 0) {
|
||||
this.lastId = id;
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
if (!this.requestWaiting) {
|
||||
if (DEBUG) debug("notifyResult: cursor.continue() not called yet");
|
||||
} else {
|
||||
let callback = this.requestWaiting;
|
||||
this.requestWaiting = null;
|
||||
|
||||
this.drip(callback);
|
||||
}
|
||||
|
||||
this.maybeSqueezeIdCollector(txn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Request for one more ID if necessary.
|
||||
*
|
||||
* @param txn
|
||||
* An IDBTransaction object. Null if caller has no active transaction.
|
||||
*/
|
||||
maybeSqueezeIdCollector: function(txn) {
|
||||
if (this.done || // Nothing to be read.
|
||||
this.readingAhead || // Already in progress.
|
||||
this.idCollector.requestWaiting) { // Already requested.
|
||||
return;
|
||||
}
|
||||
|
||||
let max = this.maxReadAhead;
|
||||
if (!max && this.requestWaiting) {
|
||||
// If |this.requestWaiting| is set, try to read ahead at least once.
|
||||
max = 1;
|
||||
}
|
||||
if (max >= 0 && this.results.length >= max) {
|
||||
// More-equal than <max> entries has been read. Stop.
|
||||
if (DEBUG) debug("maybeSqueezeIdCollector: max " + max + " entries read. Stop.");
|
||||
return;
|
||||
}
|
||||
|
||||
// A hack to pass current txn to |this.collect| when it's called directly by
|
||||
// |IDsCollector.squeeze|.
|
||||
this.activeTxn = txn;
|
||||
this.idCollector.squeeze(this.collect.bind(this));
|
||||
this.activeTxn = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Request to pass available results or wait.
|
||||
*
|
||||
* @param callback
|
||||
* A nsIMobileMessageCursorCallback.
|
||||
*/
|
||||
squeeze: function(callback) {
|
||||
if (this.requestWaiting) {
|
||||
throw new Error("Already waiting for another request!");
|
||||
}
|
||||
|
||||
if (this.results.length || this.done) {
|
||||
// If |this.results.length| is non-zero, we have already some results to
|
||||
// pass. Otherwise, if |this.done| evaluates to true, we have also a
|
||||
// confirmed result to pass.
|
||||
this.drip(callback);
|
||||
} else {
|
||||
this.requestWaiting = callback;
|
||||
}
|
||||
|
||||
// If we called |this.drip| in the last step, the fetched results have been
|
||||
// consumed and we should ask some more for read-ahead now.
|
||||
//
|
||||
// Otherwise, kick start read-ahead again because it may be stopped
|
||||
// previously because of |this.maxReadAhead| had been reached.
|
||||
this.maybeSqueezeIdCollector(null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Consume fetched resutls.
|
||||
*
|
||||
* @param callback
|
||||
* A nsIMobileMessageCursorCallback.
|
||||
*/
|
||||
drip: function(callback) {
|
||||
let results = this.results;
|
||||
this.results = [];
|
||||
|
||||
let func = this.notifyCallback.bind(this, callback, results, this.lastId);
|
||||
Services.tm.currentThread.dispatch(func, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify a nsIMobileMessageCursorCallback.
|
||||
*
|
||||
* @param callback
|
||||
* A nsIMobileMessageCursorCallback.
|
||||
* @param results
|
||||
* An array of result objects.
|
||||
* @param lastId
|
||||
* Since we only call |this.drip| when either there are results
|
||||
* available or the read-ahead has done, so lastId here will be
|
||||
* COLLECT_ID_END or COLLECT_ID_ERROR when results is empty and null
|
||||
* otherwise.
|
||||
*/
|
||||
notifyCallback: function(callback, results, lastId) {
|
||||
if (DEBUG) {
|
||||
debug("notifyCallback(results[" + results.length + "], " + lastId + ")");
|
||||
}
|
||||
|
||||
if (results.length) {
|
||||
callback.notifyCursorResult(results, results.length);
|
||||
} else if (lastId == COLLECT_ID_END) {
|
||||
callback.notifyCursorDone();
|
||||
} else {
|
||||
callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function IDsCollector() {
|
||||
this.results = [];
|
||||
this.done = false;
|
||||
}
|
||||
ResultsCollector.prototype = {
|
||||
IDsCollector.prototype = {
|
||||
results: null,
|
||||
requestWaiting: null,
|
||||
done: null,
|
||||
@ -3517,20 +3815,16 @@ ResultsCollector.prototype = {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("collect: message ID = " + id);
|
||||
}
|
||||
if (id) {
|
||||
// Queue up any id but '0' and replies later accordingly.
|
||||
this.results.push(id);
|
||||
}
|
||||
if (DEBUG) debug("IDsCollector::collect ID = " + id);
|
||||
// Queue up any id.
|
||||
this.results.push(id);
|
||||
if (id <= 0) {
|
||||
// No more processing on '0' or negative values passed.
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
if (!this.requestWaiting) {
|
||||
if (DEBUG) debug("Cursor.continue() not called yet");
|
||||
if (DEBUG) debug("IDsCollector::squeeze() not called yet");
|
||||
return !this.done;
|
||||
}
|
||||
|
||||
@ -3575,22 +3869,11 @@ ResultsCollector.prototype = {
|
||||
* A callback function that accepts a numeric id.
|
||||
*/
|
||||
drip: function(txn, callback) {
|
||||
if (!this.results.length) {
|
||||
if (DEBUG) debug("No messages matching the filter criteria");
|
||||
callback(txn, COLLECT_ID_END);
|
||||
return;
|
||||
let firstId = this.results[0];
|
||||
if (firstId > 0) {
|
||||
this.results.shift();
|
||||
}
|
||||
|
||||
if (this.results[0] < 0) {
|
||||
// An previous error found. Keep the answer in results so that we can
|
||||
// reply INTERNAL_ERROR for further requests.
|
||||
if (DEBUG) debug("An previous error found");
|
||||
callback(txn, COLLECT_ID_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
let firstMessageId = this.results.shift();
|
||||
callback(txn, firstMessageId);
|
||||
callback(txn, firstId);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3784,7 +4067,7 @@ UnionResultsCollector.prototype = {
|
||||
function GetMessagesCursor(mmdb, callback) {
|
||||
this.mmdb = mmdb;
|
||||
this.callback = callback;
|
||||
this.collector = new ResultsCollector();
|
||||
this.collector = new ResultsCollector(this.getMessage.bind(this));
|
||||
|
||||
this.handleContinue(); // Trigger first run.
|
||||
}
|
||||
@ -3796,7 +4079,7 @@ GetMessagesCursor.prototype = {
|
||||
callback: null,
|
||||
collector: null,
|
||||
|
||||
getMessageTxn: function(messageStore, messageId) {
|
||||
getMessageTxn: function(txn, messageStore, messageId, collector) {
|
||||
if (DEBUG) debug ("Fetching message " + messageId);
|
||||
|
||||
let getRequest = messageStore.get(messageId);
|
||||
@ -3807,32 +4090,26 @@ GetMessagesCursor.prototype = {
|
||||
}
|
||||
let domMessage =
|
||||
self.mmdb.createDomMessageFromRecord(event.target.result);
|
||||
self.callback.notifyCursorResult(domMessage);
|
||||
collector.notifyResult(txn, messageId, domMessage);
|
||||
};
|
||||
getRequest.onerror = function(event) {
|
||||
// Error reporting is done in ResultsCollector.notifyCallback.
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if (DEBUG) {
|
||||
debug("notifyCursorError - messageId: " + messageId);
|
||||
}
|
||||
self.callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
collector.notifyResult(txn, messageId, null);
|
||||
};
|
||||
},
|
||||
|
||||
notify: function(txn, messageId) {
|
||||
if (!messageId) {
|
||||
this.callback.notifyCursorDone();
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageId < 0) {
|
||||
this.callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
getMessage: function(txn, messageId, collector) {
|
||||
// When filter transaction is not yet completed, we're called with current
|
||||
// ongoing transaction object.
|
||||
if (txn) {
|
||||
let messageStore = txn.objectStore(MESSAGE_STORE_NAME);
|
||||
this.getMessageTxn(messageStore, messageId);
|
||||
this.getMessageTxn(txn, messageStore, messageId, collector);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3840,10 +4117,11 @@ GetMessagesCursor.prototype = {
|
||||
let self = this;
|
||||
this.mmdb.newTxn(READ_ONLY, function(error, txn, messageStore) {
|
||||
if (error) {
|
||||
self.callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
return;
|
||||
debug("getMessage: failed to create new transaction");
|
||||
collector.notifyResult(null, messageId, null);
|
||||
} else {
|
||||
self.getMessageTxn(txn, messageStore, messageId, collector);
|
||||
}
|
||||
self.getMessageTxn(messageStore, messageId);
|
||||
}, [MESSAGE_STORE_NAME]);
|
||||
},
|
||||
|
||||
@ -3851,14 +4129,14 @@ GetMessagesCursor.prototype = {
|
||||
|
||||
handleContinue: function() {
|
||||
if (DEBUG) debug("Getting next message in list");
|
||||
this.collector.squeeze(this.notify.bind(this));
|
||||
this.collector.squeeze(this.callback);
|
||||
}
|
||||
};
|
||||
|
||||
function GetThreadsCursor(mmdb, callback) {
|
||||
this.mmdb = mmdb;
|
||||
this.callback = callback;
|
||||
this.collector = new ResultsCollector();
|
||||
this.collector = new ResultsCollector(this.getThread.bind(this));
|
||||
|
||||
this.handleContinue(); // Trigger first run.
|
||||
}
|
||||
@ -3870,11 +4148,10 @@ GetThreadsCursor.prototype = {
|
||||
callback: null,
|
||||
collector: null,
|
||||
|
||||
getThreadTxn: function(threadStore, threadId) {
|
||||
getThreadTxn: function(txn, threadStore, threadId, collector) {
|
||||
if (DEBUG) debug ("Fetching thread " + threadId);
|
||||
|
||||
let getRequest = threadStore.get(threadId);
|
||||
let self = this;
|
||||
getRequest.onsuccess = function(event) {
|
||||
let threadRecord = event.target.result;
|
||||
if (DEBUG) {
|
||||
@ -3888,32 +4165,26 @@ GetThreadsCursor.prototype = {
|
||||
threadRecord.body,
|
||||
threadRecord.unreadCount,
|
||||
threadRecord.lastMessageType);
|
||||
self.callback.notifyCursorResult(thread);
|
||||
collector.notifyResult(txn, threadId, thread);
|
||||
};
|
||||
getRequest.onerror = function(event) {
|
||||
// Error reporting is done in ResultsCollector.notifyCallback.
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if (DEBUG) {
|
||||
debug("notifyCursorError - threadId: " + threadId);
|
||||
}
|
||||
self.callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
collector.notifyResult(txn, threadId, null);
|
||||
};
|
||||
},
|
||||
|
||||
notify: function(txn, threadId) {
|
||||
if (!threadId) {
|
||||
this.callback.notifyCursorDone();
|
||||
return;
|
||||
}
|
||||
|
||||
if (threadId < 0) {
|
||||
this.callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
getThread: function(txn, threadId, collector) {
|
||||
// When filter transaction is not yet completed, we're called with current
|
||||
// ongoing transaction object.
|
||||
if (txn) {
|
||||
let threadStore = txn.objectStore(THREAD_STORE_NAME);
|
||||
this.getThreadTxn(threadStore, threadId);
|
||||
this.getThreadTxn(txn, threadStore, threadId, collector);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3921,10 +4192,10 @@ GetThreadsCursor.prototype = {
|
||||
let self = this;
|
||||
this.mmdb.newTxn(READ_ONLY, function(error, txn, threadStore) {
|
||||
if (error) {
|
||||
self.callback.notifyCursorError(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
return;
|
||||
collector.notifyResult(null, threadId, null);
|
||||
} else {
|
||||
self.getThreadTxn(txn, threadStore, threadId, collector);
|
||||
}
|
||||
self.getThreadTxn(threadStore, threadId);
|
||||
}, [THREAD_STORE_NAME]);
|
||||
},
|
||||
|
||||
@ -3932,7 +4203,7 @@ GetThreadsCursor.prototype = {
|
||||
|
||||
handleContinue: function() {
|
||||
if (DEBUG) debug("Getting next thread in list");
|
||||
this.collector.squeeze(this.notify.bind(this));
|
||||
this.collector.squeeze(this.callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,11 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(8fd0dba2-032e-4190-a751-07cc3782e93e)]
|
||||
[scriptable, builtinclass, uuid(134a6958-543b-46e2-b419-4631a2314164)]
|
||||
interface nsIMobileMessageCursorCallback : nsISupports
|
||||
{
|
||||
void notifyCursorError(in long error);
|
||||
void notifyCursorResult(in nsISupports result);
|
||||
void notifyCursorResult([array, size_is(size)] in nsISupports results,
|
||||
in uint32_t size);
|
||||
void notifyCursorDone();
|
||||
};
|
||||
|
@ -293,22 +293,17 @@ MobileMessageCursorChild::RecvNotifyResult(const MobileMessageCursorData& aData)
|
||||
{
|
||||
MOZ_ASSERT(mCursorCallback);
|
||||
|
||||
nsCOMPtr<nsISupports> result;
|
||||
switch(aData.type()) {
|
||||
case MobileMessageCursorData::TMmsMessageData:
|
||||
result = new MmsMessage(aData.get_MmsMessageData());
|
||||
case MobileMessageCursorData::TMobileMessageArrayData:
|
||||
DoNotifyResult(aData.get_MobileMessageArrayData().messages());
|
||||
break;
|
||||
case MobileMessageCursorData::TSmsMessageData:
|
||||
result = new SmsMessage(aData.get_SmsMessageData());
|
||||
break;
|
||||
case MobileMessageCursorData::TThreadData:
|
||||
result = new MobileMessageThread(aData.get_ThreadData());
|
||||
case MobileMessageCursorData::TThreadArrayData:
|
||||
DoNotifyResult(aData.get_ThreadArrayData().threads());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Received invalid response parameters!");
|
||||
}
|
||||
|
||||
mCursorCallback->NotifyCursorResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -338,6 +333,48 @@ MobileMessageCursorChild::HandleContinue()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MobileMessageCursorChild::DoNotifyResult(const nsTArray<MobileMessageData>& aDataArray)
|
||||
{
|
||||
const uint32_t length = aDataArray.Length();
|
||||
MOZ_ASSERT(length);
|
||||
|
||||
AutoFallibleTArray<nsISupports*, 1> autoArray;
|
||||
NS_ENSURE_TRUE_VOID(autoArray.SetCapacity(length));
|
||||
|
||||
AutoFallibleTArray<nsCOMPtr<nsISupports>, 1> messages;
|
||||
NS_ENSURE_TRUE_VOID(messages.SetCapacity(length));
|
||||
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsISupports> message = CreateMessageFromMessageData(aDataArray[i]);
|
||||
NS_ENSURE_TRUE_VOID(messages.AppendElement(message));
|
||||
NS_ENSURE_TRUE_VOID(autoArray.AppendElement(message.get()));
|
||||
}
|
||||
|
||||
mCursorCallback->NotifyCursorResult(autoArray.Elements(), length);
|
||||
}
|
||||
|
||||
void
|
||||
MobileMessageCursorChild::DoNotifyResult(const nsTArray<ThreadData>& aDataArray)
|
||||
{
|
||||
const uint32_t length = aDataArray.Length();
|
||||
MOZ_ASSERT(length);
|
||||
|
||||
AutoFallibleTArray<nsISupports*, 1> autoArray;
|
||||
NS_ENSURE_TRUE_VOID(autoArray.SetCapacity(length));
|
||||
|
||||
AutoFallibleTArray<nsCOMPtr<nsISupports>, 1> threads;
|
||||
NS_ENSURE_TRUE_VOID(threads.SetCapacity(length));
|
||||
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
nsCOMPtr<nsISupports> thread = new MobileMessageThread(aDataArray[i]);
|
||||
NS_ENSURE_TRUE_VOID(threads.AppendElement(thread));
|
||||
NS_ENSURE_TRUE_VOID(autoArray.AppendElement(thread.get()));
|
||||
}
|
||||
|
||||
mCursorCallback->NotifyCursorResult(autoArray.Elements(), length);
|
||||
}
|
||||
|
||||
} // namespace mobilemessage
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -129,6 +129,13 @@ protected:
|
||||
|
||||
virtual bool
|
||||
Recv__delete__(const int32_t& aError) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
void
|
||||
DoNotifyResult(const nsTArray<MobileMessageData>& aData);
|
||||
|
||||
void
|
||||
DoNotifyResult(const nsTArray<ThreadData>& aData);
|
||||
};
|
||||
|
||||
} // namespace mobilemessage
|
||||
|
@ -843,40 +843,59 @@ MobileMessageCursorParent::NotifyCursorError(int32_t aError)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageCursorParent::NotifyCursorResult(nsISupports* aResult)
|
||||
MobileMessageCursorParent::NotifyCursorResult(nsISupports** aResults,
|
||||
uint32_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(aResults && *aResults && aSize);
|
||||
|
||||
// The child process could die before this asynchronous notification, in which
|
||||
// case ActorDestroy() was called and mContinueCallback is now null. Return an
|
||||
// error here to avoid sending a message to the dead process.
|
||||
NS_ENSURE_TRUE(mContinueCallback, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMMozSmsMessage> iSms = do_QueryInterface(aResult);
|
||||
if (iSms) {
|
||||
SmsMessage* message = static_cast<SmsMessage*>(aResult);
|
||||
return SendNotifyResult(MobileMessageCursorData(message->GetData()))
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMozMmsMessage> iMms = do_QueryInterface(aResult);
|
||||
if (iMms) {
|
||||
MmsMessage* message = static_cast<MmsMessage*>(aResult);
|
||||
ContentParent* parent = static_cast<ContentParent*>(Manager()->Manager());
|
||||
MmsMessageData data;
|
||||
if (!message->GetData(parent, data)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return SendNotifyResult(MobileMessageCursorData(data))
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMozMobileMessageThread> iThread = do_QueryInterface(aResult);
|
||||
nsCOMPtr<nsIDOMMozMobileMessageThread> iThread =
|
||||
do_QueryInterface(aResults[0]);
|
||||
if (iThread) {
|
||||
MobileMessageThread* thread = static_cast<MobileMessageThread*>(aResult);
|
||||
return SendNotifyResult(MobileMessageCursorData(thread->GetData()))
|
||||
nsTArray<ThreadData> threads;
|
||||
|
||||
for (uint32_t i = 0; i < aSize; i++) {
|
||||
nsCOMPtr<nsIDOMMozMobileMessageThread> iThread =
|
||||
do_QueryInterface(aResults[i]);
|
||||
NS_ENSURE_TRUE(iThread, NS_ERROR_FAILURE);
|
||||
|
||||
MobileMessageThread* thread =
|
||||
static_cast<MobileMessageThread*>(iThread.get());
|
||||
threads.AppendElement(thread->GetData());
|
||||
}
|
||||
|
||||
return SendNotifyResult(MobileMessageCursorData(ThreadArrayData(threads)))
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Received invalid response parameters!");
|
||||
ContentParent* parent = static_cast<ContentParent*>(Manager()->Manager());
|
||||
nsTArray<MobileMessageData> messages;
|
||||
for (uint32_t i = 0; i < aSize; i++) {
|
||||
nsCOMPtr<nsIDOMMozSmsMessage> iSms = do_QueryInterface(aResults[i]);
|
||||
if (iSms) {
|
||||
SmsMessage* sms = static_cast<SmsMessage*>(iSms.get());
|
||||
messages.AppendElement(sms->GetData());
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMozMmsMessage> iMms = do_QueryInterface(aResults[i]);
|
||||
if (iMms) {
|
||||
MmsMessage* mms = static_cast<MmsMessage*>(iMms.get());
|
||||
MmsMessageData mmsData;
|
||||
NS_ENSURE_TRUE(mms->GetData(parent, mmsData), NS_ERROR_FAILURE);
|
||||
messages.AppendElement(mmsData);
|
||||
continue;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return SendNotifyResult(MobileMessageCursorData(MobileMessageArrayData(messages)))
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -99,11 +99,20 @@ struct ThreadData
|
||||
MessageType lastMessageType;
|
||||
};
|
||||
|
||||
struct MobileMessageArrayData
|
||||
{
|
||||
MobileMessageData[] messages;
|
||||
};
|
||||
|
||||
struct ThreadArrayData
|
||||
{
|
||||
ThreadData[] threads;
|
||||
};
|
||||
|
||||
union MobileMessageCursorData
|
||||
{
|
||||
MmsMessageData;
|
||||
SmsMessageData;
|
||||
ThreadData;
|
||||
MobileMessageArrayData;
|
||||
ThreadArrayData;
|
||||
};
|
||||
|
||||
struct DeletedMessageInfoData
|
||||
|
@ -303,9 +303,9 @@ function createMmdbCursor(aMmdb, aMethodName) {
|
||||
deferred.reject([aRv, results]);
|
||||
},
|
||||
|
||||
notifyCursorResult: function(aResult) {
|
||||
ok(true, "notifyCursorResult: " + aResult.id);
|
||||
results.push(aResult);
|
||||
notifyCursorResult: function(aResults, aSize) {
|
||||
ok(true, "notifyCursorResult: " + aResults.map(function(aElement) { return aElement.id; }));
|
||||
results = results.concat(aResults);
|
||||
cursor.handleContinue();
|
||||
},
|
||||
|
||||
|
@ -410,8 +410,6 @@ nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
|
||||
CheckClassInitialized();
|
||||
|
||||
nsRefPtr<nsNPAPIPlugin> plugin = new nsNPAPIPlugin();
|
||||
if (!plugin)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag);
|
||||
if (!pluginLib) {
|
||||
@ -421,6 +419,7 @@ nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
|
||||
#if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
|
||||
if (!pluginLib->HasRequiredFunctions()) {
|
||||
NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
|
||||
delete pluginLib;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#endif
|
||||
@ -866,7 +865,7 @@ _geturl(NPP npp, const char* relativeURL, const char* target)
|
||||
(strncmp(relativeURL, "ftp:", 4) != 0)) {
|
||||
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
|
||||
|
||||
|
||||
|
||||
const char *name = nullptr;
|
||||
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
|
||||
host->GetPluginName(inst, &name);
|
||||
@ -2096,14 +2095,14 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
case NPNVsupportsQuickDrawBool: {
|
||||
*(NPBool*)result = false;
|
||||
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
case NPNVsupportsCoreGraphicsBool: {
|
||||
*(NPBool*)result = true;
|
||||
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -2173,14 +2172,14 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
InitMatrixInterface(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
case kPathInterfaceV0_ANPGetValue: {
|
||||
LOG("get path interface");
|
||||
ANPPathInterfaceV0 *i = (ANPPathInterfaceV0 *) result;
|
||||
InitPathInterface(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
case kTypefaceInterfaceV0_ANPGetValue: {
|
||||
LOG("get typeface interface");
|
||||
ANPTypefaceInterfaceV0 *i = (ANPTypefaceInterfaceV0 *) result;
|
||||
@ -2236,7 +2235,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
InitSurfaceInterface(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
case kSupportedDrawingModel_ANPGetValue: {
|
||||
LOG("get supported drawing model");
|
||||
uint32_t* bits = reinterpret_cast<uint32_t*>(result);
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
PROGRAM = 'plugin-hang-ui'
|
||||
Program('plugin-hang-ui')
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'MiniShmChild.cpp',
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'plugin_child_interpose'
|
||||
SharedLibrary('plugin_child_interpose')
|
||||
|
||||
UNIFIED_SOURCES += [ "%s.mm" % (LIBRARY_NAME) ]
|
||||
|
||||
@ -12,6 +12,4 @@ UNIFIED_SOURCES += [
|
||||
'plugin_child_quirks.mm',
|
||||
]
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
|
||||
OS_LIBS += ['-framework Carbon']
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'nptestjava'
|
||||
SharedLibrary('nptestjava')
|
||||
|
||||
relative_path = '..'
|
||||
include('../testplugin.mozbuild')
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
DIRS += ['secondplugin', 'javaplugin']
|
||||
|
||||
LIBRARY_NAME = 'nptest'
|
||||
SharedLibrary('nptest')
|
||||
|
||||
FAIL_ON_WARNINGS = not CONFIG['_MSC_VER']
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
LIBRARY_NAME = 'npsecondtest'
|
||||
SharedLibrary('npsecondtest')
|
||||
|
||||
relative_path = '..'
|
||||
include('../testplugin.mozbuild')
|
||||
|
@ -40,8 +40,6 @@ elif toolkit == 'windows':
|
||||
'msimg32',
|
||||
]
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
|
||||
# must link statically with the CRT; nptest isn't Gecko code
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
|
@ -284,8 +284,8 @@ function RILContentHelper() {
|
||||
this.voicemailStatuses = [];
|
||||
for (let clientId = 0; clientId < this.numClients; clientId++) {
|
||||
this.rilContexts[clientId] = {
|
||||
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
|
||||
iccInfo: null
|
||||
cardState: Ci.nsIIccProvider.CARD_STATE_UNKNOWN,
|
||||
iccInfo: null
|
||||
};
|
||||
|
||||
this.voicemailInfos[clientId] = new VoicemailInfo();
|
||||
|
@ -559,8 +559,8 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() {
|
||||
|
||||
_isCardPresentAtClient: function(clientId) {
|
||||
let cardState = _ril.getRadioInterface(clientId).rilContext.cardState;
|
||||
return cardState !== RIL.GECKO_CARDSTATE_UNDETECTED &&
|
||||
cardState !== RIL.GECKO_CARDSTATE_UNKNOWN;
|
||||
return cardState !== Ci.nsIIccProvider.CARD_STATE_UNDETECTED &&
|
||||
cardState !== Ci.nsIIccProvider.CARD_STATE_UNKNOWN;
|
||||
},
|
||||
|
||||
_isRadioAbleToEnableAtClient: function(clientId, numCards) {
|
||||
@ -1873,7 +1873,7 @@ function RadioInterface(aClientId, aWorkerMessenger) {
|
||||
aWorkerMessenger.registerClient(aClientId, this);
|
||||
|
||||
this.rilContext = {
|
||||
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
|
||||
cardState: Ci.nsIIccProvider.CARD_STATE_UNKNOWN,
|
||||
iccInfo: null,
|
||||
imsi: null
|
||||
};
|
||||
@ -3713,7 +3713,7 @@ RadioInterface.prototype = {
|
||||
} else if (radioState == RIL.GECKO_RADIOSTATE_DISABLED) {
|
||||
if (DEBUG) this.debug("Error! Radio is disabled when sending SMS.");
|
||||
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
|
||||
} else if (this.rilContext.cardState != "ready") {
|
||||
} else if (this.rilContext.cardState != Ci.nsIIccProvider.CARD_STATE_READY) {
|
||||
if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS.");
|
||||
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
||||
}
|
||||
|
@ -2487,38 +2487,40 @@ this.GECKO_RADIOSTATE_ENABLED = "enabled";
|
||||
this.GECKO_RADIOSTATE_DISABLING = "disabling";
|
||||
this.GECKO_RADIOSTATE_DISABLED = "disabled";
|
||||
|
||||
this.GECKO_CARDSTATE_UNINITIALIZED = "uninitialized";
|
||||
this.GECKO_CARDSTATE_UNDETECTED = null;
|
||||
this.GECKO_CARDSTATE_ILLEGAL = "illegal";
|
||||
this.GECKO_CARDSTATE_UNKNOWN = "unknown";
|
||||
this.GECKO_CARDSTATE_PIN_REQUIRED = "pinRequired";
|
||||
this.GECKO_CARDSTATE_PUK_REQUIRED = "pukRequired";
|
||||
this.GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS = "personalizationInProgress";
|
||||
this.GECKO_CARDSTATE_PERSONALIZATION_READY = "personalizationReady";
|
||||
this.GECKO_CARDSTATE_NETWORK_LOCKED = "networkLocked";
|
||||
this.GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED = "networkSubsetLocked";
|
||||
this.GECKO_CARDSTATE_NETWORK1_LOCKED = "network1Locked";
|
||||
this.GECKO_CARDSTATE_NETWORK2_LOCKED = "network2Locked";
|
||||
this.GECKO_CARDSTATE_HRPD_NETWORK_LOCKED = "hrpdNetworkLocked";
|
||||
this.GECKO_CARDSTATE_CORPORATE_LOCKED = "corporateLocked";
|
||||
this.GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED = "serviceProviderLocked";
|
||||
this.GECKO_CARDSTATE_SIM_LOCKED = "simPersonalizationLock";
|
||||
this.GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED = "ruimCorporateLocked";
|
||||
this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED = "ruimServiceProviderLocked";
|
||||
this.GECKO_CARDSTATE_RUIM_LOCKED = "ruimPersonalizationLock";
|
||||
this.GECKO_CARDSTATE_NETWORK_PUK_REQUIRED = "networkPukRequired";
|
||||
this.GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED = "networkSubsetPukRequired";
|
||||
this.GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED = "network1PukRequired";
|
||||
this.GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED = "network2PukRequired";
|
||||
this.GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED = "hrpdNetworkPukRequired";
|
||||
this.GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED = "corporatePukRequired";
|
||||
this.GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED = "serviceProviderPukRequired";
|
||||
this.GECKO_CARDSTATE_SIM_PUK_REQUIRED = "simPersonalizationPukRequired";
|
||||
this.GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED = "ruimCorporatePukRequired";
|
||||
this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = "ruimServiceProviderPukRequired";
|
||||
this.GECKO_CARDSTATE_RUIM_PUK_REQUIRED = "ruimPersonalizationPukRequired";
|
||||
this.GECKO_CARDSTATE_READY = "ready";
|
||||
this.GECKO_CARDSTATE_PERMANENT_BLOCKED = "permanentBlocked";
|
||||
// Only used in ril_worker.js
|
||||
this.GECKO_CARDSTATE_UNINITIALIZED = 4294967294; // UINT32_MAX - 1
|
||||
// See nsIIccProvider::CARD_STATE_*
|
||||
this.GECKO_CARDSTATE_UNDETECTED = 4294967295; // UINT32_MAX
|
||||
this.GECKO_CARDSTATE_UNKNOWN = 0;
|
||||
this.GECKO_CARDSTATE_READY = 1;
|
||||
this.GECKO_CARDSTATE_PIN_REQUIRED = 2;
|
||||
this.GECKO_CARDSTATE_PUK_REQUIRED = 3;
|
||||
this.GECKO_CARDSTATE_PERMANENT_BLOCKED = 4;
|
||||
this.GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS = 5;
|
||||
this.GECKO_CARDSTATE_PERSONALIZATION_READY = 6;
|
||||
this.GECKO_CARDSTATE_NETWORK_LOCKED = 7;
|
||||
this.GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED = 8;
|
||||
this.GECKO_CARDSTATE_CORPORATE_LOCKED = 9;
|
||||
this.GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED = 10;
|
||||
this.GECKO_CARDSTATE_SIM_LOCKED = 11;
|
||||
this.GECKO_CARDSTATE_NETWORK_PUK_REQUIRED = 12;
|
||||
this.GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED = 13;
|
||||
this.GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED = 14;
|
||||
this.GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED = 15;
|
||||
this.GECKO_CARDSTATE_SIM_PUK_REQUIRED = 16;
|
||||
this.GECKO_CARDSTATE_NETWORK1_LOCKED = 17;
|
||||
this.GECKO_CARDSTATE_NETWORK2_LOCKED = 18;
|
||||
this.GECKO_CARDSTATE_HRPD_NETWORK_LOCKED = 19;
|
||||
this.GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED = 20;
|
||||
this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED = 21;
|
||||
this.GECKO_CARDSTATE_RUIM_LOCKED = 22;
|
||||
this.GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED = 23;
|
||||
this.GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED = 24;
|
||||
this.GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED = 25;
|
||||
this.GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED = 26;
|
||||
this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27;
|
||||
this.GECKO_CARDSTATE_RUIM_PUK_REQUIRED = 28;
|
||||
this.GECKO_CARDSTATE_ILLEGAL = 29;
|
||||
|
||||
this.GECKO_CARDLOCK_PIN = "pin";
|
||||
this.GECKO_CARDLOCK_PIN2 = "pin2";
|
||||
@ -2556,6 +2558,7 @@ PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_PUK] = GECKO_CARDSTATE_NETWORK_PUK
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK] = GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED;
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK] = GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED;
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK] = GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED;
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SIM_PUK] = GECKO_CARDSTATE_SIM_PUK_REQUIRED;
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK1] = GECKO_CARDSTATE_NETWORK1_LOCKED;
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK2] = GECKO_CARDSTATE_NETWORK2_LOCKED;
|
||||
PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_HRPD] = GECKO_CARDSTATE_HRPD_NETWORK_LOCKED;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user