зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team, a=merge
This commit is contained in:
Коммит
e046a644c8
|
@ -547,8 +547,9 @@ GroupPos
|
|||
ARIARowAccessible::GroupPosition()
|
||||
{
|
||||
int32_t count = 0, index = 0;
|
||||
if (nsCoreUtils::GetUIntAttr(nsAccUtils::TableFor(this)->GetContent(),
|
||||
nsGkAtoms::aria_rowcount, &count) &&
|
||||
Accessible* table = nsAccUtils::TableFor(this);
|
||||
if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
|
||||
nsGkAtoms::aria_rowcount, &count) &&
|
||||
nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
|
||||
return GroupPos(0, index, count);
|
||||
}
|
||||
|
|
|
@ -128,7 +128,10 @@ var LogShake = {
|
|||
"/proc/version": LogParser.prettyPrintArray,
|
||||
"/proc/vmallocinfo": LogParser.prettyPrintArray,
|
||||
"/proc/vmstat": LogParser.prettyPrintArray,
|
||||
"/system/b2g/application.ini": LogParser.prettyPrintArray
|
||||
"/system/b2g/application.ini": LogParser.prettyPrintArray,
|
||||
"/cache/recovery/last_install": LogParser.prettyPrintArray,
|
||||
"/cache/recovery/last_kmsg": LogParser.prettyPrintArray,
|
||||
"/cache/recovery/last_log": LogParser.prettyPrintArray
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<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="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="065f6361461030d32c6dc08d716b013bfadab1d9"/>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<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="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="065f6361461030d32c6dc08d716b013bfadab1d9"/>
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "4973f57cd8f9a62a95f783a24eac32da2bde99fc",
|
||||
"git_revision": "e698df503ff700eb5782e3d50c6eb753567d3451",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "c728de03bc96ef160fd5a662b3efcd5cf2c2b844",
|
||||
"revision": "bd073200a776c714b8160a38c77f980b19fd97c2",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4973f57cd8f9a62a95f783a24eac32da2bde99fc"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e698df503ff700eb5782e3d50c6eb753567d3451"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e0fe55ac52323eace5a6119ab2b911fc4f64495"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[DEFAULT]
|
||||
skip-if = os == 'android' || buildapp == 'b2g' || os == 'mac'
|
||||
support-files =
|
||||
head.js
|
||||
context.html
|
||||
|
|
|
@ -103,6 +103,8 @@ SEARCH_PATHS = [
|
|||
'testing/mozbase/mozdevice',
|
||||
'testing/mozbase/mozfile',
|
||||
'testing/mozbase/mozhttpd',
|
||||
'testing/mozbase/mozinfo',
|
||||
'testing/mozbase/mozinstall',
|
||||
'testing/mozbase/mozleak',
|
||||
'testing/mozbase/mozlog',
|
||||
'testing/mozbase/moznetwork',
|
||||
|
@ -110,7 +112,6 @@ SEARCH_PATHS = [
|
|||
'testing/mozbase/mozprofile',
|
||||
'testing/mozbase/mozrunner',
|
||||
'testing/mozbase/mozsystemmonitor',
|
||||
'testing/mozbase/mozinfo',
|
||||
'testing/mozbase/mozscreenshot',
|
||||
'testing/mozbase/moztest',
|
||||
'testing/mozbase/mozversion',
|
||||
|
|
|
@ -212,11 +212,10 @@ var testcases = [ {
|
|||
protocolChange: true
|
||||
}, {
|
||||
input: "[::1][100",
|
||||
fixedURI: "http://[::1][100/",
|
||||
alternateURI: "http://[::1][100/",
|
||||
fixedURI: null,
|
||||
alternateURI: null,
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
affectedByDNSForSingleHosts: true,
|
||||
protocolChange: true
|
||||
}, {
|
||||
input: "[::1]]",
|
||||
keywordLookup: true,
|
||||
|
@ -503,13 +502,14 @@ if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
|
|||
fixedURI: "file:////mozilla",
|
||||
protocolChange: true,
|
||||
});
|
||||
// \ is an invalid character in the hostname until bug 652186 is implemented
|
||||
testcases.push({
|
||||
input: "mozilla\\",
|
||||
fixedURI: "http://mozilla\\/",
|
||||
alternateURI: "http://www.mozilla/",
|
||||
// fixedURI: "http://mozilla\\/",
|
||||
// alternateURI: "http://www.mozilla/",
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
affectedByDNSForSingleHosts: true,
|
||||
// affectedByDNSForSingleHosts: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -84,11 +84,10 @@ MP3Demuxer::IsSeekable() const {
|
|||
}
|
||||
|
||||
void
|
||||
MP3Demuxer::NotifyDataArrived(uint32_t aLength, int64_t aOffset) {
|
||||
MP3Demuxer::NotifyDataArrived() {
|
||||
// TODO: bug 1169485.
|
||||
NS_WARNING("Unimplemented function NotifyDataArrived");
|
||||
MP3DEMUXER_LOGV("NotifyDataArrived(%u, %" PRId64 ") mOffset=%" PRId64,
|
||||
aLength, aOffset, mTrackDemuxer->GetResourceOffset());
|
||||
MP3DEMUXER_LOGV("NotifyDataArrived()");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(
|
||||
TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
bool IsSeekable() const override;
|
||||
void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
|
||||
void NotifyDataArrived() override;
|
||||
void NotifyDataRemoved() override;
|
||||
// Do not shift the calculated buffered range by the start time of the first
|
||||
// decoded frame. The mac MP3 decoder will buffer some samples and the first
|
||||
|
|
|
@ -77,15 +77,17 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Notifies the demuxer that the underlying resource has received more data.
|
||||
// Notifies the demuxer that the underlying resource has received more data
|
||||
// since the demuxer was initialized.
|
||||
// The demuxer can use this mechanism to inform all track demuxers that new
|
||||
// data is available.
|
||||
virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) { }
|
||||
// data is available and to refresh its buffered range.
|
||||
virtual void NotifyDataArrived() { }
|
||||
|
||||
// Notifies the demuxer that the underlying resource has had data removed.
|
||||
// Notifies the demuxer that the underlying resource has had data removed
|
||||
// since the demuxer was initialized.
|
||||
// The demuxer can use this mechanism to inform all track demuxers to update
|
||||
// its TimeIntervals.
|
||||
// This will be called should the demuxer be used with MediaSource.
|
||||
// its buffered range.
|
||||
// This will be called should the demuxer be used with MediaSourceResource.
|
||||
virtual void NotifyDataRemoved() { }
|
||||
|
||||
// Indicate to MediaFormatReader if it should compute the start time
|
||||
|
|
|
@ -1603,7 +1603,7 @@ MediaFormatReader::NotifyDemuxer(uint32_t aLength, int64_t aOffset)
|
|||
}
|
||||
|
||||
if (aLength || aOffset) {
|
||||
mDemuxer->NotifyDataArrived(aLength, aOffset);
|
||||
mDemuxer->NotifyDataArrived();
|
||||
} else {
|
||||
mDemuxer->NotifyDataRemoved();
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ MP4Demuxer::IsSeekable() const
|
|||
}
|
||||
|
||||
void
|
||||
MP4Demuxer::NotifyDataArrived(uint32_t aLength, int64_t aOffset)
|
||||
MP4Demuxer::NotifyDataArrived()
|
||||
{
|
||||
for (uint32_t i = 0; i < mDemuxers.Length(); i++) {
|
||||
mDemuxers[i]->NotifyDataArrived();
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
|
||||
virtual UniquePtr<EncryptionInfo> GetCrypto() override;
|
||||
|
||||
virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
|
||||
virtual void NotifyDataArrived() override;
|
||||
|
||||
virtual void NotifyDataRemoved() override;
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ MediaSourceDemuxer::AttemptInit()
|
|||
return p;
|
||||
}
|
||||
|
||||
void MediaSourceDemuxer::NotifyDataArrived(uint32_t aLength, int64_t aOffset)
|
||||
void MediaSourceDemuxer::NotifyDataArrived()
|
||||
{
|
||||
nsRefPtr<MediaSourceDemuxer> self = this;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
bool ShouldComputeStartTime() const override { return false; }
|
||||
|
||||
void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
|
||||
void NotifyDataArrived() override;
|
||||
|
||||
/* interface for TrackBuffersManager */
|
||||
void AttachSourceBuffer(TrackBuffersManager* aSourceBuffer);
|
||||
|
|
|
@ -876,10 +876,8 @@ void
|
|||
TrackBuffersManager::AppendDataToCurrentInputBuffer(MediaByteBuffer* aData)
|
||||
{
|
||||
MOZ_ASSERT(mCurrentInputBuffer);
|
||||
int64_t offset = mCurrentInputBuffer->GetLength();
|
||||
mCurrentInputBuffer->AppendData(aData);
|
||||
// A MediaByteBuffer has a maximum size of 2GiB.
|
||||
mInputDemuxer->NotifyDataArrived(uint32_t(aData->Length()), offset);
|
||||
mInputDemuxer->NotifyDataArrived();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include <android/log.h>
|
||||
#define MCP_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "MediaCodecProxy", __VA_ARGS__)
|
||||
#define TIMEOUT_DEQUEUE_INPUTBUFFER_MS 1000000ll
|
||||
|
||||
namespace android {
|
||||
|
||||
|
@ -571,7 +570,8 @@ bool MediaCodecProxy::UpdateOutputBuffers()
|
|||
}
|
||||
|
||||
status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize,
|
||||
int64_t aTimestampUsecs, uint64_t aflags)
|
||||
int64_t aTimestampUsecs, uint64_t aflags,
|
||||
int64_t aTimeoutUs)
|
||||
{
|
||||
// Read Lock for mCodec
|
||||
{
|
||||
|
@ -583,9 +583,11 @@ status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize,
|
|||
}
|
||||
|
||||
size_t index;
|
||||
status_t err = dequeueInputBuffer(&index, TIMEOUT_DEQUEUE_INPUTBUFFER_MS);
|
||||
status_t err = dequeueInputBuffer(&index, aTimeoutUs);
|
||||
if (err != OK) {
|
||||
MCP_LOG("dequeueInputBuffer returned %d", err);
|
||||
if (err != -EAGAIN) {
|
||||
MCP_LOG("dequeueInputBuffer returned %d", err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ public:
|
|||
|
||||
// If aData is null, will notify decoder input EOS
|
||||
status_t Input(const uint8_t* aData, uint32_t aDataSize,
|
||||
int64_t aTimestampUsecs, uint64_t flags);
|
||||
int64_t aTimestampUsecs, uint64_t flags, int64_t aTimeoutUs = 0);
|
||||
status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs);
|
||||
bool Prepare();
|
||||
void ReleaseMediaResources();
|
||||
|
|
|
@ -389,9 +389,8 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
|||
picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mStreamSource);
|
||||
// This is the approximate byte position in the stream.
|
||||
int64_t pos = mStreamSource->Tell();
|
||||
int64_t pos = mStreamSource ? mStreamSource->Tell() : 0;
|
||||
|
||||
nsRefPtr<VideoData> v;
|
||||
if (!frame.mGraphicBuffer) {
|
||||
|
@ -492,9 +491,8 @@ bool MediaOmxReader::DecodeAudioData()
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
EnsureActive();
|
||||
|
||||
MOZ_ASSERT(mStreamSource);
|
||||
// This is the approximate byte position in the stream.
|
||||
int64_t pos = mStreamSource->Tell();
|
||||
int64_t pos = mStreamSource ? mStreamSource->Tell() : 0;
|
||||
|
||||
// Read next frame
|
||||
MPAPI::AudioFrame source;
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
#include "MediaData.h"
|
||||
#include "MediaInfo.h"
|
||||
|
||||
#define CODECCONFIG_TIMEOUT_US 10000LL
|
||||
#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL
|
||||
|
||||
#include <android/log.h>
|
||||
#define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__)
|
||||
|
||||
extern PRLogModuleInfo* GetPDMLog();
|
||||
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000
|
||||
|
||||
using namespace android;
|
||||
typedef android::MediaCodecProxy MediaCodecProxy;
|
||||
|
@ -34,18 +36,15 @@ typedef android::MediaCodecProxy MediaCodecProxy;
|
|||
namespace mozilla {
|
||||
|
||||
GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
|
||||
: mLastDecodedTime(0)
|
||||
, mAudioChannels(aConfig.mChannels)
|
||||
: mAudioChannels(aConfig.mChannels)
|
||||
, mAudioRate(aConfig.mRate)
|
||||
, mAudioProfile(aConfig.mProfile)
|
||||
, mAudioBuffer(nullptr)
|
||||
, mMonitor("GonkAudioDecoderManager")
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
|
||||
MOZ_ASSERT(mAudioChannels);
|
||||
mCodecSpecificData = aConfig.mCodecSpecificConfig;
|
||||
mMimeType = aConfig.mMimeType;
|
||||
|
||||
}
|
||||
|
||||
GonkAudioDecoderManager::~GonkAudioDecoderManager()
|
||||
|
@ -54,9 +53,9 @@ GonkAudioDecoderManager::~GonkAudioDecoderManager()
|
|||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder::InitPromise>
|
||||
GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
GonkAudioDecoderManager::Init()
|
||||
{
|
||||
if (InitMediaCodecProxy(aCallback)) {
|
||||
if (InitMediaCodecProxy()) {
|
||||
return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
|
||||
} else {
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
|
@ -64,18 +63,14 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
}
|
||||
|
||||
bool
|
||||
GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback)
|
||||
GonkAudioDecoderManager::InitMediaCodecProxy()
|
||||
{
|
||||
status_t rv = OK;
|
||||
if (mLooper != nullptr) {
|
||||
if (!InitLoopers(MediaData::AUDIO_DATA)) {
|
||||
return false;
|
||||
}
|
||||
// Create ALooper
|
||||
mLooper = new ALooper;
|
||||
mLooper->setName("GonkAudioDecoderManager");
|
||||
mLooper->start();
|
||||
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, nullptr);
|
||||
if (!mDecoder.get()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -99,7 +94,8 @@ GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback
|
|||
|
||||
if (mMimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0,
|
||||
android::MediaCodec::BUFFER_FLAG_CODECCONFIG);
|
||||
android::MediaCodec::BUFFER_FLAG_CODECCONFIG,
|
||||
CODECCONFIG_TIMEOUT_US);
|
||||
}
|
||||
|
||||
if (rv == OK) {
|
||||
|
@ -110,52 +106,6 @@ GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GonkAudioDecoderManager::HasQueuedSample()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return mQueueSample.Length();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (aSample) {
|
||||
sample = aSample;
|
||||
} else {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
}
|
||||
|
||||
mQueueSample.AppendElement(sample);
|
||||
|
||||
status_t rv;
|
||||
while (mQueueSample.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
MonitorAutoUnlock mon_exit(mMonitor);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
if (rv == OK) {
|
||||
mQueueSample.RemoveElementAt(0);
|
||||
} else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
|
||||
// In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
|
||||
// buffer on time.
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
||||
if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
|
||||
|
@ -175,13 +125,13 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (mLastDecodedTime > timeUs) {
|
||||
if (mLastTime > timeUs) {
|
||||
ReleaseAudioBuffer();
|
||||
GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastDecodedTime = timeUs;
|
||||
mLastTime = timeUs;
|
||||
|
||||
const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
|
||||
size_t dataOffset = mAudioBuffer->range_offset();
|
||||
|
@ -207,23 +157,6 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Flush()
|
||||
{
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
}
|
||||
|
||||
mLastDecodedTime = 0;
|
||||
|
||||
if (mDecoder->flush() != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutData)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
using namespace android;
|
||||
|
||||
namespace android {
|
||||
struct MOZ_EXPORT ALooper;
|
||||
class MOZ_EXPORT MediaBuffer;
|
||||
} // namespace android
|
||||
|
||||
|
@ -24,44 +23,26 @@ typedef android::MediaCodecProxy MediaCodecProxy;
|
|||
public:
|
||||
GonkAudioDecoderManager(const AudioInfo& aConfig);
|
||||
|
||||
virtual ~GonkAudioDecoderManager() override;
|
||||
virtual ~GonkAudioDecoderManager();
|
||||
|
||||
nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
nsresult Input(MediaRawData* aSample) override;
|
||||
nsRefPtr<InitPromise> Init() override;
|
||||
|
||||
nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) override;
|
||||
|
||||
nsresult Flush() override;
|
||||
|
||||
bool HasQueuedSample() override;
|
||||
|
||||
private:
|
||||
bool InitMediaCodecProxy(MediaDataDecoderCallback* aCallback);
|
||||
bool InitMediaCodecProxy();
|
||||
|
||||
nsresult CreateAudioData(int64_t aStreamOffset,
|
||||
AudioData** aOutData);
|
||||
|
||||
void ReleaseAudioBuffer();
|
||||
|
||||
int64_t mLastDecodedTime;
|
||||
|
||||
uint32_t mAudioChannels;
|
||||
uint32_t mAudioRate;
|
||||
const uint32_t mAudioProfile;
|
||||
|
||||
MediaDataDecoderCallback* mReaderCallback;
|
||||
android::MediaBuffer* mAudioBuffer;
|
||||
android::sp<ALooper> mLooper;
|
||||
|
||||
// This monitor protects mQueueSample.
|
||||
Monitor mMonitor;
|
||||
|
||||
// An queue with the MP4 samples which are waiting to be sent into OMX.
|
||||
// If an element is an empty MP4Sample, that menas EOS. There should not
|
||||
// any sample be queued after EOS.
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
#include "nsTArray.h"
|
||||
#include "MediaCodecProxy.h"
|
||||
|
||||
#include <stagefright/foundation/ADebug.h>
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include <android/log.h>
|
||||
#define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__)
|
||||
#define INPUT_TIMEOUT_US 0LL // Don't wait for buffer if none is available.
|
||||
#define MIN_QUEUED_SAMPLES 2
|
||||
|
||||
extern PRLogModuleInfo* GetPDMLog();
|
||||
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
@ -19,6 +23,103 @@ using namespace android;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
GonkDecoderManager::InitLoopers(MediaData::Type aType)
|
||||
{
|
||||
MOZ_ASSERT(mDecodeLooper.get() == nullptr && mTaskLooper.get() == nullptr);
|
||||
MOZ_ASSERT(aType == MediaData::VIDEO_DATA || aType == MediaData::AUDIO_DATA);
|
||||
|
||||
const char* suffix = (aType == MediaData::VIDEO_DATA ? "video" : "audio");
|
||||
mDecodeLooper = new ALooper;
|
||||
android::AString name("MediaCodecProxy/");
|
||||
name.append(suffix);
|
||||
mDecodeLooper->setName(name.c_str());
|
||||
|
||||
mTaskLooper = new ALooper;
|
||||
name.setTo("GonkDecoderManager/");
|
||||
name.append(suffix);
|
||||
mTaskLooper->setName(name.c_str());
|
||||
mTaskLooper->registerHandler(this);
|
||||
|
||||
return mDecodeLooper->start() == OK && mTaskLooper->start() == OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (aSample) {
|
||||
sample = aSample;
|
||||
} else {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
}
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mQueuedSamples.AppendElement(sample);
|
||||
}
|
||||
|
||||
sp<AMessage> input = new AMessage(kNotifyProcessInput, id());
|
||||
if (!aSample) {
|
||||
input->setInt32("input-eos", 1);
|
||||
}
|
||||
input->post();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
GonkDecoderManager::ProcessQueuedSamples()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
status_t rv;
|
||||
while (mQueuedSamples.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueuedSamples.ElementAt(0);
|
||||
{
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0,
|
||||
INPUT_TIMEOUT_US);
|
||||
}
|
||||
if (rv == OK) {
|
||||
mQueuedSamples.RemoveElementAt(0);
|
||||
mWaitOutput.AppendElement(data->mOffset);
|
||||
} else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
|
||||
// In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
|
||||
// buffer on time.
|
||||
break;
|
||||
} else {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return mQueuedSamples.Length();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Flush()
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GMDD_LOG("Decoder is not initialized");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mQueuedSamples.Clear();
|
||||
}
|
||||
|
||||
mLastTime = 0;
|
||||
|
||||
MonitorAutoLock lock(mFlushMonitor);
|
||||
mIsFlushing = true;
|
||||
sp<AMessage> flush = new AMessage(kNotifyProcessFlush, id());
|
||||
flush->post();
|
||||
while (mIsFlushing) {
|
||||
lock.Wait();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Shutdown()
|
||||
{
|
||||
|
@ -33,16 +134,135 @@ GonkDecoderManager::Shutdown()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
GonkDecoderManager::HasQueuedSample()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mQueuedSamples.Length();
|
||||
}
|
||||
|
||||
void
|
||||
GonkDecoderManager::ProcessInput(bool aEndOfStream)
|
||||
{
|
||||
status_t rv = ProcessQueuedSamples();
|
||||
if (rv >= 0) {
|
||||
if (!aEndOfStream && rv <= MIN_QUEUED_SAMPLES) {
|
||||
mDecodeCallback->InputExhausted();
|
||||
}
|
||||
|
||||
if (mToDo.get() == nullptr) {
|
||||
mToDo = new AMessage(kNotifyDecoderActivity, id());
|
||||
if (aEndOfStream) {
|
||||
mToDo->setInt32("input-eos", 1);
|
||||
}
|
||||
mDecoder->requestActivityNotification(mToDo);
|
||||
}
|
||||
} else {
|
||||
GMDD_LOG("input processed: error#%d", rv);
|
||||
mDecodeCallback->Error();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkDecoderManager::ProcessFlush()
|
||||
{
|
||||
MonitorAutoLock lock(mFlushMonitor);
|
||||
mWaitOutput.Clear();
|
||||
if (mDecoder->flush() != OK) {
|
||||
GMDD_LOG("flush error");
|
||||
mDecodeCallback->Error();
|
||||
}
|
||||
mIsFlushing = false;
|
||||
lock.NotifyAll();
|
||||
}
|
||||
|
||||
void
|
||||
GonkDecoderManager::ProcessToDo(bool aEndOfStream)
|
||||
{
|
||||
MOZ_ASSERT(mToDo.get() != nullptr);
|
||||
mToDo.clear();
|
||||
|
||||
if (HasQueuedSample()) {
|
||||
status_t pendingInput = ProcessQueuedSamples();
|
||||
if (pendingInput < 0) {
|
||||
mDecodeCallback->Error();
|
||||
return;
|
||||
}
|
||||
if (!aEndOfStream && pendingInput <= MIN_QUEUED_SAMPLES) {
|
||||
mDecodeCallback->InputExhausted();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
while (mWaitOutput.Length() > 0) {
|
||||
nsRefPtr<MediaData> output;
|
||||
int64_t offset = mWaitOutput.ElementAt(0);
|
||||
rv = Output(offset, output);
|
||||
if (rv == NS_OK) {
|
||||
mWaitOutput.RemoveElementAt(0);
|
||||
mDecodeCallback->Output(output);
|
||||
} else if (rv == NS_ERROR_ABORT) {
|
||||
GMDD_LOG("eos output");
|
||||
mWaitOutput.RemoveElementAt(0);
|
||||
MOZ_ASSERT(mQueuedSamples.IsEmpty());
|
||||
MOZ_ASSERT(mWaitOutput.IsEmpty());
|
||||
// EOS
|
||||
if (output) {
|
||||
mDecodeCallback->Output(output);
|
||||
}
|
||||
mDecodeCallback->DrainComplete();
|
||||
return;
|
||||
} else if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
break;
|
||||
} else {
|
||||
mDecodeCallback->Error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasQueuedSample() || mWaitOutput.Length() > 0) {
|
||||
mToDo = new AMessage(kNotifyDecoderActivity, id());
|
||||
mDecoder->requestActivityNotification(mToDo);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
switch (aMessage->what()) {
|
||||
case kNotifyProcessInput:
|
||||
{
|
||||
int32_t eos = 0;
|
||||
ProcessInput(aMessage->findInt32("input-eos", &eos) && eos);
|
||||
break;
|
||||
}
|
||||
case kNotifyProcessFlush:
|
||||
{
|
||||
ProcessFlush();
|
||||
break;
|
||||
}
|
||||
case kNotifyDecoderActivity:
|
||||
{
|
||||
int32_t eos = 0;
|
||||
ProcessToDo(aMessage->findInt32("input-eos", &eos) && eos);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
TRESPASS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
|
||||
FlushableTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mTaskQueue(aTaskQueue)
|
||||
, mCallback(aCallback)
|
||||
, mManager(aManager)
|
||||
, mSignaledEOS(false)
|
||||
, mDrainComplete(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkMediaDataDecoder);
|
||||
mManager->SetDecodeCallback(aCallback);
|
||||
}
|
||||
|
||||
GonkMediaDataDecoder::~GonkMediaDataDecoder()
|
||||
|
@ -53,9 +273,7 @@ GonkMediaDataDecoder::~GonkMediaDataDecoder()
|
|||
nsRefPtr<MediaDataDecoder::InitPromise>
|
||||
GonkMediaDataDecoder::Init()
|
||||
{
|
||||
mDrainComplete = false;
|
||||
|
||||
return mManager->Init(mCallback);
|
||||
return mManager->Init();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -73,79 +291,10 @@ GonkMediaDataDecoder::Shutdown()
|
|||
nsresult
|
||||
GonkMediaDataDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(
|
||||
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
|
||||
this,
|
||||
&GonkMediaDataDecoder::ProcessDecode,
|
||||
nsRefPtr<MediaRawData>(aSample)));
|
||||
mTaskQueue->Dispatch(runnable.forget());
|
||||
mManager->Input(aSample);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ProcessDecode(MediaRawData* aSample)
|
||||
{
|
||||
nsresult rv = mManager->Input(aSample);
|
||||
if (rv != NS_OK) {
|
||||
NS_WARNING("GonkMediaDataDecoder failed to input data");
|
||||
GMDD_LOG("Failed to input data err: %d",int(rv));
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
if (aSample) {
|
||||
mLastStreamOffset = aSample->mOffset;
|
||||
}
|
||||
ProcessOutput();
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ProcessOutput()
|
||||
{
|
||||
nsRefPtr<MediaData> output;
|
||||
nsresult rv = NS_ERROR_ABORT;
|
||||
|
||||
while (!mDrainComplete) {
|
||||
// There are samples in queue, try to send them into decoder when EOS.
|
||||
if (mSignaledEOS && mManager->HasQueuedSample()) {
|
||||
GMDD_LOG("ProcessOutput: drain all input samples");
|
||||
rv = mManager->Input(nullptr);
|
||||
}
|
||||
rv = mManager->Output(mLastStreamOffset, output);
|
||||
if (rv == NS_OK) {
|
||||
mCallback->Output(output);
|
||||
continue;
|
||||
} else if (rv == NS_ERROR_NOT_AVAILABLE && mSignaledEOS) {
|
||||
// Try to get more frames before getting EOS frame
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE && !mSignaledEOS) {
|
||||
mCallback->InputExhausted();
|
||||
return;
|
||||
}
|
||||
if (rv != NS_OK) {
|
||||
NS_WARNING("GonkMediaDataDecoder failed to output data");
|
||||
GMDD_LOG("Failed to output data");
|
||||
// GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached.
|
||||
if (rv == NS_ERROR_ABORT) {
|
||||
if (output) {
|
||||
mCallback->Output(output);
|
||||
}
|
||||
mCallback->DrainComplete();
|
||||
MOZ_ASSERT_IF(mSignaledEOS, !mManager->HasQueuedSample());
|
||||
mSignaledEOS = false;
|
||||
mDrainComplete = true;
|
||||
return;
|
||||
}
|
||||
GMDD_LOG("Callback error!");
|
||||
mCallback->Error();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkMediaDataDecoder::Flush()
|
||||
{
|
||||
|
@ -154,25 +303,13 @@ GonkMediaDataDecoder::Flush()
|
|||
// it's executing at all. Note the MP4Reader ignores all output while
|
||||
// flushing.
|
||||
mTaskQueue->Flush();
|
||||
mDrainComplete = false;
|
||||
return mManager->Flush();
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ProcessDrain()
|
||||
{
|
||||
// Notify decoder input EOS by sending a null data.
|
||||
ProcessDecode(nullptr);
|
||||
mSignaledEOS = true;
|
||||
ProcessOutput();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkMediaDataDecoder::Drain()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &GonkMediaDataDecoder::ProcessDrain);
|
||||
mTaskQueue->Dispatch(runnable.forget());
|
||||
mManager->Input(nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#if !defined(GonkMediaDataDecoder_h_)
|
||||
#define GonkMediaDataDecoder_h_
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include <stagefright/foundation/AHandler.h>
|
||||
|
||||
namespace android {
|
||||
struct ALooper;
|
||||
class MediaCodecProxy;
|
||||
} // namespace android
|
||||
|
||||
|
@ -16,7 +18,7 @@ namespace mozilla {
|
|||
class MediaRawData;
|
||||
|
||||
// Manage the data flow from inputting encoded data and outputting decode data.
|
||||
class GonkDecoderManager {
|
||||
class GonkDecoderManager : public android::AHandler {
|
||||
public:
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
typedef MediaDataDecoder::InitPromise InitPromise;
|
||||
|
@ -24,39 +26,99 @@ public:
|
|||
|
||||
virtual ~GonkDecoderManager() {}
|
||||
|
||||
virtual nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) = 0;
|
||||
virtual nsRefPtr<InitPromise> Init() = 0;
|
||||
|
||||
// Add samples into OMX decoder or queue them if decoder is out of input buffer.
|
||||
virtual nsresult Input(MediaRawData* aSample) = 0;
|
||||
|
||||
// Produces decoded output, it blocks until output can be produced or a timeout
|
||||
// is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
|
||||
// if there's not enough data to produce more output. If this returns a failure
|
||||
// code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the
|
||||
// MP4Reader.
|
||||
// The overrided class should follow the same behaviour.
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) = 0;
|
||||
// Asynchronously send sample into mDecoder. If out of input buffer, aSample
|
||||
// will be queued for later re-send.
|
||||
nsresult Input(MediaRawData* aSample);
|
||||
|
||||
// Flush the queued sample.
|
||||
virtual nsresult Flush() = 0;
|
||||
nsresult Flush();
|
||||
|
||||
// Shutdown decoder and rejects the init promise.
|
||||
nsresult Shutdown();
|
||||
|
||||
// True if sample is queued.
|
||||
virtual bool HasQueuedSample() = 0;
|
||||
bool HasQueuedSample();
|
||||
|
||||
// Set callback for decoder events, such as requesting more input,
|
||||
// returning output, or reporting error.
|
||||
void SetDecodeCallback(MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
mDecodeCallback = aCallback;
|
||||
}
|
||||
|
||||
protected:
|
||||
GonkDecoderManager()
|
||||
: mMutex("GonkDecoderManager")
|
||||
, mLastTime(0)
|
||||
, mFlushMonitor("GonkDecoderManager::Flush")
|
||||
, mIsFlushing(false)
|
||||
, mDecodeCallback(nullptr)
|
||||
{}
|
||||
|
||||
bool InitLoopers(MediaData::Type aType);
|
||||
|
||||
void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
|
||||
|
||||
// Produces decoded output. It returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
|
||||
// when output is not produced yet.
|
||||
// If this returns a failure code other than NS_ERROR_NOT_AVAILABLE, an error
|
||||
// will be reported through mDecodeCallback.
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) = 0;
|
||||
|
||||
// Send queued samples to OMX. It returns how many samples are still in
|
||||
// queue after processing, or negtive error code if failed.
|
||||
int32_t ProcessQueuedSamples();
|
||||
|
||||
void ProcessInput(bool aEndOfStream);
|
||||
void ProcessFlush();
|
||||
void ProcessToDo(bool aEndOfStream);
|
||||
|
||||
nsRefPtr<MediaByteBuffer> mCodecSpecificData;
|
||||
|
||||
nsAutoCString mMimeType;
|
||||
|
||||
// MediaCodedc's wrapper that performs the decoding.
|
||||
android::sp<android::MediaCodecProxy> mDecoder;
|
||||
// Looper for mDecoder to run on.
|
||||
android::sp<android::ALooper> mDecodeLooper;
|
||||
// Looper to run decode tasks such as processing input, output, flush, and
|
||||
// recycling output buffers.
|
||||
android::sp<android::ALooper> mTaskLooper;
|
||||
enum {
|
||||
// Decoder will send this to indicate internal state change such as input or
|
||||
// output buffers availability. Used to run pending input & output tasks.
|
||||
kNotifyDecoderActivity = 'nda ',
|
||||
// Signal the decoder to flush.
|
||||
kNotifyProcessFlush = 'npf ',
|
||||
// Used to process queued samples when there is new input.
|
||||
kNotifyProcessInput = 'npi ',
|
||||
};
|
||||
|
||||
MozPromiseHolder<InitPromise> mInitPromise;
|
||||
|
||||
Mutex mMutex; // Protects mQueuedSamples.
|
||||
// A queue that stores the samples waiting to be sent to mDecoder.
|
||||
// Empty element means EOS and there shouldn't be any sample be queued after it.
|
||||
// Samples are queued in caller's thread and dequeued in mTaskLooper.
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueuedSamples;
|
||||
|
||||
int64_t mLastTime; // The last decoded frame presentation time.
|
||||
|
||||
Monitor mFlushMonitor; // Waits for flushing to complete.
|
||||
bool mIsFlushing;
|
||||
|
||||
// Remembers the notification that is currently waiting for the decoder event
|
||||
// to avoid requesting more than one notification at the time, which is
|
||||
// forbidden by mDecoder.
|
||||
android::sp<android::AMessage> mToDo;
|
||||
|
||||
// Stores the offset of every output that needs to be read from mDecoder.
|
||||
nsTArray<int64_t> mWaitOutput;
|
||||
|
||||
MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error.
|
||||
};
|
||||
|
||||
// Samples are decoded using the GonkDecoder (MediaCodec)
|
||||
|
@ -83,33 +145,9 @@ public:
|
|||
nsresult Shutdown() override;
|
||||
|
||||
private:
|
||||
|
||||
// Called on the task queue. Inserts the sample into the decoder, and
|
||||
// extracts output if available, if aSample is null, it means there is
|
||||
// no data from source, it will notify the decoder EOS and flush all the
|
||||
// decoded frames.
|
||||
void ProcessDecode(MediaRawData* aSample);
|
||||
|
||||
// Called on the task queue. Extracts output if available, and delivers
|
||||
// it to the reader. Called after ProcessDecode() and ProcessDrain().
|
||||
void ProcessOutput();
|
||||
|
||||
// Called on the task queue. Orders the Gonk to drain, and then extracts
|
||||
// all available output.
|
||||
void ProcessDrain();
|
||||
|
||||
RefPtr<FlushableTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
nsAutoPtr<GonkDecoderManager> mManager;
|
||||
|
||||
// The last offset into the media resource that was passed into Input().
|
||||
// This is used to approximate the decoder's position in the media resource.
|
||||
int64_t mLastStreamOffset;
|
||||
// Set it ture when there is no input data
|
||||
bool mSignaledEOS;
|
||||
// Set if there is no more output data from decoder
|
||||
bool mDrainComplete;
|
||||
android::sp<GonkDecoderManager> mManager;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -17,17 +17,15 @@
|
|||
#include "stagefright/MediaBuffer.h"
|
||||
#include "stagefright/MetaData.h"
|
||||
#include "stagefright/MediaErrors.h"
|
||||
#include <stagefright/foundation/ADebug.h>
|
||||
#include <stagefright/foundation/AMessage.h>
|
||||
#include <stagefright/foundation/AString.h>
|
||||
#include <stagefright/foundation/ALooper.h>
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000
|
||||
#define CODECCONFIG_TIMEOUT_US 10000LL
|
||||
#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL
|
||||
|
||||
#include <android/log.h>
|
||||
#define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__)
|
||||
|
@ -44,12 +42,9 @@ GonkVideoDecoderManager::GonkVideoDecoderManager(
|
|||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
const VideoInfo& aConfig)
|
||||
: mImageContainer(aImageContainer)
|
||||
, mReaderCallback(nullptr)
|
||||
, mLastDecodedTime(0)
|
||||
, mColorConverterBufferSize(0)
|
||||
, mNativeWindow(nullptr)
|
||||
, mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock")
|
||||
, mMonitor("GonkVideoDecoderManager")
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkVideoDecoderManager);
|
||||
mMimeType = aConfig.mMimeType;
|
||||
|
@ -64,7 +59,6 @@ GonkVideoDecoderManager::GonkVideoDecoderManager(
|
|||
nsIntSize frameSize(mVideoWidth, mVideoHeight);
|
||||
mPicture = pictureRect;
|
||||
mInitialFrame = frameSize;
|
||||
mHandler = new MessageHandler(this);
|
||||
mVideoListener = new VideoResourceListener(this);
|
||||
|
||||
}
|
||||
|
@ -76,7 +70,7 @@ GonkVideoDecoderManager::~GonkVideoDecoderManager()
|
|||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder::InitPromise>
|
||||
GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
GonkVideoDecoderManager::Init()
|
||||
{
|
||||
nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
|
||||
nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
|
||||
|
@ -101,26 +95,19 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
mReaderCallback = aCallback;
|
||||
|
||||
mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue();
|
||||
MOZ_ASSERT(mReaderTaskQueue);
|
||||
|
||||
if (mLooper.get() != nullptr) {
|
||||
if (mDecodeLooper.get() != nullptr) {
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
// Create ALooper
|
||||
mLooper = new ALooper;
|
||||
mManagerLooper = new ALooper;
|
||||
mManagerLooper->setName("GonkVideoDecoderManager");
|
||||
// Register AMessage handler to ALooper.
|
||||
mManagerLooper->registerHandler(mHandler);
|
||||
// Start ALooper thread.
|
||||
if (mLooper->start() != OK || mManagerLooper->start() != OK ) {
|
||||
|
||||
if (!InitLoopers(MediaData::VIDEO_DATA)) {
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
nsRefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, mVideoListener);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, mVideoListener);
|
||||
mDecoder->AsyncAskMediaCodec();
|
||||
|
||||
uint32_t capability = MediaCodecProxy::kEmptyCapability;
|
||||
|
@ -132,52 +119,6 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
return p;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (!aSample) {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
} else {
|
||||
sample = aSample;
|
||||
}
|
||||
|
||||
mQueueSample.AppendElement(sample);
|
||||
|
||||
status_t rv;
|
||||
while (mQueueSample.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
MonitorAutoUnlock mon_unlock(mMonitor);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
if (rv == OK) {
|
||||
mQueueSample.RemoveElementAt(0);
|
||||
} else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
|
||||
// In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
|
||||
// buffer on time.
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
GonkVideoDecoderManager::HasQueuedSample()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return mQueueSample.Length();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
||||
{
|
||||
|
@ -197,12 +138,12 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mLastDecodedTime > timeUs) {
|
||||
if (mLastTime > timeUs) {
|
||||
ReleaseVideoBuffer();
|
||||
GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastDecodedTime = timeUs;
|
||||
mLastTime = timeUs;
|
||||
|
||||
if (mVideoBuffer->range_length() == 0) {
|
||||
// Some decoders may return spurious empty buffers that we just want to ignore
|
||||
|
@ -367,27 +308,6 @@ GonkVideoDecoderManager::SetVideoFormat()
|
|||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Flush()
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GVDM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
}
|
||||
|
||||
mLastDecodedTime = 0;
|
||||
|
||||
if (mDecoder->flush() != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Blocks until decoded sample is produced by the deoder.
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
|
@ -497,7 +417,8 @@ GonkVideoDecoderManager::codecReserved()
|
|||
if (mMimeType.EqualsLiteral("video/mp4v-es")) {
|
||||
rv = mDecoder->Input(mCodecSpecificData->Elements(),
|
||||
mCodecSpecificData->Length(), 0,
|
||||
android::MediaCodec::BUFFER_FLAG_CODECCONFIG);
|
||||
android::MediaCodec::BUFFER_FLAG_CODECCONFIG,
|
||||
CODECCONFIG_TIMEOUT_US);
|
||||
}
|
||||
|
||||
if (rv != OK) {
|
||||
|
@ -516,7 +437,7 @@ GonkVideoDecoderManager::codecCanceled()
|
|||
mInitPromise.RejectIfExists(DecoderFailureReason::CANCELED, __func__);
|
||||
}
|
||||
|
||||
// Called on GonkVideoDecoderManager::mManagerLooper thread.
|
||||
// Called on GonkDecoderManager::mTaskLooper thread.
|
||||
void
|
||||
GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
|
@ -528,26 +449,10 @@ GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
|||
}
|
||||
|
||||
default:
|
||||
TRESPASS();
|
||||
{
|
||||
GonkDecoderManager::onMessageReceived(aMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GonkVideoDecoderManager::MessageHandler::MessageHandler(GonkVideoDecoderManager *aManager)
|
||||
: mManager(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
GonkVideoDecoderManager::MessageHandler::~MessageHandler()
|
||||
{
|
||||
mManager = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::MessageHandler::onMessageReceived(const android::sp<android::AMessage> &aMessage)
|
||||
{
|
||||
if (mManager != nullptr) {
|
||||
mManager->onMessageReceived(aMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -652,7 +557,7 @@ void GonkVideoDecoderManager::PostReleaseVideoBuffer(
|
|||
}
|
||||
}
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyPostReleaseBuffer, mHandler->id());
|
||||
new AMessage(kNotifyPostReleaseBuffer, id());
|
||||
notify->post();
|
||||
|
||||
}
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
#if !defined(GonkVideoDecoderManager_h_)
|
||||
#define GonkVideoDecoderManager_h_
|
||||
|
||||
#include <set>
|
||||
#include "nsRect.h"
|
||||
#include "GonkMediaDataDecoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "I420ColorConverterHelper.h"
|
||||
#include "MediaCodecProxy.h"
|
||||
#include <stagefright/foundation/AHandler.h>
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
#include "mozilla/layers/FenceUtils.h"
|
||||
|
@ -22,7 +20,6 @@
|
|||
using namespace android;
|
||||
|
||||
namespace android {
|
||||
struct ALooper;
|
||||
class MediaBuffer;
|
||||
struct MOZ_EXPORT AString;
|
||||
class GonkNativeWindow;
|
||||
|
@ -42,19 +39,13 @@ public:
|
|||
GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer,
|
||||
const VideoInfo& aConfig);
|
||||
|
||||
virtual ~GonkVideoDecoderManager() override;
|
||||
virtual ~GonkVideoDecoderManager();
|
||||
|
||||
nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
nsresult Input(MediaRawData* aSample) override;
|
||||
nsRefPtr<InitPromise> Init() override;
|
||||
|
||||
nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) override;
|
||||
|
||||
nsresult Flush() override;
|
||||
|
||||
bool HasQueuedSample() override;
|
||||
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
private:
|
||||
|
@ -70,23 +61,8 @@ private:
|
|||
int32_t mCropRight = 0;
|
||||
int32_t mCropBottom = 0;
|
||||
};
|
||||
class MessageHandler : public android::AHandler
|
||||
{
|
||||
public:
|
||||
MessageHandler(GonkVideoDecoderManager *aManager);
|
||||
~MessageHandler();
|
||||
|
||||
void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
|
||||
|
||||
private:
|
||||
// Forbidden
|
||||
MessageHandler() = delete;
|
||||
MessageHandler(const MessageHandler &rhs) = delete;
|
||||
const MessageHandler &operator=(const MessageHandler &rhs) = delete;
|
||||
|
||||
GonkVideoDecoderManager *mManager;
|
||||
};
|
||||
friend class MessageHandler;
|
||||
void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
|
||||
|
||||
class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
|
||||
{
|
||||
|
@ -119,7 +95,6 @@ private:
|
|||
// For codec resource management
|
||||
void codecReserved();
|
||||
void codecCanceled();
|
||||
void onMessageReceived(const sp<AMessage> &aMessage);
|
||||
|
||||
void ReleaseAllPendingVideoBuffers();
|
||||
void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer,
|
||||
|
@ -136,16 +111,10 @@ private:
|
|||
|
||||
android::MediaBuffer* mVideoBuffer;
|
||||
|
||||
MediaDataDecoderCallback* mReaderCallback;
|
||||
MediaInfo mInfo;
|
||||
android::sp<VideoResourceListener> mVideoListener;
|
||||
android::sp<MessageHandler> mHandler;
|
||||
android::sp<ALooper> mLooper;
|
||||
android::sp<ALooper> mManagerLooper;
|
||||
FrameInfo mFrameInfo;
|
||||
|
||||
int64_t mLastDecodedTime; // The last decoded frame presentation time.
|
||||
|
||||
// color converter
|
||||
android::I420ColorConverterHelper mColorConverter;
|
||||
nsAutoArrayPtr<uint8_t> mColorConverterBuffer;
|
||||
|
@ -168,17 +137,9 @@ private:
|
|||
// The lock protects mPendingReleaseItems.
|
||||
Mutex mPendingReleaseItemsLock;
|
||||
|
||||
// This monitor protects mQueueSample.
|
||||
Monitor mMonitor;
|
||||
|
||||
// This TaskQueue should be the same one in mReaderCallback->OnReaderTaskQueue().
|
||||
// This TaskQueue should be the same one in mDecodeCallback->OnReaderTaskQueue().
|
||||
// It is for codec resource mangement, decoding task should not dispatch to it.
|
||||
nsRefPtr<TaskQueue> mReaderTaskQueue;
|
||||
|
||||
// An queue with the MP4 samples which are waiting to be sent into OMX.
|
||||
// If an element is an empty MP4Sample, that menas EOS. There should not
|
||||
// any sample be queued after EOS.
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -230,26 +230,34 @@ public:
|
|||
|
||||
aOutput->AllocateChannels(channelCount);
|
||||
for (uint32_t i = 0; i < channelCount; ++i) {
|
||||
float* scaledSample = (float *)(aInput.mChannelData[i]);
|
||||
AudioBlockInPlaceScale(scaledSample, aInput.mVolume);
|
||||
const float* inputBuffer = static_cast<const float*>(scaledSample);
|
||||
const float* inputSamples;
|
||||
float scaledInput[WEBAUDIO_BLOCK_SIZE];
|
||||
if (aInput.mVolume != 1.0f) {
|
||||
AudioBlockCopyChannelWithScale(
|
||||
static_cast<const float*>(aInput.mChannelData[i]),
|
||||
aInput.mVolume,
|
||||
scaledInput);
|
||||
inputSamples = scaledInput;
|
||||
} else {
|
||||
inputSamples = static_cast<const float*>(aInput.mChannelData[i]);
|
||||
}
|
||||
float* outputBuffer = aOutput->ChannelFloatsForWrite(i);
|
||||
float* sampleBuffer;
|
||||
|
||||
switch (mType) {
|
||||
case OverSampleType::None:
|
||||
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::None);
|
||||
ProcessCurve<1>(inputBuffer, outputBuffer);
|
||||
ProcessCurve<1>(inputSamples, outputBuffer);
|
||||
break;
|
||||
case OverSampleType::_2x:
|
||||
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::_2x);
|
||||
sampleBuffer = mResampler.UpSample(i, inputBuffer, 2);
|
||||
sampleBuffer = mResampler.UpSample(i, inputSamples, 2);
|
||||
ProcessCurve<2>(sampleBuffer, sampleBuffer);
|
||||
mResampler.DownSample(i, outputBuffer, 2);
|
||||
break;
|
||||
case OverSampleType::_4x:
|
||||
mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::_4x);
|
||||
sampleBuffer = mResampler.UpSample(i, inputBuffer, 4);
|
||||
sampleBuffer = mResampler.UpSample(i, inputSamples, 4);
|
||||
ProcessCurve<4>(sampleBuffer, sampleBuffer);
|
||||
mResampler.DownSample(i, outputBuffer, 4);
|
||||
break;
|
||||
|
|
|
@ -172,6 +172,7 @@ skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' || android_ve
|
|||
[test_stereoPanningWithGain.html]
|
||||
[test_waveDecoder.html]
|
||||
[test_waveShaper.html]
|
||||
[test_waveShaperGain.html]
|
||||
[test_waveShaperNoCurve.html]
|
||||
[test_waveShaperPassThrough.html]
|
||||
[test_waveShaperInvalidLengthCurve.html]
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that WaveShaperNode doesn't corrupt its inputs when the gain is !=
|
||||
1.0 (bug 1203616)</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var samplerate = 44100;
|
||||
var context = new OfflineAudioContext(1, 44100, samplerate);
|
||||
|
||||
var dc = context.createBufferSource();
|
||||
|
||||
var buffer = context.createBuffer(1, 1, samplerate);
|
||||
buffer.getChannelData(0)[0] = 1.0;
|
||||
dc.buffer = buffer;
|
||||
|
||||
var gain = context.createGain();
|
||||
var ws2 = context.createWaveShaper();
|
||||
var ws = [];
|
||||
|
||||
// No-op waveshaper curves.
|
||||
for (var i = 0; i < 2; i++) {
|
||||
ws[i] = context.createWaveShaper();
|
||||
var curve = new Float32Array(2);
|
||||
curve[0] = -1.0;
|
||||
curve[1] = 1.0;
|
||||
ws[i].curve = curve;
|
||||
ws[i].connect(context.destination);
|
||||
gain.connect(ws[i]);
|
||||
}
|
||||
|
||||
dc.connect(gain);
|
||||
dc.start();
|
||||
|
||||
gain.gain.value = 0.5;
|
||||
|
||||
context.startRendering().then(buffer => {
|
||||
document.querySelector("pre").innerHTML = buffer.getChannelData(0)[0];
|
||||
ok(buffer.getChannelData(0)[0] == 1.0, "Volume was handled properly");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
<pre>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
@ -462,9 +462,9 @@ WebMDemuxer::EnsureUpToDateIndex()
|
|||
}
|
||||
|
||||
void
|
||||
WebMDemuxer::NotifyDataArrived(uint32_t aLength, int64_t aOffset)
|
||||
WebMDemuxer::NotifyDataArrived()
|
||||
{
|
||||
WEBM_DEBUG("length: %ld offset: %ld", aLength, aOffset);
|
||||
WEBM_DEBUG("");
|
||||
mNeedReIndex = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ private:
|
|||
void Cleanup();
|
||||
void InitBufferedState();
|
||||
nsresult ReadMetadata();
|
||||
void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
|
||||
void NotifyDataArrived() override;
|
||||
void NotifyDataRemoved() override;
|
||||
void EnsureUpToDateIndex();
|
||||
media::TimeIntervals GetBuffered();
|
||||
|
|
|
@ -168,7 +168,7 @@ PresentationReceiver::NotifySessionConnect(uint64_t aWindowId,
|
|||
|
||||
nsRefPtr<PresentationSession> session =
|
||||
PresentationSession::Create(GetOwner(), aSessionId,
|
||||
PresentationSessionState::Disconnected);
|
||||
PresentationSessionState::Closed);
|
||||
if (NS_WARN_IF(!session)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ PresentationService::SendSessionMessage(const nsAString& aSessionId,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::Terminate(const nsAString& aSessionId)
|
||||
PresentationService::CloseSession(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
@ -439,7 +439,21 @@ PresentationService::Terminate(const nsAString& aSessionId)
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return info->Close(NS_OK);
|
||||
return info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::TerminateSession(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -495,7 +509,7 @@ PresentationService::UnregisterSessionListener(const nsAString& aSessionId)
|
|||
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (info) {
|
||||
NS_WARN_IF(NS_FAILED(info->Close(NS_OK)));
|
||||
NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED)));
|
||||
UntrackSessionInfo(aSessionId);
|
||||
return info->SetListener(nullptr);
|
||||
}
|
||||
|
|
|
@ -142,31 +142,44 @@ PresentationSession::Send(const nsAString& aData,
|
|||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = service->SendSessionMessage(mId, stream);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresentationSession::Close()
|
||||
PresentationSession::Close(ErrorResult& aRv)
|
||||
{
|
||||
// Closing does nothing if the session is already terminated.
|
||||
if (NS_WARN_IF(mState == PresentationSessionState::Terminated)) {
|
||||
// It only works when the state is CONNECTED.
|
||||
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Bug 1210340 - Support close semantics.
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
void
|
||||
PresentationSession::Terminate(ErrorResult& aRv)
|
||||
{
|
||||
// It only works when the state is CONNECTED.
|
||||
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(NS_FAILED(service->Terminate(mId)));
|
||||
NS_WARN_IF(NS_FAILED(service->TerminateSession(mId)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -182,8 +195,8 @@ PresentationSession::NotifyStateChange(const nsAString& aSessionId,
|
|||
case nsIPresentationSessionListener::STATE_CONNECTED:
|
||||
state = PresentationSessionState::Connected;
|
||||
break;
|
||||
case nsIPresentationSessionListener::STATE_DISCONNECTED:
|
||||
state = PresentationSessionState::Disconnected;
|
||||
case nsIPresentationSessionListener::STATE_CLOSED:
|
||||
state = PresentationSessionState::Closed;
|
||||
break;
|
||||
case nsIPresentationSessionListener::STATE_TERMINATED:
|
||||
state = PresentationSessionState::Terminated;
|
||||
|
|
|
@ -23,10 +23,9 @@ public:
|
|||
DOMEventTargetHelper)
|
||||
NS_DECL_NSIPRESENTATIONSESSIONLISTENER
|
||||
|
||||
static already_AddRefed<PresentationSession>
|
||||
Create(nsPIDOMWindow* aWindow,
|
||||
const nsAString& aId,
|
||||
PresentationSessionState aState);
|
||||
static already_AddRefed<PresentationSession> Create(nsPIDOMWindow* aWindow,
|
||||
const nsAString& aId,
|
||||
PresentationSessionState aState);
|
||||
|
||||
virtual void DisconnectFromOwner() override;
|
||||
|
||||
|
@ -38,9 +37,12 @@ public:
|
|||
|
||||
PresentationSessionState State() const;
|
||||
|
||||
void Send(const nsAString& aData, ErrorResult& aRv);
|
||||
void Send(const nsAString& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Close();
|
||||
void Close(ErrorResult& aRv);
|
||||
|
||||
void Terminate(ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(statechange);
|
||||
IMPL_EVENT_HANDLER(message);
|
||||
|
|
|
@ -174,10 +174,7 @@ PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
|
|||
|
||||
// The transport might become ready, or might become un-ready again, before
|
||||
// the listener has registered. So notify the listener of the state change.
|
||||
uint16_t state = IsSessionReady() ?
|
||||
nsIPresentationSessionListener::STATE_CONNECTED :
|
||||
nsIPresentationSessionListener::STATE_DISCONNECTED;
|
||||
return mListener->NotifyStateChange(mSessionId, state);
|
||||
return mListener->NotifyStateChange(mSessionId, mState);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -198,23 +195,15 @@ PresentationSessionInfo::Send(nsIInputStream* aData)
|
|||
}
|
||||
|
||||
nsresult
|
||||
PresentationSessionInfo::Close(nsresult aReason)
|
||||
PresentationSessionInfo::Close(nsresult aReason,
|
||||
uint32_t aState)
|
||||
{
|
||||
// The session is disconnected and it's a normal close. Simply change the
|
||||
// state to TERMINATED.
|
||||
if (!IsSessionReady() && NS_SUCCEEDED(aReason)) {
|
||||
if (mListener) {
|
||||
// Notify the listener and the service will untrack the session info after
|
||||
// the listener calls |UnregisterSessionListener|.
|
||||
nsresult rv = mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
} else {
|
||||
// Directly untrack the session info from the service.
|
||||
NS_WARN_IF(NS_FAILED(UntrackFromService()));
|
||||
}
|
||||
if (NS_WARN_IF(!IsSessionReady())) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
SetState(aState);
|
||||
|
||||
Shutdown(aReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -222,12 +211,7 @@ PresentationSessionInfo::Close(nsresult aReason)
|
|||
nsresult
|
||||
PresentationSessionInfo::ReplySuccess()
|
||||
{
|
||||
if (mListener) {
|
||||
// Notify session state change.
|
||||
nsresult rv = mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_CONNECTED);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
SetState(nsIPresentationSessionListener::STATE_CONNECTED);
|
||||
|
||||
if (mCallback) {
|
||||
NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess()));
|
||||
|
@ -308,17 +292,14 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
|
|||
// Unset |mIsTransportReady| here so it won't affect |IsSessionReady()| above.
|
||||
mIsTransportReady = false;
|
||||
|
||||
if (mState == nsIPresentationSessionListener::STATE_CONNECTED) {
|
||||
// The transport channel is closed unexpectedly (not caused by a |Close| call).
|
||||
SetState(nsIPresentationSessionListener::STATE_CLOSED);
|
||||
}
|
||||
|
||||
Shutdown(aReason);
|
||||
|
||||
uint16_t state = (NS_WARN_IF(NS_FAILED(aReason))) ?
|
||||
nsIPresentationSessionListener::STATE_DISCONNECTED :
|
||||
nsIPresentationSessionListener::STATE_TERMINATED;
|
||||
if (mListener) {
|
||||
// It happens after the session is ready. Notify session state change.
|
||||
// If the new state is TERMINATED. the service will untrack the session info
|
||||
// after the listener calls |UnregisterSessionListener|.
|
||||
return mListener->NotifyStateChange(mSessionId, state);
|
||||
} else if (state == nsIPresentationSessionListener::STATE_TERMINATED) {
|
||||
if (mState == nsIPresentationSessionListener::STATE_TERMINATED) {
|
||||
// Directly untrack the session info from the service.
|
||||
return UntrackFromService();
|
||||
}
|
||||
|
@ -509,12 +490,9 @@ PresentationControllingInfo::NotifyClosed(nsresult aReason)
|
|||
SetControlChannel(nullptr);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aReason))) {
|
||||
if (mListener) {
|
||||
// The presentation session instance at receiver side may already exist.
|
||||
// Change the state to TERMINATED since it never succeeds.
|
||||
return mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
}
|
||||
// The presentation session instance may already exist.
|
||||
// Change the state to TERMINATED since it never succeeds.
|
||||
SetState(nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
|
||||
// Reply error for an abnormal close.
|
||||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
@ -566,11 +544,8 @@ PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
|
|||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
// It happens after the session is ready. Notify session state change.
|
||||
if (mListener) {
|
||||
return mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_DISCONNECTED);
|
||||
}
|
||||
// It happens after the session is ready. Change the state to CLOSED.
|
||||
SetState(nsIPresentationSessionListener::STATE_CLOSED);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -775,12 +750,9 @@ PresentationPresentingInfo::NotifyClosed(nsresult aReason)
|
|||
SetControlChannel(nullptr);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aReason))) {
|
||||
if (mListener) {
|
||||
// The presentation session instance at receiver side may already exist.
|
||||
// Change the state to TERMINATED since it never succeeds.
|
||||
return mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
}
|
||||
// The presentation session instance may already exist.
|
||||
// Change the state to TERMINATED since it never succeeds.
|
||||
SetState(nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
|
||||
// Reply error for an abnormal close.
|
||||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
, mSessionId(aSessionId)
|
||||
, mIsResponderReady(false)
|
||||
, mIsTransportReady(false)
|
||||
, mState(nsIPresentationSessionListener::STATE_CLOSED)
|
||||
, mCallback(aCallback)
|
||||
{
|
||||
MOZ_ASSERT(!mUrl.IsEmpty());
|
||||
|
@ -89,7 +90,8 @@ public:
|
|||
|
||||
nsresult Send(nsIInputStream* aData);
|
||||
|
||||
nsresult Close(nsresult aReason);
|
||||
nsresult Close(nsresult aReason,
|
||||
uint32_t aState);
|
||||
|
||||
nsresult ReplyError(nsresult aReason);
|
||||
|
||||
|
@ -112,10 +114,26 @@ protected:
|
|||
|
||||
virtual nsresult UntrackFromService();
|
||||
|
||||
void SetState(uint32_t aState)
|
||||
{
|
||||
if (mState == aState) {
|
||||
return;
|
||||
}
|
||||
|
||||
mState = aState;
|
||||
|
||||
// Notify session state change.
|
||||
if (mListener) {
|
||||
nsresult rv = mListener->NotifyStateChange(mSessionId, mState);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
}
|
||||
|
||||
nsString mUrl;
|
||||
nsString mSessionId;
|
||||
bool mIsResponderReady;
|
||||
bool mIsTransportReady;
|
||||
uint32_t mState; // CONNECTED, CLOSED, TERMINATED
|
||||
nsCOMPtr<nsIPresentationServiceCallback> mCallback;
|
||||
nsCOMPtr<nsIPresentationSessionListener> mListener;
|
||||
nsCOMPtr<nsIPresentationDevice> mDevice;
|
||||
|
|
|
@ -13,11 +13,11 @@ interface nsIPresentationAvailabilityListener : nsISupports
|
|||
void notifyAvailableChange(in bool available);
|
||||
};
|
||||
|
||||
[scriptable, uuid(3b9ae71f-2905-4969-9117-101627c1c2ea)]
|
||||
[scriptable, uuid(7dd48df8-8f8c-48c7-ac37-7b9fd1acf2f8)]
|
||||
interface nsIPresentationSessionListener : nsISupports
|
||||
{
|
||||
const unsigned short STATE_CONNECTED = 0;
|
||||
const unsigned short STATE_DISCONNECTED = 1;
|
||||
const unsigned short STATE_CLOSED = 1;
|
||||
const unsigned short STATE_TERMINATED = 2;
|
||||
|
||||
/*
|
||||
|
|
|
@ -33,7 +33,7 @@ interface nsIPresentationServiceCallback : nsISupports
|
|||
void notifyError(in nsresult error);
|
||||
};
|
||||
|
||||
[scriptable, uuid(5a254519-45c3-4229-9b16-f58c05b78fc6)]
|
||||
[scriptable, uuid(c177a13a-bf1a-48bf-8032-d415c3343c46)]
|
||||
interface nsIPresentationService : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -62,12 +62,19 @@ interface nsIPresentationService : nsISupports
|
|||
void sendSessionMessage(in DOMString sessionId,
|
||||
in nsIInputStream stream);
|
||||
|
||||
/*
|
||||
* Close the session.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
*/
|
||||
void closeSession(in DOMString sessionId);
|
||||
|
||||
/*
|
||||
* Terminate the session.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
*/
|
||||
void terminate(in DOMString sessionId);
|
||||
void terminateSession(in DOMString sessionId);
|
||||
|
||||
/*
|
||||
* Register an availability listener. Must be called from the main thread.
|
||||
|
|
|
@ -25,7 +25,12 @@ struct SendSessionMessageRequest
|
|||
InputStreamParams data;
|
||||
};
|
||||
|
||||
struct TerminateRequest
|
||||
struct CloseSessionRequest
|
||||
{
|
||||
nsString sessionId;
|
||||
};
|
||||
|
||||
struct TerminateSessionRequest
|
||||
{
|
||||
nsString sessionId;
|
||||
};
|
||||
|
@ -34,7 +39,8 @@ union PresentationIPCRequest
|
|||
{
|
||||
StartSessionRequest;
|
||||
SendSessionMessageRequest;
|
||||
TerminateRequest;
|
||||
CloseSessionRequest;
|
||||
TerminateSessionRequest;
|
||||
};
|
||||
|
||||
sync protocol PPresentation
|
||||
|
|
|
@ -71,11 +71,19 @@ PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::Terminate(const nsAString& aSessionId)
|
||||
PresentationIPCService::CloseSession(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
return SendRequest(nullptr, TerminateRequest(nsAutoString(aSessionId)));
|
||||
return SendRequest(nullptr, CloseSessionRequest(nsAutoString(aSessionId)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::TerminateSession(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
return SendRequest(nullptr, TerminateSessionRequest(nsAutoString(aSessionId)));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -74,8 +74,11 @@ PresentationParent::RecvPPresentationRequestConstructor(
|
|||
case PresentationIPCRequest::TSendSessionMessageRequest:
|
||||
rv = actor->DoRequest(aRequest.get_SendSessionMessageRequest());
|
||||
break;
|
||||
case PresentationIPCRequest::TTerminateRequest:
|
||||
rv = actor->DoRequest(aRequest.get_TerminateRequest());
|
||||
case PresentationIPCRequest::TCloseSessionRequest:
|
||||
rv = actor->DoRequest(aRequest.get_CloseSessionRequest());
|
||||
break;
|
||||
case PresentationIPCRequest::TTerminateSessionRequest:
|
||||
rv = actor->DoRequest(aRequest.get_TerminateSessionRequest());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown PresentationIPCRequest type");
|
||||
|
@ -278,7 +281,7 @@ PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
|
|||
}
|
||||
|
||||
nsresult
|
||||
PresentationRequestParent::DoRequest(const TerminateRequest& aRequest)
|
||||
PresentationRequestParent::DoRequest(const CloseSessionRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
|
@ -289,7 +292,26 @@ PresentationRequestParent::DoRequest(const TerminateRequest& aRequest)
|
|||
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
||||
nsresult rv = mService->Terminate(aRequest.sessionId());
|
||||
nsresult rv = mService->CloseSession(aRequest.sessionId());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NotifyError(rv);
|
||||
}
|
||||
return NotifySuccess();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Validate the accessibility (primarily for receiver side) so that a
|
||||
// compromised child process can't fake the ID.
|
||||
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
|
||||
IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
|
||||
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
||||
nsresult rv = mService->TerminateSession(aRequest.sessionId());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NotifyError(rv);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,9 @@ private:
|
|||
|
||||
nsresult DoRequest(const SendSessionMessageRequest& aRequest);
|
||||
|
||||
nsresult DoRequest(const TerminateRequest& aRequest);
|
||||
nsresult DoRequest(const CloseSessionRequest& aRequest);
|
||||
|
||||
nsresult DoRequest(const TerminateSessionRequest& aRequest);
|
||||
|
||||
bool mActorDestroyed;
|
||||
nsCOMPtr<nsIPresentationService> mService;
|
||||
|
|
|
@ -42,12 +42,12 @@ function testSessionAvailable() {
|
|||
session = aSession;
|
||||
|
||||
ok(session.id, "Session ID should be set: " + session.id);
|
||||
is(session.state, "disconnected", "Session state at receiver side should be disconnected by default.");
|
||||
is(session.state, "closed", "Session state at receiver side should be closed by default.");
|
||||
aResolve();
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when getting the session: " + aError);
|
||||
teardown();
|
||||
finish();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
|
@ -81,7 +81,7 @@ function testIncomingMessage() {
|
|||
});
|
||||
}
|
||||
|
||||
function testCloseSession() {
|
||||
function testTerminateSession() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
session.onstatechange = function() {
|
||||
session.onstatechange = null;
|
||||
|
@ -89,14 +89,14 @@ function testCloseSession() {
|
|||
aResolve();
|
||||
};
|
||||
|
||||
session.close();
|
||||
session.terminate();
|
||||
});
|
||||
}
|
||||
|
||||
testSessionAvailable().
|
||||
then(testSessionReady).
|
||||
then(testIncomingMessage).
|
||||
then(testCloseSession).
|
||||
then(testTerminateSession).
|
||||
then(finish);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -42,12 +42,12 @@ function testSessionAvailable() {
|
|||
session = aSession;
|
||||
|
||||
ok(session.id, "Session ID should be set: " + session.id);
|
||||
is(session.state, "disconnected", "Session state at receiver side should be disconnected by default.");
|
||||
is(session.state, "closed", "Session state at receiver side should be closed by default.");
|
||||
aResolve();
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when getting the session: " + aError);
|
||||
teardown();
|
||||
finish();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
|
@ -81,7 +81,7 @@ function testIncomingMessage() {
|
|||
});
|
||||
}
|
||||
|
||||
function testCloseSession() {
|
||||
function testTerminateSession() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
session.onstatechange = function() {
|
||||
session.onstatechange = null;
|
||||
|
@ -89,14 +89,14 @@ function testCloseSession() {
|
|||
aResolve();
|
||||
};
|
||||
|
||||
session.close();
|
||||
session.terminate();
|
||||
});
|
||||
}
|
||||
|
||||
testSessionAvailable().
|
||||
then(testSessionReady).
|
||||
then(testIncomingMessage).
|
||||
then(testCloseSession).
|
||||
then(testTerminateSession).
|
||||
then(finish);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -42,12 +42,12 @@ function testSessionAvailable() {
|
|||
session = aSession;
|
||||
|
||||
ok(session.id, "Session ID should be set: " + session.id);
|
||||
is(session.state, "disconnected", "Session state at receiver side should be disconnected by default.");
|
||||
is(session.state, "closed", "Session state at receiver side should be closed by default.");
|
||||
aResolve();
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when getting the session: " + aError);
|
||||
teardown();
|
||||
finish();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -148,7 +148,7 @@ function testIncomingMessage() {
|
|||
});
|
||||
}
|
||||
|
||||
function testCloseSession() {
|
||||
function testTerminateSession() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
|
@ -161,7 +161,7 @@ function testCloseSession() {
|
|||
aResolve();
|
||||
};
|
||||
|
||||
session.close();
|
||||
session.terminate();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ function runTests() {
|
|||
then(testStartSession).
|
||||
then(testSend).
|
||||
then(testIncomingMessage).
|
||||
then(testCloseSession).
|
||||
then(testTerminateSession).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ function testStartSession() {
|
|||
});
|
||||
}
|
||||
|
||||
function testCloseSession() {
|
||||
function testTerminateSession() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
|
@ -110,7 +110,7 @@ function testCloseSession() {
|
|||
aResolve();
|
||||
};
|
||||
|
||||
session.close();
|
||||
session.terminate();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ function runTests() {
|
|||
|
||||
testSetup().
|
||||
then(testStartSession).
|
||||
then(testCloseSession).
|
||||
then(testTerminateSession).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ function testSessionDisconnection() {
|
|||
|
||||
session.onstatechange = function() {
|
||||
session.onstatechange = null;
|
||||
is(session.state, "disconnected", "Session should be disconnected.");
|
||||
is(session.state, "closed", "Session should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
|
@ -121,18 +121,6 @@ function testSessionDisconnection() {
|
|||
});
|
||||
}
|
||||
|
||||
function testCloseSession() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
session.onstatechange = function() {
|
||||
session.onstatechange = null;
|
||||
is(session.state, "terminated", "Session should be terminated.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
session.close();
|
||||
});
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
|
||||
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
|
||||
|
@ -149,7 +137,6 @@ function runTests() {
|
|||
testSetup().
|
||||
then(testStartSession).
|
||||
then(testSessionDisconnection).
|
||||
then(testCloseSession).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
component {94b065ad-d45a-436a-b394-6dabc3cf110f} TVSimulatorService.js
|
||||
contract @mozilla.org/tv/simulatorservice;1 {94b065ad-d45a-436a-b394-6dabc3cf110f}
|
||||
TVSimulatorService @mozilla.org/tv/simulatorservice;1
|
||||
|
|
|
@ -10,10 +10,10 @@ enum PresentationSessionState
|
|||
"connected",
|
||||
|
||||
// Existing presentation, but the communication channel is inactive.
|
||||
"disconnected",
|
||||
"closed",
|
||||
|
||||
// The presentation is nonexistent anymore. It could be terminated manually,
|
||||
// or either requesting page or presenting page is no longer available.
|
||||
// or either controlling or receiving browsing context is no longer available.
|
||||
"terminated"
|
||||
};
|
||||
|
||||
|
@ -27,27 +27,24 @@ interface PresentationSession : EventTarget {
|
|||
readonly attribute DOMString id;
|
||||
|
||||
/*
|
||||
* Please refer to PresentationSessionStateEvent.webidl for the declaration of
|
||||
* PresentationSessionState.
|
||||
*
|
||||
* @value "connected", "disconnected", or "terminated".
|
||||
* @value "connected", "closed", or "terminated".
|
||||
*/
|
||||
readonly attribute PresentationSessionState state;
|
||||
|
||||
/*
|
||||
* It is called when session state changes. New state is dispatched with the
|
||||
* event.
|
||||
* It is called when session state changes.
|
||||
*/
|
||||
attribute EventHandler onstatechange;
|
||||
|
||||
/*
|
||||
* After a communication channel has been established between the requesting
|
||||
* page and the presenting page, send() is called to send message out, and the
|
||||
* event handler "onmessage" will be invoked on the remote side.
|
||||
* After a communication channel has been established between the controlling
|
||||
* and receiving context, this function is called to send message out, and the
|
||||
* event handler "onmessage" will be invoked at the remote side.
|
||||
*
|
||||
* This function only works when state equals "connected".
|
||||
* This function only works when the state is "connected".
|
||||
*
|
||||
* @data: String literal-only for current implementation.
|
||||
* TODO bug 1148307 Implement PresentationSessionTransport with DataChannel to
|
||||
* support other binary types.
|
||||
*/
|
||||
[Throws]
|
||||
void send(DOMString data);
|
||||
|
@ -58,12 +55,21 @@ interface PresentationSession : EventTarget {
|
|||
attribute EventHandler onmessage;
|
||||
|
||||
/*
|
||||
* Both the requesting page and the presenting page can close the session by
|
||||
* calling terminate(). Then, the session is destroyed and its state is
|
||||
* truned into "terminated". After getting into the state of "terminated",
|
||||
* resumeSession() is incapable of re-establishing the connection.
|
||||
* Both the controlling and receving browsing context can close the session.
|
||||
* Then, the session state should turn into "closed".
|
||||
*
|
||||
* This function does nothing if the state has already been "terminated".
|
||||
* This function only works when the state is not "connected".
|
||||
*/
|
||||
void close();
|
||||
// TODO Bug 1210340 - Support close semantics.
|
||||
// [Throws]
|
||||
// void close();
|
||||
|
||||
/*
|
||||
* Both the controlling and receving browsing context can terminate the session.
|
||||
* Then the session state should turn into "terminated".
|
||||
*
|
||||
* This function only works when the state is not "connected".
|
||||
*/
|
||||
[Throws]
|
||||
void terminate();
|
||||
};
|
||||
|
|
|
@ -2315,30 +2315,6 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
|||
ENSURE_NOT_CHILD_PROCESS;
|
||||
NS_ENSURE_ARG(aAppId != nsIScriptSecurityManager::NO_APP_ID);
|
||||
|
||||
// We begin by removing all the permissions from the DB.
|
||||
// After clearing the DB, we call AddInternal() to make sure that all
|
||||
// processes are aware of this change and the representation of the DB in
|
||||
// memory is updated.
|
||||
// We have to get all permissions associated with an application first
|
||||
// because removing entries from the permissions table while iterating over
|
||||
// it is dangerous.
|
||||
|
||||
nsAutoCString sql;
|
||||
sql.AppendLiteral("DELETE FROM moz_perms WHERE appId=");
|
||||
sql.AppendInt(aAppId);
|
||||
|
||||
if (aBrowserOnly) {
|
||||
sql.AppendLiteral(" AND isInBrowserElement=1");
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageAsyncStatement> removeStmt;
|
||||
nsresult rv = mDBConn->CreateAsyncStatement(sql, getter_AddRefs(removeStmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStoragePendingStatement> pending;
|
||||
rv = removeStmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMArray<nsIPermission> permissions;
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test() {
|
||||
// initialize the permission manager service
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
let pm = Services.perms;
|
||||
|
||||
function mkPrin(uri, appId, inBrowser) {
|
||||
return ssm.createCodebasePrincipal(Services.io.newURI(uri, null, null),
|
||||
{appId: appId, inBrowser: inBrowser});
|
||||
}
|
||||
|
||||
function checkPerms(perms) {
|
||||
perms.forEach((perm) => {
|
||||
// Look up the expected permission
|
||||
do_check_eq(pm.getPermissionObject(mkPrin(perm[0], perm[1], perm[2]),
|
||||
perm[3], true).capability,
|
||||
perm[4], "Permission is expected in the permission database");
|
||||
});
|
||||
|
||||
// Count the entries
|
||||
let count = 0;
|
||||
let enumerator = Services.perms.enumerator;
|
||||
while (enumerator.hasMoreElements()) { enumerator.getNext(); count++; }
|
||||
|
||||
do_check_eq(count, perms.length, "There should be the right number of permissions in the DB");
|
||||
}
|
||||
|
||||
checkPerms([]);
|
||||
|
||||
let permissions = [
|
||||
['http://google.com', 1001, false, 'a', 1],
|
||||
['http://google.com', 1001, false, 'b', 1],
|
||||
['http://mozilla.com', 1001, false, 'b', 1],
|
||||
['http://mozilla.com', 1001, false, 'a', 1],
|
||||
|
||||
['http://google.com', 1001, true, 'a', 1],
|
||||
['http://google.com', 1001, true, 'b', 1],
|
||||
['http://mozilla.com', 1001, true, 'b', 1],
|
||||
['http://mozilla.com', 1001, true, 'a', 1],
|
||||
|
||||
['http://google.com', 1011, false, 'a', 1],
|
||||
['http://google.com', 1011, false, 'b', 1],
|
||||
['http://mozilla.com', 1011, false, 'b', 1],
|
||||
['http://mozilla.com', 1011, false, 'a', 1],
|
||||
];
|
||||
|
||||
permissions.forEach((perm) => {
|
||||
pm.addFromPrincipal(mkPrin(perm[0], perm[1], perm[2]), perm[3], perm[4]);
|
||||
});
|
||||
|
||||
checkPerms(permissions);
|
||||
|
||||
let remove_false_perms = [
|
||||
['http://google.com', 1011, false, 'a', 1],
|
||||
['http://google.com', 1011, false, 'b', 1],
|
||||
['http://mozilla.com', 1011, false, 'b', 1],
|
||||
['http://mozilla.com', 1011, false, 'a', 1],
|
||||
];
|
||||
|
||||
pm.removePermissionsForApp(1001, false);
|
||||
checkPerms(remove_false_perms);
|
||||
|
||||
let restore = [
|
||||
['http://google.com', 1001, false, 'a', 1],
|
||||
['http://google.com', 1001, false, 'b', 1],
|
||||
['http://mozilla.com', 1001, false, 'b', 1],
|
||||
['http://mozilla.com', 1001, false, 'a', 1],
|
||||
|
||||
['http://google.com', 1001, true, 'a', 1],
|
||||
['http://google.com', 1001, true, 'b', 1],
|
||||
['http://mozilla.com', 1001, true, 'b', 1],
|
||||
['http://mozilla.com', 1001, true, 'a', 1],
|
||||
];
|
||||
|
||||
restore.forEach((perm) => {
|
||||
pm.addFromPrincipal(mkPrin(perm[0], perm[1], perm[2]), perm[3], perm[4]);
|
||||
});
|
||||
checkPerms(permissions);
|
||||
|
||||
let remove_true_perms = [
|
||||
['http://google.com', 1001, false, 'a', 1],
|
||||
['http://google.com', 1001, false, 'b', 1],
|
||||
['http://mozilla.com', 1001, false, 'b', 1],
|
||||
['http://mozilla.com', 1001, false, 'a', 1],
|
||||
|
||||
['http://google.com', 1011, false, 'a', 1],
|
||||
['http://google.com', 1011, false, 'b', 1],
|
||||
['http://mozilla.com', 1011, false, 'b', 1],
|
||||
['http://mozilla.com', 1011, false, 'a', 1],
|
||||
];
|
||||
|
||||
pm.removePermissionsForApp(1001, true);
|
||||
checkPerms(remove_true_perms);
|
||||
}
|
|
@ -26,6 +26,7 @@ skip-if = true # Bug 863738
|
|||
[test_permmanager_notifications.js]
|
||||
[test_permmanager_removeall.js]
|
||||
[test_permmanager_removesince.js]
|
||||
[test_permmanager_removeforapp.js]
|
||||
[test_permmanager_load_invalid_entries.js]
|
||||
skip-if = debug == true
|
||||
[test_permmanager_idn.js]
|
||||
|
|
|
@ -536,6 +536,27 @@ IsTransferFilterType(FilterType aType)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
HasUnboundedOutputRegion(FilterType aType)
|
||||
{
|
||||
if (IsTransferFilterType(aType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (aType) {
|
||||
case FilterType::COLOR_MATRIX:
|
||||
case FilterType::POINT_DIFFUSE:
|
||||
case FilterType::SPOT_DIFFUSE:
|
||||
case FilterType::DISTANT_DIFFUSE:
|
||||
case FilterType::POINT_SPECULAR:
|
||||
case FilterType::SPOT_SPECULAR:
|
||||
case FilterType::DISTANT_SPECULAR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<FilterNode>
|
||||
FilterNodeD2D1::Create(ID2D1DeviceContext *aDC, FilterType aType)
|
||||
|
@ -556,7 +577,7 @@ FilterNodeD2D1::Create(ID2D1DeviceContext *aDC, FilterType aType)
|
|||
|
||||
RefPtr<FilterNodeD2D1> filter = new FilterNodeD2D1(effect, aType);
|
||||
|
||||
if (IsTransferFilterType(aType) || aType == FilterType::COLOR_MATRIX) {
|
||||
if (HasUnboundedOutputRegion(aType)) {
|
||||
// These filters can produce non-transparent output from transparent
|
||||
// input pixels, and we want them to have an unbounded output region.
|
||||
filter = new FilterNodeExtendInputAdapterD2D1(aDC, filter, aType);
|
||||
|
|
|
@ -3340,7 +3340,7 @@ template<typename LightType, typename LightingType>
|
|||
IntRect
|
||||
FilterNodeLightingSoftware<LightType, LightingType>::GetOutputRectInRect(const IntRect& aRect)
|
||||
{
|
||||
return GetInputRectInRect(IN_LIGHTING_IN, aRect);
|
||||
return aRect;
|
||||
}
|
||||
|
||||
Point3D
|
||||
|
@ -3482,7 +3482,7 @@ FilterNodeLightingSoftware<LightType, LightingType>::DoRender(const IntRect& aRe
|
|||
|
||||
RefPtr<DataSourceSurface> input =
|
||||
GetInputDataSourceSurface(IN_LIGHTING_IN, srcRect, CAN_HANDLE_A8,
|
||||
EDGE_MODE_DUPLICATE);
|
||||
EDGE_MODE_NONE);
|
||||
|
||||
if (!input) {
|
||||
return nullptr;
|
||||
|
|
|
@ -435,12 +435,14 @@ public:
|
|||
DebugGLGraphicBuffer(void *layerRef,
|
||||
GLenum target,
|
||||
GLuint name,
|
||||
const LayerRenderState &aState)
|
||||
const LayerRenderState &aState,
|
||||
bool aIsMask)
|
||||
: DebugGLData(Packet::TEXTURE),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
|
||||
mTarget(target),
|
||||
mName(name),
|
||||
mState(aState)
|
||||
mState(aState),
|
||||
mIsMask(aIsMask)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -457,6 +459,7 @@ public:
|
|||
tp->set_layerref(mLayerRef);
|
||||
tp->set_name(mName);
|
||||
tp->set_target(mTarget);
|
||||
tp->set_ismask(mIsMask);
|
||||
|
||||
int pFormat = buffer->getPixelFormat();
|
||||
if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
|
||||
|
@ -513,6 +516,7 @@ private:
|
|||
GLenum mTarget;
|
||||
GLuint mName;
|
||||
const LayerRenderState &mState;
|
||||
bool mIsMask;
|
||||
Packet mPacket;
|
||||
};
|
||||
#endif
|
||||
|
@ -523,13 +527,15 @@ public:
|
|||
void* layerRef,
|
||||
GLenum target,
|
||||
GLuint name,
|
||||
DataSourceSurface* img)
|
||||
DataSourceSurface* img,
|
||||
bool aIsMask)
|
||||
: DebugGLData(Packet::TEXTURE),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
|
||||
mTarget(target),
|
||||
mName(name),
|
||||
mContextAddress(reinterpret_cast<intptr_t>(cx)),
|
||||
mDatasize(0)
|
||||
mDatasize(0),
|
||||
mIsMask(aIsMask)
|
||||
{
|
||||
// pre-packing
|
||||
// DataSourceSurface may have locked buffer,
|
||||
|
@ -552,6 +558,7 @@ private:
|
|||
tp->set_target(mTarget);
|
||||
tp->set_dataformat(LOCAL_GL_RGBA);
|
||||
tp->set_glcontext(static_cast<uint64_t>(mContextAddress));
|
||||
tp->set_ismask(mIsMask);
|
||||
|
||||
if (aImage) {
|
||||
tp->set_width(aImage->GetSize().width);
|
||||
|
@ -590,6 +597,7 @@ protected:
|
|||
GLuint mName;
|
||||
intptr_t mContextAddress;
|
||||
uint32_t mDatasize;
|
||||
bool mIsMask;
|
||||
|
||||
// Packet data
|
||||
Packet mPacket;
|
||||
|
@ -872,9 +880,11 @@ NS_IMPL_ISUPPORTS(DebugDataSender::SendTask, nsIRunnable);
|
|||
* 2. SendEffectChain
|
||||
* 1. SendTexturedEffect
|
||||
* -> SendTextureSource
|
||||
* 2. SendYCbCrEffect
|
||||
* 2. SendMaskEffect
|
||||
* -> SendTextureSource
|
||||
* 3. SendColor
|
||||
* 3. SendYCbCrEffect
|
||||
* -> SendTextureSource
|
||||
* 4. SendColor
|
||||
*/
|
||||
class SenderHelper
|
||||
{
|
||||
|
@ -895,7 +905,7 @@ public:
|
|||
|
||||
static bool GetLayersTreeSendable() {return sLayersTreeSendable;}
|
||||
|
||||
static void ClearTextureIdList();
|
||||
static void ClearSentTextureIds();
|
||||
|
||||
|
||||
// Sender private functions
|
||||
|
@ -907,58 +917,52 @@ private:
|
|||
static void SendTextureSource(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
bool aFlipY);
|
||||
bool aFlipY,
|
||||
bool aIsMask);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static bool SendGraphicBuffer(void* aLayerRef,
|
||||
static bool SendGraphicBuffer(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
const TexturedEffect* aEffect);
|
||||
const TexturedEffect* aEffect,
|
||||
bool aIsMask);
|
||||
#endif
|
||||
static void SendTexturedEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const TexturedEffect* aEffect);
|
||||
static void SendMaskEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectMask* aEffect);
|
||||
static void SendYCbCrEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectYCbCr* aEffect);
|
||||
static GLuint GetTextureID(GLContext* aGLContext,
|
||||
TextureSourceOGL* aSource);
|
||||
static bool IsTextureIdContainsInList(GLuint aTextureId);
|
||||
static bool HasTextureIdBeenSent(GLuint aTextureId);
|
||||
// Data fields
|
||||
private:
|
||||
static bool sLayersTreeSendable;
|
||||
static bool sLayersBufferSendable;
|
||||
static std::list<GLuint> sTextureIdList;
|
||||
static std::vector<GLuint> sSentTextureIds;
|
||||
};
|
||||
|
||||
bool SenderHelper::sLayersTreeSendable = true;
|
||||
bool SenderHelper::sLayersBufferSendable = true;
|
||||
std::list<GLuint> SenderHelper::sTextureIdList;
|
||||
std::vector<GLuint> SenderHelper::sSentTextureIds;
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// SenderHelper implementation
|
||||
// ----------------------------------------------
|
||||
void
|
||||
SenderHelper::ClearTextureIdList()
|
||||
SenderHelper::ClearSentTextureIds()
|
||||
{
|
||||
std::list<GLuint>::iterator it;
|
||||
while (!sTextureIdList.empty()) {
|
||||
it = sTextureIdList.begin();
|
||||
sTextureIdList.erase(it);
|
||||
}
|
||||
sSentTextureIds.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
SenderHelper::IsTextureIdContainsInList(GLuint aTextureId)
|
||||
SenderHelper::HasTextureIdBeenSent(GLuint aTextureId)
|
||||
{
|
||||
for (std::list<GLuint>::iterator it = sTextureIdList.begin();
|
||||
it != sTextureIdList.end(); ++it) {
|
||||
if (*it == aTextureId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return std::find(sSentTextureIds.begin(), sSentTextureIds.end(), aTextureId) != sSentTextureIds.end();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1035,13 +1039,17 @@ void
|
|||
SenderHelper::SendTextureSource(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
bool aFlipY)
|
||||
bool aFlipY,
|
||||
bool aIsMask)
|
||||
{
|
||||
MOZ_ASSERT(aGLContext);
|
||||
if (!aGLContext) {
|
||||
return;
|
||||
}
|
||||
GLuint texID = GetTextureID(aGLContext, aSource);
|
||||
if (HasTextureIdBeenSent(texID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum textureTarget = aSource->GetTextureTarget();
|
||||
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget,
|
||||
|
@ -1058,26 +1066,31 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
|
|||
shaderConfig, aFlipY);
|
||||
gLayerScopeManager.GetSocketManager()->AppendDebugData(
|
||||
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
|
||||
aTexID, img));
|
||||
texID, img, aIsMask));
|
||||
|
||||
sTextureIdList.push_back(aTexID);
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID);
|
||||
sSentTextureIds.push_back(texID);
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
|
||||
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
bool
|
||||
SenderHelper::SendGraphicBuffer(void* aLayerRef,
|
||||
SenderHelper::SendGraphicBuffer(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
const TexturedEffect* aEffect) {
|
||||
const TexturedEffect* aEffect,
|
||||
bool aIsMask) {
|
||||
GLuint texID = GetTextureID(aGLContext, aSource);
|
||||
if (HasTextureIdBeenSent(texID)) {
|
||||
return false;
|
||||
}
|
||||
if (!aEffect->mState.mSurface.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum target = aSource->GetTextureTarget();
|
||||
mozilla::UniquePtr<DebugGLGraphicBuffer> package =
|
||||
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, aTexID, aEffect->mState);
|
||||
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, texID, aEffect->mState, aIsMask);
|
||||
|
||||
// The texure content in this TexureHost is not altered,
|
||||
// we don't need to send it again.
|
||||
|
@ -1089,9 +1102,9 @@ SenderHelper::SendGraphicBuffer(void* aLayerRef,
|
|||
|
||||
// Transfer ownership to SocketManager.
|
||||
gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
|
||||
sTextureIdList.push_back(aTexID);
|
||||
sSentTextureIds.push_back(texID);
|
||||
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID);
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
|
||||
|
||||
gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
|
||||
return true;
|
||||
|
@ -1108,19 +1121,27 @@ SenderHelper::SendTexturedEffect(GLContext* aGLContext,
|
|||
return;
|
||||
}
|
||||
|
||||
GLuint texID = GetTextureID(aGLContext, source);
|
||||
if (IsTextureIdContainsInList(texID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) {
|
||||
if (SendGraphicBuffer(aGLContext, aLayerRef, source, aEffect, false)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// Fallback texture sending path.
|
||||
// Render to texture and read pixels back.
|
||||
SendTextureSource(aGLContext, aLayerRef, source, texID, false);
|
||||
SendTextureSource(aGLContext, aLayerRef, source, false, false);
|
||||
}
|
||||
|
||||
void
|
||||
SenderHelper::SendMaskEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectMask* aEffect)
|
||||
{
|
||||
TextureSourceOGL* source = aEffect->mMaskTexture->AsSourceOGL();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendTextureSource(aGLContext, aLayerRef, source, false, true);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1137,20 +1158,9 @@ SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
|
|||
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
|
||||
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
|
||||
|
||||
GLuint texID = GetTextureID(aGLContext, sourceY);
|
||||
if (!IsTextureIdContainsInList(texID)) {
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceY, texID, false);
|
||||
}
|
||||
|
||||
texID = GetTextureID(aGLContext, sourceCb);
|
||||
if (!IsTextureIdContainsInList(texID)) {
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceCb, texID, false);
|
||||
}
|
||||
|
||||
texID = GetTextureID(aGLContext, sourceCr);
|
||||
if (!IsTextureIdContainsInList(texID)) {
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceCr, texID, false);
|
||||
}
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceY, false, false);
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceCb, false, false);
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceCr, false, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1188,8 +1198,11 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
|
|||
break;
|
||||
}
|
||||
|
||||
//const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
|
||||
// TODO:
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
const EffectMask* effectMask =
|
||||
static_cast<const EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
|
||||
SendMaskEffect(aGLContext, aEffectChain.mLayerRef, effectMask);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1872,7 +1885,7 @@ LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
|
|||
if (!LayerScope::CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
SenderHelper::ClearTextureIdList();
|
||||
SenderHelper::ClearSentTextureIds();
|
||||
|
||||
gLayerScopeManager.GetSocketManager()->AppendDebugData(
|
||||
new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
|
||||
|
|
|
@ -53,6 +53,10 @@ TextureClientDIB::BorrowDrawTarget()
|
|||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize);
|
||||
}
|
||||
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "DIB failed draw target surface " << mSize << ", " << (int)mIsLocked << ", " << IsAllocated();
|
||||
}
|
||||
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
||||
|
|
|
@ -424,7 +424,7 @@ TextureClientD3D11::BorrowDrawTarget()
|
|||
mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture10, mFormat);
|
||||
}
|
||||
if (!mDrawTarget) {
|
||||
gfxWarning() << "Invalid draw target for borrowing";
|
||||
gfxCriticalNote << "Invalid draw target for borrowing D3D11 " << (int)mFormat;
|
||||
}
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
|
|
@ -541,6 +541,7 @@ TextureClientD3D9::BorrowDrawTarget()
|
|||
MOZ_ASSERT(mIsLocked && mD3D9Surface);
|
||||
if (!mIsLocked || !mD3D9Surface) {
|
||||
NS_WARNING("Calling BorrowDrawTarget on an Unlocked TextureClient");
|
||||
gfxCriticalNote << "BorrowDrawTarget on an Unlocked TextureClient";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -552,10 +553,14 @@ TextureClientD3D9::BorrowDrawTarget()
|
|||
nsRefPtr<gfxASurface> surface = new gfxWindowsSurface(mD3D9Surface);
|
||||
if (!surface || surface->CairoStatus()) {
|
||||
NS_WARNING("Could not create surface for d3d9 surface");
|
||||
gfxCriticalNote << "Failed creation on D3D9";
|
||||
return nullptr;
|
||||
}
|
||||
mDrawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, mSize);
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "Bad draw target creation for surface D3D9 " << mSize;
|
||||
}
|
||||
} else {
|
||||
// gfxWindowsSurface don't support transparency so we can't use the d3d9
|
||||
// windows surface optimization.
|
||||
|
@ -569,6 +574,9 @@ TextureClientD3D9::BorrowDrawTarget()
|
|||
mDrawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForData((uint8_t*)rect.pBits, mSize,
|
||||
rect.Pitch, mFormat);
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "Bad draw target creation for data D3D9 " << mSize << ", " << (int)mFormat;
|
||||
}
|
||||
mLockRect = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -648,6 +648,7 @@ const int TexturePacket::kTargetFieldNumber;
|
|||
const int TexturePacket::kDataformatFieldNumber;
|
||||
const int TexturePacket::kGlcontextFieldNumber;
|
||||
const int TexturePacket::kDataFieldNumber;
|
||||
const int TexturePacket::kIsMaskFieldNumber;
|
||||
#endif // !_MSC_VER
|
||||
|
||||
TexturePacket::TexturePacket()
|
||||
|
@ -678,6 +679,7 @@ void TexturePacket::SharedCtor() {
|
|||
dataformat_ = 0u;
|
||||
glcontext_ = GOOGLE_ULONGLONG(0);
|
||||
data_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
|
||||
ismask_ = false;
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
|
@ -732,10 +734,13 @@ void TexturePacket::Clear() {
|
|||
if (_has_bits_[0 / 32] & 255) {
|
||||
ZR_(layerref_, glcontext_);
|
||||
}
|
||||
if (has_data()) {
|
||||
if (data_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
data_->clear();
|
||||
if (_has_bits_[8 / 32] & 768) {
|
||||
if (has_data()) {
|
||||
if (data_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
data_->clear();
|
||||
}
|
||||
}
|
||||
ismask_ = false;
|
||||
}
|
||||
|
||||
#undef OFFSET_OF_FIELD_
|
||||
|
@ -755,7 +760,7 @@ bool TexturePacket::MergePartialFromCodedStream(
|
|||
&unknown_fields_string);
|
||||
// @@protoc_insertion_point(parse_start:mozilla.layers.layerscope.TexturePacket)
|
||||
for (;;) {
|
||||
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
|
||||
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
|
||||
tag = p.first;
|
||||
if (!p.second) goto handle_unusual;
|
||||
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
|
||||
|
@ -887,6 +892,21 @@ bool TexturePacket::MergePartialFromCodedStream(
|
|||
} else {
|
||||
goto handle_unusual;
|
||||
}
|
||||
if (input->ExpectTag(160)) goto parse_isMask;
|
||||
break;
|
||||
}
|
||||
|
||||
// optional bool isMask = 20;
|
||||
case 20: {
|
||||
if (tag == 160) {
|
||||
parse_isMask:
|
||||
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
|
||||
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
|
||||
input, &ismask_)));
|
||||
set_has_ismask();
|
||||
} else {
|
||||
goto handle_unusual;
|
||||
}
|
||||
if (input->ExpectAtEnd()) goto success;
|
||||
break;
|
||||
}
|
||||
|
@ -962,6 +982,11 @@ void TexturePacket::SerializeWithCachedSizes(
|
|||
9, this->data(), output);
|
||||
}
|
||||
|
||||
// optional bool isMask = 20;
|
||||
if (has_ismask()) {
|
||||
::google::protobuf::internal::WireFormatLite::WriteBool(20, this->ismask(), output);
|
||||
}
|
||||
|
||||
output->WriteRaw(unknown_fields().data(),
|
||||
unknown_fields().size());
|
||||
// @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.TexturePacket)
|
||||
|
@ -1036,6 +1061,11 @@ int TexturePacket::ByteSize() const {
|
|||
this->data());
|
||||
}
|
||||
|
||||
// optional bool isMask = 20;
|
||||
if (has_ismask()) {
|
||||
total_size += 2 + 1;
|
||||
}
|
||||
|
||||
}
|
||||
total_size += unknown_fields().size();
|
||||
|
||||
|
@ -1082,6 +1112,9 @@ void TexturePacket::MergeFrom(const TexturePacket& from) {
|
|||
if (from.has_data()) {
|
||||
set_data(from.data());
|
||||
}
|
||||
if (from.has_ismask()) {
|
||||
set_ismask(from.ismask());
|
||||
}
|
||||
}
|
||||
mutable_unknown_fields()->append(from.unknown_fields());
|
||||
}
|
||||
|
@ -1109,6 +1142,7 @@ void TexturePacket::Swap(TexturePacket* other) {
|
|||
std::swap(dataformat_, other->dataformat_);
|
||||
std::swap(glcontext_, other->glcontext_);
|
||||
std::swap(data_, other->data_);
|
||||
std::swap(ismask_, other->ismask_);
|
||||
std::swap(_has_bits_[0], other->_has_bits_[0]);
|
||||
_unknown_fields_.swap(other->_unknown_fields_);
|
||||
std::swap(_cached_size_, other->_cached_size_);
|
||||
|
|
|
@ -460,6 +460,13 @@ class TexturePacket : public ::google::protobuf::MessageLite {
|
|||
inline ::std::string* release_data();
|
||||
inline void set_allocated_data(::std::string* data);
|
||||
|
||||
// optional bool isMask = 20;
|
||||
inline bool has_ismask() const;
|
||||
inline void clear_ismask();
|
||||
static const int kIsMaskFieldNumber = 20;
|
||||
inline bool ismask() const;
|
||||
inline void set_ismask(bool value);
|
||||
|
||||
// @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.TexturePacket)
|
||||
private:
|
||||
inline void set_has_layerref();
|
||||
|
@ -480,6 +487,8 @@ class TexturePacket : public ::google::protobuf::MessageLite {
|
|||
inline void clear_has_glcontext();
|
||||
inline void set_has_data();
|
||||
inline void clear_has_data();
|
||||
inline void set_has_ismask();
|
||||
inline void clear_has_ismask();
|
||||
|
||||
::std::string _unknown_fields_;
|
||||
|
||||
|
@ -494,6 +503,7 @@ class TexturePacket : public ::google::protobuf::MessageLite {
|
|||
::google::protobuf::uint32 dataformat_;
|
||||
::google::protobuf::uint64 glcontext_;
|
||||
::std::string* data_;
|
||||
bool ismask_;
|
||||
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
|
||||
friend void protobuf_AddDesc_LayerScopePacket_2eproto_impl();
|
||||
#else
|
||||
|
@ -2664,6 +2674,30 @@ inline void TexturePacket::set_allocated_data(::std::string* data) {
|
|||
// @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.TexturePacket.data)
|
||||
}
|
||||
|
||||
// optional bool isMask = 20;
|
||||
inline bool TexturePacket::has_ismask() const {
|
||||
return (_has_bits_[0] & 0x00000200u) != 0;
|
||||
}
|
||||
inline void TexturePacket::set_has_ismask() {
|
||||
_has_bits_[0] |= 0x00000200u;
|
||||
}
|
||||
inline void TexturePacket::clear_has_ismask() {
|
||||
_has_bits_[0] &= ~0x00000200u;
|
||||
}
|
||||
inline void TexturePacket::clear_ismask() {
|
||||
ismask_ = false;
|
||||
clear_has_ismask();
|
||||
}
|
||||
inline bool TexturePacket::ismask() const {
|
||||
// @@protoc_insertion_point(field_get:mozilla.layers.layerscope.TexturePacket.isMask)
|
||||
return ismask_;
|
||||
}
|
||||
inline void TexturePacket::set_ismask(bool value) {
|
||||
set_has_ismask();
|
||||
ismask_ = value;
|
||||
// @@protoc_insertion_point(field_set:mozilla.layers.layerscope.TexturePacket.isMask)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// LayersPacket_Layer_Size
|
||||
|
|
|
@ -20,6 +20,7 @@ message ColorPacket {
|
|||
}
|
||||
|
||||
message TexturePacket {
|
||||
// Basic info
|
||||
required uint64 layerref = 1;
|
||||
optional uint32 width = 2;
|
||||
optional uint32 height = 3;
|
||||
|
@ -29,6 +30,13 @@ message TexturePacket {
|
|||
optional uint32 dataformat = 7;
|
||||
optional uint64 glcontext = 8;
|
||||
optional bytes data = 9;
|
||||
|
||||
// Texture effect attributes (10 to 19)
|
||||
// TODO: reserved for primary textured effect attributes, see Bug 1205521
|
||||
|
||||
// Mask effect attributes (20 to 29)
|
||||
optional bool isMask = 20;
|
||||
// TODO: reserved for secondary mask effect attributes, see Bug 1205521
|
||||
}
|
||||
|
||||
message LayersPacket {
|
||||
|
|
|
@ -1232,9 +1232,6 @@ FilterNodeGraphFromDescription(DrawTarget* aDT,
|
|||
{
|
||||
const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
|
||||
|
||||
Rect resultNeededRect(aResultNeededRect);
|
||||
resultNeededRect.RoundOut();
|
||||
|
||||
RefPtr<FilterCachedColorModels> sourceFilters[4];
|
||||
nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
|
||||
|
||||
|
@ -1407,6 +1404,9 @@ ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
|
|||
|
||||
case PrimitiveType::ConvolveMatrix:
|
||||
{
|
||||
if (atts.GetUint(eConvolveMatrixEdgeMode) != EDGE_MODE_NONE) {
|
||||
return aDescription.PrimitiveSubregion();
|
||||
}
|
||||
Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
|
||||
IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
|
||||
IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
|
||||
|
@ -1603,6 +1603,8 @@ FilterSupport::PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& a
|
|||
|
||||
case PrimitiveType::Turbulence:
|
||||
case PrimitiveType::Image:
|
||||
case PrimitiveType::DiffuseLighting:
|
||||
case PrimitiveType::SpecularLighting:
|
||||
{
|
||||
return aDescription.PrimitiveSubregion();
|
||||
}
|
||||
|
|
|
@ -437,7 +437,8 @@ public:
|
|||
|
||||
/**
|
||||
* Computes the region that changes in the filter output due to a change in
|
||||
* input.
|
||||
* input. This is primarily needed when an individual piece of content inside
|
||||
* a filtered container element changes.
|
||||
*/
|
||||
static nsIntRegion
|
||||
ComputeResultChangeRegion(const FilterDescription& aFilter,
|
||||
|
|
|
@ -181,15 +181,10 @@ static inline bool ShouldFailWithOOM() { return false; }
|
|||
|
||||
namespace js {
|
||||
|
||||
MOZ_NORETURN MOZ_COLD void
|
||||
CrashAtUnhandlableOOM(const char* reason);
|
||||
|
||||
/* Disable OOM testing in sections which are not OOM safe. */
|
||||
struct MOZ_RAII AutoEnterOOMUnsafeRegion
|
||||
{
|
||||
void crash(const char* reason) {
|
||||
CrashAtUnhandlableOOM(reason);
|
||||
}
|
||||
MOZ_NORETURN MOZ_COLD void crash(const char* reason);
|
||||
|
||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
AutoEnterOOMUnsafeRegion()
|
||||
|
|
|
@ -97,12 +97,12 @@ function ModuleDeclarationInstantiation()
|
|||
let module = this;
|
||||
|
||||
// Step 5
|
||||
if (module.environment !== undefined)
|
||||
if (GetModuleEnvironment(module) !== undefined)
|
||||
return;
|
||||
|
||||
// Step 7
|
||||
CreateModuleEnvironment(module);
|
||||
let env = module.environment;
|
||||
let env = GetModuleEnvironment(module);
|
||||
|
||||
// Step 8
|
||||
let requestedModules = module.requestedModules;
|
||||
|
@ -131,7 +131,7 @@ function ModuleDeclarationInstantiation()
|
|||
if (imp.importName === "*") {
|
||||
// TODO
|
||||
// let namespace = GetModuleNamespace(importedModule);
|
||||
// CreateNamespaceBinding(module.environment, imp.localName, namespace);
|
||||
// CreateNamespaceBinding(env, imp.localName, namespace);
|
||||
} else {
|
||||
let resolution = importedModule.resolveExport(imp.importName);
|
||||
if (resolution === null)
|
||||
|
|
|
@ -410,8 +410,6 @@ ModuleObject::evaluate(JSContext* cx, MutableHandleValue rval)
|
|||
return JS_ExecuteScript(cx, script, rval);
|
||||
}
|
||||
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, initialEnvironment, InitialEnvironmentSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, environment, EnvironmentSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, evaluated, EvaluatedSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, requestedModules, RequestedModulesSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
|
||||
|
@ -423,8 +421,6 @@ JSObject*
|
|||
js::InitModuleClass(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
static const JSPropertySpec protoAccessors[] = {
|
||||
JS_PSG("initialEnvironment", ModuleObject_initialEnvironmentGetter, 0),
|
||||
JS_PSG("environment", ModuleObject_environmentGetter, 0),
|
||||
JS_PSG("evaluated", ModuleObject_evaluatedGetter, 0),
|
||||
JS_PSG("requestedModules", ModuleObject_requestedModulesGetter, 0),
|
||||
JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
|
||||
|
|
|
@ -2886,6 +2886,80 @@ SetRNGState(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
#endif
|
||||
|
||||
static ModuleEnvironmentObject*
|
||||
GetModuleEnvironment(JSContext* cx, HandleValue moduleValue)
|
||||
{
|
||||
RootedModuleObject module(cx, &moduleValue.toObject().as<ModuleObject>());
|
||||
|
||||
// Use the initial environment so that tests can check bindings exists
|
||||
// before they have been instantiated.
|
||||
RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
|
||||
MOZ_ASSERT(env);
|
||||
MOZ_ASSERT_IF(module->environment(), module->environment() == env);
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetModuleEnvironmentNames(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1) {
|
||||
JS_ReportError(cx, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isObject() || !args[0].toObject().is<ModuleObject>()) {
|
||||
JS_ReportError(cx, "First argument should be a ModuleObject");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, args[0]));
|
||||
Rooted<IdVector> ids(cx, IdVector(cx));
|
||||
if (!JS_Enumerate(cx, env, &ids))
|
||||
return false;
|
||||
|
||||
uint32_t length = ids.length();
|
||||
RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, length));
|
||||
if (!array)
|
||||
return false;
|
||||
|
||||
array->setDenseInitializedLength(length);
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
array->initDenseElement(i, StringValue(JSID_TO_STRING(ids[i])));
|
||||
|
||||
args.rval().setObject(*array);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetModuleEnvironmentValue(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 2) {
|
||||
JS_ReportError(cx, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isObject() || !args[0].toObject().is<ModuleObject>()) {
|
||||
JS_ReportError(cx, "First argument should be a ModuleObject");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[1].isString()) {
|
||||
JS_ReportError(cx, "Second argument should be a string");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, args[0]));
|
||||
RootedString name(cx, args[1].toString());
|
||||
RootedId id(cx);
|
||||
if (!JS_StringToId(cx, name, &id))
|
||||
return false;
|
||||
|
||||
return GetProperty(cx, env, env, id, args.rval());
|
||||
}
|
||||
|
||||
static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
JS_FN_HELP("gc", ::GC, 0, 0,
|
||||
"gc([obj] | 'compartment' [, 'shrinking'])",
|
||||
|
@ -3359,6 +3433,14 @@ gc::ZealModeHelpText),
|
|||
" Set this compartment's RNG state.\n"),
|
||||
#endif
|
||||
|
||||
JS_FN_HELP("getModuleEnvironmentNames", GetModuleEnvironmentNames, 1, 0,
|
||||
"getModuleEnvironmentNames(module)",
|
||||
" Get the list of a module environment's bound names for a specified module.\n"),
|
||||
|
||||
JS_FN_HELP("getModuleEnvironmentValue", GetModuleEnvironmentValue, 2, 0,
|
||||
"getModuleEnvironmentValue(module, name)",
|
||||
" Get the value of a bound name in a module environment.\n"),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
|
||||
|
|
|
@ -952,7 +952,7 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
|||
|
||||
SliceData data(budget, reason, PRMJ_Now(), JS_GetCurrentEmbedderTime(), GetPageFaultCount());
|
||||
if (!slices.append(data)) {
|
||||
// OOM testing fails if we CrashAtUnhandlableOOM here.
|
||||
// OOM testing fails if we crash here, so set a flag instead.
|
||||
aborted = true;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// |jit-test| allow-oom
|
||||
// |jit-test| allow-oom; allow-unhandlable-oom
|
||||
gcparam("maxBytes", gcparam("gcBytes") + 4*1024);
|
||||
var max = 400;
|
||||
function f(b) {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
load(libdir + 'oomTest.js');
|
||||
|
||||
oomTest(() => {
|
||||
try {
|
||||
var max = 400;
|
||||
function f(b) {
|
||||
if (b) {
|
||||
f(b - 1);
|
||||
} else {
|
||||
g = {};
|
||||
}
|
||||
g.apply(null, arguments);
|
||||
}
|
||||
f(max - 1);
|
||||
} catch(exc0) {}
|
||||
f();
|
||||
});
|
|
@ -1,13 +1,7 @@
|
|||
// Exercise ModuleDeclarationInstantiation() operation.
|
||||
|
||||
function parseAndInstantiate(source) {
|
||||
let m = parseModule(source);
|
||||
m.declarationInstantiation();
|
||||
return m.environment;
|
||||
}
|
||||
|
||||
function testModuleEnvironment(module, expected) {
|
||||
var actual = Object.keys(module.environment);
|
||||
var actual = getModuleEnvironmentNames(module);
|
||||
assertEq(actual.length, expected.length);
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
assertEq(actual[i], expected[i]);
|
||||
|
@ -15,8 +9,9 @@ function testModuleEnvironment(module, expected) {
|
|||
}
|
||||
|
||||
// Check the environment of an empty module.
|
||||
let e = parseAndInstantiate("");
|
||||
assertEq(Object.keys(e).length, 0);
|
||||
let m = parseModule("");
|
||||
m.declarationInstantiation();
|
||||
testModuleEnvironment(m, []);
|
||||
|
||||
let moduleRepo = new Map();
|
||||
setModuleResolveHook(function(module, specifier) {
|
||||
|
@ -25,8 +20,8 @@ setModuleResolveHook(function(module, specifier) {
|
|||
throw "Module " + specifier + " not found";
|
||||
});
|
||||
|
||||
a = moduleRepo['a'] = parseModule("var x = 1; export { x };");
|
||||
b = moduleRepo['b'] = parseModule("import { x as y } from 'a';");
|
||||
let a = moduleRepo['a'] = parseModule("var x = 1; export { x };");
|
||||
let b = moduleRepo['b'] = parseModule("import { x as y } from 'a';");
|
||||
|
||||
a.declarationInstantiation();
|
||||
b.declarationInstantiation();
|
||||
|
|
|
@ -3,13 +3,11 @@ load(libdir + "class.js");
|
|||
// Test top-level module environment
|
||||
|
||||
function testInitialEnvironment(source, expected) {
|
||||
print(source);
|
||||
let m = parseModule(source);
|
||||
let scope = m.initialEnvironment;
|
||||
let keys = Object.keys(scope);
|
||||
assertEq(keys.length, expected.length);
|
||||
let module = parseModule(source);
|
||||
let names = getModuleEnvironmentNames(module);
|
||||
assertEq(names.length, expected.length);
|
||||
expected.forEach(function(name) {
|
||||
assertEq(name in scope, true);
|
||||
assertEq(names.includes(name), true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -26,15 +26,15 @@ assertEq(typeof m.evaluation(), "undefined");
|
|||
|
||||
// Check top level variables are initialized by evaluation.
|
||||
m = parseModule("export var x = 2 + 2;");
|
||||
assertEq(typeof m.initialEnvironment.x, "undefined");
|
||||
assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined");
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
||||
assertEq(m.environment.x, 4);
|
||||
assertEq(getModuleEnvironmentValue(m, "x"), 4);
|
||||
|
||||
m = parseModule("export let x = 2 * 3;");
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
||||
assertEq(m.environment.x, 6);
|
||||
assertEq(getModuleEnvironmentValue(m, "x"), 6);
|
||||
|
||||
// Set up a module to import from.
|
||||
let a = moduleRepo['a'] =
|
||||
|
@ -99,4 +99,5 @@ assertDeepEq(parseAndEvaluate(`import { x as x1, y as y1 } from 'c1';
|
|||
m = parseModule("import { x } from 'a'; function f() { return x; }")
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
||||
assertEq(m.environment.f(), 1);
|
||||
let f = getModuleEnvironmentValue(m, "f");
|
||||
assertEq(f(), 1);
|
||||
|
|
|
@ -2031,7 +2031,7 @@ SnapshotIterator::maybeRead(const RValueAllocation& a, MaybeReadFallback& fallba
|
|||
|
||||
if (fallback.canRecoverResults()) {
|
||||
if (!initInstructionResults(fallback))
|
||||
js::CrashAtUnhandlableOOM("Unable to recover allocations.");
|
||||
MOZ_CRASH("Unable to recover allocations.");
|
||||
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
|
|
|
@ -993,7 +993,7 @@ class BOffImm
|
|||
{
|
||||
MOZ_ASSERT((offset & 0x3) == 0);
|
||||
if (!IsInRange(offset))
|
||||
CrashAtUnhandlableOOM("BOffImm");
|
||||
MOZ_CRASH("BOffImm offset out of range");
|
||||
}
|
||||
|
||||
explicit BOffImm()
|
||||
|
|
|
@ -1199,13 +1199,15 @@ JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
|
|||
#endif
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
void CompartmentChecker::check(InterpreterFrame* fp)
|
||||
void
|
||||
CompartmentChecker::check(InterpreterFrame* fp)
|
||||
{
|
||||
if (fp)
|
||||
check(fp->scopeChain());
|
||||
}
|
||||
|
||||
void CompartmentChecker::check(AbstractFramePtr frame)
|
||||
void
|
||||
CompartmentChecker::check(AbstractFramePtr frame)
|
||||
{
|
||||
if (frame)
|
||||
check(frame.scopeChain());
|
||||
|
@ -1213,7 +1215,7 @@ void CompartmentChecker::check(AbstractFramePtr frame)
|
|||
#endif
|
||||
|
||||
void
|
||||
js::CrashAtUnhandlableOOM(const char* reason)
|
||||
AutoEnterOOMUnsafeRegion::crash(const char* reason)
|
||||
{
|
||||
char msgbuf[1024];
|
||||
JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
|
||||
|
|
|
@ -3548,6 +3548,9 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFu
|
|||
if (!dst)
|
||||
return nullptr;
|
||||
|
||||
// Save flags in case we need to undo the early mutations.
|
||||
const int preservedFlags = fun->flags();
|
||||
|
||||
dst->setFunction(fun);
|
||||
Rooted<LazyScript*> lazy(cx);
|
||||
if (fun->isInterpretedLazy()) {
|
||||
|
@ -3562,6 +3565,7 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFu
|
|||
fun->initLazyScript(lazy);
|
||||
else
|
||||
fun->setScript(nullptr);
|
||||
fun->setFlags(preservedFlags);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -4023,17 +4027,11 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
|
|||
continue;
|
||||
AbstractFramePtr frame = i.abstractFramePtr();
|
||||
if (frame.isFunctionFrame() && frame.script() == script) {
|
||||
/* We crash on OOM since cleaning up here would be complicated. */
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
|
||||
if (!argsobj) {
|
||||
/*
|
||||
* We can't leave stack frames with script->needsArgsObj but no
|
||||
* arguments object. It is, however, safe to leave frames with
|
||||
* an arguments object but !script->needsArgsObj.
|
||||
*/
|
||||
script->needsArgsObj_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!argsobj)
|
||||
oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
|
||||
SetFrameArgumentsObject(cx, frame, script, argsobj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1293,6 +1293,23 @@ intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_GetModuleEnvironment(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
|
||||
RootedModuleEnvironmentObject env(cx, module->environment());
|
||||
args.rval().setUndefined();
|
||||
if (!env) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
args.rval().setObject(*env);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_CreateModuleEnvironment(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -1586,7 +1603,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("CallModuleMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
|
||||
JS_FN("HostResolveImportedModule", intrinsic_HostResolveImportedModule, 2, 0),
|
||||
JS_FN("CreateModuleEnvironment", intrinsic_CreateModuleEnvironment, 2, 0),
|
||||
JS_FN("GetModuleEnvironment", intrinsic_GetModuleEnvironment, 1, 0),
|
||||
JS_FN("CreateModuleEnvironment", intrinsic_CreateModuleEnvironment, 1, 0),
|
||||
JS_FN("CreateImportBinding", intrinsic_CreateImportBinding, 4, 0),
|
||||
JS_FN("SetModuleEvaluated", intrinsic_SetModuleEvaluated, 1, 0),
|
||||
JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
|
||||
|
|
|
@ -734,9 +734,13 @@ JSStructuredCloneWriter::~JSStructuredCloneWriter()
|
|||
// Free any transferable data left lying around in the buffer
|
||||
uint64_t* data;
|
||||
size_t size;
|
||||
MOZ_ALWAYS_TRUE(extractBuffer(&data, &size));
|
||||
DiscardTransferables(data, size, callbacks, closure);
|
||||
js_free(data);
|
||||
{
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!extractBuffer(&data, &size))
|
||||
oomUnsafe.crash("Unable to extract clone buffer");
|
||||
DiscardTransferables(data, size, callbacks, closure);
|
||||
js_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -3,5 +3,14 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
|
||||
<image width='100' height='100' xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG6SURBVHhe7d3BbcJAGAXhJYXQg32mCV8p2vRAEb4mREoJe/g2GiTf55/hiRu+jTG+P08fxMAXwhHGn4GCYF+FghQEM4DhtJCCYAYwnBZSEMwAhtNCCoIZwHBaSEEwAxhOCykIZgDDaSEFwQxgOC2kIJgBDGfqQh6Px9j3HTtxLZypQZ7P5ziOYy0DGO3UIPf7fWzbhp24Fs7UIGudbtIWBOtSkIJgBjCcFlIQzACG00IKghnAcFpIQTADGE4LKQhmAMNpIQXBDGA4LaQgmAEMp4UUBDOA4bSQgmAGMJwWUhDMAIbTQgqCGcBwWkhBMAMYTgspCGYAw2khBcEMYDgtpCCYAQynhRQEM4DhtJCCYAYwnBZSEMwAhtNCCoIZwHBaSEEwAxhOCykIZgDDaSEFwQxgOC2kIJgBDKeFFAQzgOG0kIJgBjCcFlIQzACG00IKghnAcFrIfw7yfr/H6/XCTlwL5/bBnfY+9d8/47+ua5znuZYFiHZqEOiuZVH6DcHSFaQgmAEMp4UUBDOA4bSQgmAGMJwWUhDMAIbTQgqCGcBwWkhBMAMYTgspCGYAw2khBcEMYDgtBAvyA+wPEw79WuphAAAAAElFTkSuQmCC"/>
|
||||
<image width='100' height='100'
|
||||
xlink:href="data:image/png;base64,
|
||||
iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI
|
||||
WXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3wkbDDIilL5aRAAAAB1pVFh0Q29tbWVudAAAAAAAQ3Jl
|
||||
YXRlZCB3aXRoIEdJTVBkLmUHAAAA9UlEQVR42u3csRHDIBBFwbPHddADiqmEduhFlSiWelBOSirX
|
||||
YFsB49lXAMHf4DIeEXGFpqi1Fk8zzFPOGchsAQEiIEAEBIiAABEQIAIiIEAEBIiAAPmgUkosy2LV
|
||||
H3rd+VitNXrvse+7ZWcASSlFSsmqbggQAQEiIAICRECACAgQAQEiIEAERECACAgQAQEiIEAERECA
|
||||
CAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAfnHbv3Z+jzP6L1bdRaQdV1j
|
||||
jGHVWUC2bbOoGwJEQIAIiIAAERAgAgJEQIAIiIAAERAg+qrjOOINBcEbJFN4kugAAAAASUVORK5C
|
||||
YII="/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 1013 B После Ширина: | Высота: | Размер: 834 B |
|
@ -0,0 +1,11 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600px" height="300px">
|
||||
|
||||
<rect x="50" y="50" width="200" height="200" fill="black" />
|
||||
|
||||
<rect x="340" y="40" width="220" height="220" fill="grey" />
|
||||
<rect x="350" y="50" width="200" height="200" fill="white" />
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 387 B |
|
@ -0,0 +1,30 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600px" height="300px">
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1203376 -->
|
||||
<defs>
|
||||
<!-- the filter lights are intentionally chosen to fill the entire area with
|
||||
a solid color since we're only testing the extents of the filter region
|
||||
-->
|
||||
<filter id="diffuse" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<!-- gives a black filter region -->
|
||||
<feDiffuseLighting lighting-color="black">
|
||||
<feDistantLight />
|
||||
</feDiffuseLighting>
|
||||
</filter>
|
||||
|
||||
<filter id="specular" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<!-- gives a white filter region -->
|
||||
<feSpecularLighting lighting-color="white" specularConstant="100">
|
||||
<feDistantLight elevation="90"/>
|
||||
</feSpecularLighting>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<rect x="100" y="100" width="100" height="100" filter="url(#diffuse)" />
|
||||
|
||||
<rect x="340" y="40" width="220" height="220" fill="grey" />
|
||||
<rect x="400" y="100" width="100" height="100" filter="url(#specular)" />
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -109,10 +109,12 @@ fuzzy(2,500) == feDisplacementMap-colour-01.svg feDisplacementMap-colour-01-ref.
|
|||
== feTile-large-02.svg feTile-large-02-ref.svg
|
||||
== feTile-outside-01.svg feTile-outside-01-ref.svg
|
||||
|
||||
fuzzy(1,119) == feDiffuseLighting-1.svg feDiffuseLighting-1-ref.svg
|
||||
fuzzy(1,217) == feDiffuseLighting-1.svg feDiffuseLighting-1-ref.svg
|
||||
|
||||
fuzzy(2,2659) skip-if(d2d) == feSpecularLighting-1.svg feSpecularLighting-1-ref.svg
|
||||
|
||||
== filter-lighting-region.svg filter-lighting-region-ref.svg
|
||||
|
||||
== fePointLight-zoomed-page.svg fePointLight-zoomed-page-ref.svg
|
||||
|
||||
== feTurbulence-offset.svg feTurbulence-offset-ref.svg
|
||||
|
|
|
@ -284,8 +284,6 @@ static void nr_ice_candidate_mark_done(nr_ice_candidate *cand, int state)
|
|||
* piggybacking on it. Make sure it is marked done too. */
|
||||
if ((cand->type == RELAYED) && cand->u.relayed.srvflx_candidate) {
|
||||
nr_ice_candidate *srflx=cand->u.relayed.srvflx_candidate;
|
||||
/* Calling done_cb can destroy this, make sure it doesn't dangle. */
|
||||
cand->u.relayed.srvflx_candidate=0;
|
||||
if (state == NR_ICE_CAND_STATE_INITIALIZED &&
|
||||
nr_turn_client_get_mapped_address(cand->u.relayed.turn,
|
||||
&srflx->addr)) {
|
||||
|
@ -325,6 +323,8 @@ int nr_ice_candidate_destroy(nr_ice_candidate **candp)
|
|||
case RELAYED:
|
||||
if (cand->u.relayed.turn_handle)
|
||||
nr_ice_socket_deregister(cand->isock, cand->u.relayed.turn_handle);
|
||||
if (cand->u.relayed.srvflx_candidate)
|
||||
cand->u.relayed.srvflx_candidate->u.srvrflx.relay_candidate=0;
|
||||
nr_turn_client_ctx_destroy(&cand->u.relayed.turn);
|
||||
nr_socket_destroy(&cand->u.relayed.turn_sock);
|
||||
break;
|
||||
|
@ -332,6 +332,8 @@ int nr_ice_candidate_destroy(nr_ice_candidate **candp)
|
|||
case SERVER_REFLEXIVE:
|
||||
if (cand->u.srvrflx.stun_handle)
|
||||
nr_ice_socket_deregister(cand->isock, cand->u.srvrflx.stun_handle);
|
||||
if (cand->u.srvrflx.relay_candidate)
|
||||
cand->u.srvrflx.relay_candidate->u.relayed.srvflx_candidate=0;
|
||||
nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -76,6 +76,9 @@ struct nr_ice_candidate_ {
|
|||
struct {
|
||||
nr_stun_client_ctx *stun;
|
||||
void *stun_handle;
|
||||
/* If this is a srflx that is piggybacking on a relay candidate, this is
|
||||
* a back pointer to that relay candidate. */
|
||||
nr_ice_candidate *relay_candidate;
|
||||
} srvrflx;
|
||||
struct {
|
||||
nr_turn_client_ctx *turn;
|
||||
|
|
|
@ -286,7 +286,10 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
|
|||
isock,turn_sock,RELAYED,0,
|
||||
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
|
||||
ABORT(r);
|
||||
cand->u.relayed.srvflx_candidate=srvflx_cand;
|
||||
if (srvflx_cand) {
|
||||
cand->u.relayed.srvflx_candidate=srvflx_cand;
|
||||
srvflx_cand->u.srvrflx.relay_candidate=cand;
|
||||
}
|
||||
cand->u.relayed.server=&ctx->turn_servers[j];
|
||||
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
|
||||
component->candidate_ct++;
|
||||
|
|
|
@ -21,6 +21,20 @@
|
|||
#include "nsTraceRefcnt.h"
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_CRASHREPORTER) && defined(MOZILLA_INTERNAL_API) && \
|
||||
!defined(MOZILLA_EXTERNAL_LINKAGE) && defined(__cplusplus)
|
||||
# define MOZ_CRASH_CRASHREPORT
|
||||
namespace CrashReporter {
|
||||
// This declaration is present here as well as in nsExceptionHandler.h
|
||||
// nsExceptionHandler.h is not directly included in this file as it includes
|
||||
// windows.h, which can cause problems when it is imported into some files due
|
||||
// to the number of macros defined.
|
||||
// XXX If you change this definition - also change the definition in
|
||||
// nsExceptionHandler.h
|
||||
void AnnotateMozCrashReason(const char* aReason);
|
||||
} // namespace CrashReporter
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -249,7 +263,15 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
|
|||
* corrupted.
|
||||
*/
|
||||
#ifndef DEBUG
|
||||
# define MOZ_CRASH(...) MOZ_REALLY_CRASH()
|
||||
# ifdef MOZ_CRASH_CRASHREPORT
|
||||
# define MOZ_CRASH(...) \
|
||||
do { \
|
||||
CrashReporter::AnnotateMozCrashReason("MOZ_CRASH(" __VA_ARGS__ ")"); \
|
||||
MOZ_REALLY_CRASH(); \
|
||||
} while (0)
|
||||
# else
|
||||
# define MOZ_CRASH(...) MOZ_REALLY_CRASH()
|
||||
# endif
|
||||
#else
|
||||
# define MOZ_CRASH(...) \
|
||||
do { \
|
||||
|
@ -509,5 +531,6 @@ struct AssertionConditionType
|
|||
#endif
|
||||
|
||||
#undef MOZ_DUMP_ASSERTION_STACK
|
||||
#undef MOZ_CRASH_CRASHREPORT
|
||||
|
||||
#endif /* mozilla_Assertions_h */
|
||||
|
|
|
@ -24,7 +24,7 @@ interface nsIVerificationCallback;
|
|||
* https://wiki.mozilla.org/FirefoxOS/New_security_model/Packaging
|
||||
*/
|
||||
|
||||
[scriptable, uuid(d0a98a69-a215-4cf9-abb3-7a0b9237cd27)]
|
||||
[scriptable, uuid(cc245638-6a38-4f70-8d77-21c55aabd636)]
|
||||
interface nsIPackagedAppUtils : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -48,6 +48,12 @@ interface nsIPackagedAppUtils : nsISupports
|
|||
void checkIntegrity(in ACString aFileName,
|
||||
in ACString aHashValue,
|
||||
in nsIVerificationCallback aVerifier);
|
||||
|
||||
/**
|
||||
* The package identifier for signed package. Only available after the
|
||||
* manifest is verified.
|
||||
*/
|
||||
readonly attribute ACString packageIdentifier;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -422,14 +422,16 @@ nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
|
|||
}
|
||||
|
||||
bool
|
||||
nsStandardURL::ValidIPv6orHostname(const char *host)
|
||||
nsStandardURL::ValidIPv6orHostname(const char *host, uint32_t length)
|
||||
{
|
||||
if (!host || !*host) {
|
||||
// Should not be NULL or empty string
|
||||
if (!host) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t length = strlen(host);
|
||||
if (length != strlen(host)) {
|
||||
// Embedded null
|
||||
return false;
|
||||
}
|
||||
|
||||
bool openBracket = host[0] == '[';
|
||||
bool closeBracket = host[length - 1] == ']';
|
||||
|
@ -443,8 +445,9 @@ nsStandardURL::ValidIPv6orHostname(const char *host)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (PL_strchr(host, ':')) {
|
||||
// Hostnames should not contain a colon
|
||||
const char *end = host + length;
|
||||
if (end != net_FindCharInSet(host, end, "\t\n\v\f\r #/:?@[\\]")) {
|
||||
// % is allowed because we don't do hostname percent decoding yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -582,6 +585,11 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
|
|||
approxLen += encHost.Length();
|
||||
else
|
||||
approxLen += mHost.mLen;
|
||||
|
||||
if ((useEncHost && !ValidIPv6orHostname(encHost.BeginReading(), encHost.Length())) ||
|
||||
(!useEncHost && !ValidIPv6orHostname(tempHost.BeginReading(), tempHost.Length()))) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1609,14 +1617,10 @@ nsStandardURL::SetHost(const nsACString &input)
|
|||
if (strchr(host, ' '))
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
if (!ValidIPv6orHostname(host)) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
InvalidateCache();
|
||||
mHostEncoding = eEncoding_ASCII;
|
||||
|
||||
int32_t len;
|
||||
uint32_t len;
|
||||
nsAutoCString hostBuf;
|
||||
if (NormalizeIDN(flat, hostBuf)) {
|
||||
host = hostBuf.get();
|
||||
|
@ -1625,6 +1629,10 @@ nsStandardURL::SetHost(const nsACString &input)
|
|||
else
|
||||
len = flat.Length();
|
||||
|
||||
if (!ValidIPv6orHostname(host, len)) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
if (mHost.mLen < 0) {
|
||||
int port_length = 0;
|
||||
if (mPort != -1) {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче