mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Merge m-c to fx-team, a=merge
--HG-- extra : commitid : JfOXHrexxbp
This commit is contained in:
commit
def31b952c
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber
|
||||
Merge day clobber
|
||||
|
@ -1153,6 +1153,12 @@ pref("dom.performance.enable_notify_performance_timing", true);
|
||||
pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html");
|
||||
pref("b2g.multiscreen.system_remote_url", "index_remote.html");
|
||||
|
||||
// Blocklist service
|
||||
pref("extensions.blocklist.enabled", true);
|
||||
pref("extensions.blocklist.interval", 86400);
|
||||
pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
|
||||
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
|
||||
|
||||
// Because we can't have nice things.
|
||||
#ifdef MOZ_GRAPHENE
|
||||
#include ../graphene/graphene.js
|
||||
|
@ -24,7 +24,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
@ -154,5 +154,5 @@
|
||||
<!-- Shinano specific things -->
|
||||
<project name="device-shinano" path="device/sony/leo" remote="b2g" revision="653f7e1f093b948e40262fcb3c665c2b4976df74"/>
|
||||
<!-- Aries specific things -->
|
||||
<project name="device-aries" path="device/sony/aries" remote="b2g" revision="2916e2368074b5383c80bf5a0fba3fc83ba310bd"/>
|
||||
<project name="device-aries" path="device/sony/aries" remote="b2g" revision="a19052e4389c3ae2d8fc3e7a74a475401baacc56"/>
|
||||
</manifest>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
|
@ -20,7 +20,7 @@
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="91cac94948094cfdcd00cba5c6483e27e80cb3b0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="27de93fe66c3e80e157d157bd52ca99565351669"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="91cac94948094cfdcd00cba5c6483e27e80cb3b0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="27de93fe66c3e80e157d157bd52ca99565351669"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
|
||||
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
|
@ -10,7 +10,7 @@ MOZ_APP_UA_NAME=Firefox
|
||||
|
||||
MOZ_UA_OS_AGNOSTIC=1
|
||||
|
||||
MOZ_B2G_VERSION=2.5.0.0-prerelease
|
||||
MOZ_B2G_VERSION=2.6.0.0-prerelease
|
||||
MOZ_B2G_OS_NAME=Boot2Gecko
|
||||
|
||||
MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
|
||||
|
@ -7,7 +7,10 @@ GAIA_PATH := $(if MOZ_B2GDROID,gaia/assets/gaia,gaia/profile)
|
||||
|
||||
# For b2gdroid, we disable the screen timeout since this is managed by android.
|
||||
# We also limit the app set to the production ones.
|
||||
GAIA_OPTIONS := $(if MOZ_B2GDROID,GAIA_DISTRIBUTION_DIR=distros/b2gdroid,)
|
||||
GAIA_OPTIONS := $(if MOZ_B2GDROID, \
|
||||
GAIA_DISTRIBUTION_DIR=distros/b2gdroid \
|
||||
NO_LOCK_SCREEN=1 \
|
||||
)
|
||||
|
||||
GENERATED_DIRS += $(DIST)/bin/$(GAIA_PATH)
|
||||
|
||||
|
@ -17,7 +17,7 @@ MOZ_GRAPHENE=1
|
||||
MOZ_APP_VERSION=$FIREFOX_VERSION
|
||||
MOZ_APP_UA_NAME=Firefox
|
||||
|
||||
MOZ_B2G_VERSION=3.0.0.0-prerelease
|
||||
MOZ_B2G_VERSION=2.6.0.0-prerelease
|
||||
MOZ_B2G_OS_NAME=Boot2Gecko
|
||||
|
||||
MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
|
||||
|
@ -537,15 +537,16 @@
|
||||
#endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
@RESPATH@/components/extensions.manifest
|
||||
@RESPATH@/components/addonManager.js
|
||||
@RESPATH@/components/amContentHandler.js
|
||||
@RESPATH@/components/amInstallTrigger.js
|
||||
@RESPATH@/components/amWebInstallListener.js
|
||||
@RESPATH@/components/nsBlocklistService.js
|
||||
|
||||
@RESPATH@/components/OopCommandLine.js
|
||||
@RESPATH@/components/CommandLine.js
|
||||
#endif
|
||||
@RESPATH@/components/extensions.manifest
|
||||
@RESPATH@/components/nsBlocklistService.js
|
||||
@RESPATH@/components/BootstrapCommandLine.js
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
|
@ -1530,8 +1530,13 @@ pref("ui.key.menuAccessKeyFocuses", true);
|
||||
pref("media.eme.enabled", true);
|
||||
pref("media.eme.apiVisible", true);
|
||||
|
||||
// If decoding-via-gmp is turned on for <video>, default to using
|
||||
// Adobe's GMP for decoding.
|
||||
// Decode using Gecko Media Plugins in <video>, if a system decoder is not
|
||||
// availble and the preferred GMP is available.
|
||||
pref("media.gmp.decoder.enabled", true);
|
||||
|
||||
// If decoding-via-GMP is turned on for <video>, use Adobe's GMP for decoding,
|
||||
// if it's available. Note: We won't fallback to another GMP if Adobe's is not
|
||||
// installed.
|
||||
pref("media.gmp.decoder.aac", 2);
|
||||
pref("media.gmp.decoder.h264", 2);
|
||||
|
||||
|
@ -224,7 +224,33 @@ if test "$GNU_CXX"; then
|
||||
elif test "$ac_cv_cxx0x_headers_bug" = "yes"; then
|
||||
AC_MSG_ERROR([Your toolchain does not support C++0x/C++11 mode properly. Please upgrade your toolchain])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether 64-bits std::atomic requires -latomic],
|
||||
ac_cv_needs_atomic,
|
||||
AC_TRY_LINK(
|
||||
[#include <cstdint>
|
||||
#include <atomic>],
|
||||
[ std::atomic<uint64_t> foo; foo = 1; ],
|
||||
ac_cv_needs_atomic=no,
|
||||
_SAVE_LIBS="$LIBS"
|
||||
LIBS="$LIBS -latomic"
|
||||
AC_TRY_LINK(
|
||||
[#include <cstdint>
|
||||
#include <atomic>],
|
||||
[ std::atomic<uint64_t> foo; foo = 1; ],
|
||||
ac_cv_needs_atomic=yes,
|
||||
ac_cv_needs_atomic="do not know; assuming no")
|
||||
LIBS="$_SAVE_LIBS"
|
||||
)
|
||||
)
|
||||
if test "$ac_cv_needs_atomic" = yes; then
|
||||
MOZ_NEEDS_LIBATOMIC=1
|
||||
else
|
||||
MOZ_NEEDS_LIBATOMIC=
|
||||
fi
|
||||
AC_SUBST(MOZ_NEEDS_LIBATOMIC)
|
||||
fi
|
||||
|
||||
if test -n "$CROSS_COMPILE"; then
|
||||
dnl When cross compile, we have no variable telling us what the host compiler is. Figure it out.
|
||||
cat > conftest.C <<EOF
|
||||
|
@ -4979,7 +4979,7 @@ AC_SUBST(MOZ_WEBRTC_HAVE_ETHTOOL_SPEED_HI)
|
||||
|
||||
# target_arch is from {ia32|x64|arm|ppc}
|
||||
case "$CPU_ARCH" in
|
||||
x86_64 | arm | x86 | ppc* | ia64)
|
||||
x86_64 | arm | aarch64 | x86 | ppc* | ia64)
|
||||
:
|
||||
;;
|
||||
*)
|
||||
|
@ -131,6 +131,10 @@ function _setAppProperties(aObj, aApp) {
|
||||
aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
|
||||
aObj.sideloaded = aApp.sideloaded;
|
||||
aObj.extensionVersion = aApp.extensionVersion;
|
||||
aObj.blockedStatus =
|
||||
aApp.blockedStatus !== undefined ? aApp.blockedStatus
|
||||
: Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
aObj.blocklistId = aApp.blocklistId;
|
||||
#ifdef MOZ_B2GDROID
|
||||
aObj.android_packagename = aApp.android_packagename;
|
||||
aObj.android_classname = aApp.android_classname;
|
||||
|
@ -251,7 +251,9 @@ this.ImportExport = {
|
||||
throw "NoManifestFound";
|
||||
}
|
||||
|
||||
return [readObjectFromZip(appZipReader, "manifest.webapp"), file];
|
||||
return [readObjectFromZip(appZipReader, "manifest.webapp"),
|
||||
readObjectFromZip(appZipReader, "update.webapp"),
|
||||
file];
|
||||
},
|
||||
|
||||
// Returns a promise that resolves to the temp file path.
|
||||
@ -307,6 +309,7 @@ this.ImportExport = {
|
||||
let meta;
|
||||
let appDir;
|
||||
let manifest;
|
||||
let updateManifest;
|
||||
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
|
||||
.createInstance(Ci.nsIZipReader);
|
||||
try {
|
||||
@ -353,7 +356,7 @@ this.ImportExport = {
|
||||
let appFile;
|
||||
|
||||
if (isPackage) {
|
||||
[manifest, appFile] =
|
||||
[manifest, updateManifest, appFile] =
|
||||
this._importPackagedApp(zipReader, meta.manifestURL, appDir);
|
||||
} else {
|
||||
manifest = this._importHostedApp(zipReader, meta.manifestURL);
|
||||
@ -395,6 +398,11 @@ this.ImportExport = {
|
||||
meta.installerIsBrowser = false;
|
||||
meta.role = manifest.role;
|
||||
|
||||
// If there is an id in the mini-manifest, use it for blocklisting purposes.
|
||||
if (isPackage && updateManifest && ("id" in updateManifest)) {
|
||||
meta.blocklistId = updateManifest["id"];
|
||||
}
|
||||
|
||||
let devMode = false;
|
||||
try {
|
||||
devMode = Services.prefs.getBoolPref("dom.apps.developer_mode");
|
||||
|
@ -348,6 +348,10 @@ this.DOMApplicationRegistry = {
|
||||
app.enabled = true;
|
||||
}
|
||||
|
||||
if (app.blockedStatus === undefined) {
|
||||
app.blockedStatus = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
}
|
||||
|
||||
// At startup we can't be downloading, and the $TMP directory
|
||||
// will be empty so we can't just apply a staged update.
|
||||
app.downloading = false;
|
||||
@ -1211,6 +1215,7 @@ this.DOMApplicationRegistry = {
|
||||
ppmm.removeMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
Services.obs.removeObserver(this, "memory-pressure");
|
||||
cpmm = null;
|
||||
ppmm = null;
|
||||
if (AppConstants.MOZ_B2GDROID) {
|
||||
@ -1222,6 +1227,55 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
},
|
||||
|
||||
// Check extensions to be blocked.
|
||||
blockExtensions: function(aExtensions) {
|
||||
debug("blockExtensions");
|
||||
let app;
|
||||
let runtime = Services.appinfo.QueryInterface(Ci.nsIXULRuntime);
|
||||
|
||||
aExtensions.filter(extension => {
|
||||
// Filter out id-less items and those who don't have a matching installed
|
||||
// extension.
|
||||
if (!extension.attributes.has("id")) {
|
||||
return false;
|
||||
}
|
||||
// Check that we have an app with this extension id.
|
||||
let extId = extension.attributes.get("id");
|
||||
for (let id in this.webapps) {
|
||||
if (this.webapps[id].blocklistId == extId) {
|
||||
app = this.webapps[id];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// No webapp found for this extension id.
|
||||
return false;
|
||||
}).forEach(extension => {
|
||||
// `extension` is a object such as:
|
||||
// {"versions":[{"minVersion":"0.1",
|
||||
// "maxVersion":"1.3.328.4",
|
||||
// "severity":"1",
|
||||
// "vulnerabilityStatus":0,
|
||||
// "targetApps":{
|
||||
// "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}":[{"minVersion":"3.7a1pre","maxVersion":"*"}]
|
||||
// }
|
||||
// }],
|
||||
// "prefs":[],
|
||||
// "blockID":"i24",
|
||||
// "attributes": Map()
|
||||
// }
|
||||
//
|
||||
// `versions` is array of BlocklistItemData (see nsBlocklistService.js)
|
||||
let severity = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
for (let item of extension.versions) {
|
||||
if (item.includesItem(app.extensionVersion, runtime.version, runtime.platformVersion)) {
|
||||
severity = item.severity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.setBlockedStatus(app.manifestURL, severity);
|
||||
});
|
||||
},
|
||||
|
||||
formatMessage: function(aData) {
|
||||
let msg = aData;
|
||||
delete msg["mm"];
|
||||
@ -1919,6 +1973,9 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
delete app.retryingDownload;
|
||||
|
||||
// Once updated we are not in the blocklist anymore.
|
||||
app.blockedStatus = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
|
||||
// Update the asm.js scripts we need to compile.
|
||||
yield ScriptPreloader.preload(app, newManifest);
|
||||
|
||||
@ -2961,6 +3018,10 @@ this.DOMApplicationRegistry = {
|
||||
this._writeManifestFile(app.id, false, aManifest);
|
||||
if (aUpdateManifest) {
|
||||
this._writeManifestFile(app.id, true, aUpdateManifest);
|
||||
// If there is an id in the mini-manifest, use it for blocklisting purposes.
|
||||
if (aData.isPackage && ("id" in aUpdateManifest)) {
|
||||
this.webapps[app.id].blocklistId = aUpdateManifest["id"];
|
||||
}
|
||||
}
|
||||
|
||||
this._saveApps().then(() => {
|
||||
@ -2995,6 +3056,10 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest;
|
||||
yield this._writeManifestFile(id, aData.isPackage, jsonManifest);
|
||||
// If there is an id in the mini-manifest, use it for blocklisting purposes.
|
||||
if (aData.isPackage && ("id" in jsonManifest)) {
|
||||
app.blocklistId = jsonManifest["id"];
|
||||
}
|
||||
|
||||
debug("app.origin: " + app.origin);
|
||||
let manifest =
|
||||
@ -4581,6 +4646,20 @@ this.DOMApplicationRegistry = {
|
||||
});
|
||||
},
|
||||
|
||||
setBlockedStatus: function(aManifestURL, aSeverity) {
|
||||
let id = this._appIdForManifestURL(aManifestURL);
|
||||
if (!id || !this.webapps[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug(`Setting blocked status ${aSeverity} on ${id}`);
|
||||
let app = this.webapps[id];
|
||||
|
||||
app.blockedStatus = aSeverity;
|
||||
let enabled = aSeverity == Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
this.setEnabled({ manifestURL: aManifestURL, enabled });
|
||||
},
|
||||
|
||||
setEnabled: function(aData) {
|
||||
debug("setEnabled " + aData.manifestURL + " : " + aData.enabled);
|
||||
let id = this._appIdForManifestURL(aData.manifestURL);
|
||||
@ -4590,7 +4669,13 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
debug("Enabling " + id);
|
||||
let app = this.webapps[id];
|
||||
app.enabled = aData.enabled;
|
||||
|
||||
// If we try to enable an app, check if it's not blocked.
|
||||
if (!aData.enabled ||
|
||||
app.blockedStatus == Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
|
||||
app.enabled = aData.enabled;
|
||||
}
|
||||
|
||||
this._saveApps().then(() => {
|
||||
MessageBroadcaster.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
|
@ -2,5 +2,6 @@
|
||||
"name": "Addon app",
|
||||
"description": "Let me inject script and css!",
|
||||
"developer": { "name": "The Mozilla Community" },
|
||||
"package_path" : "application.zip"
|
||||
"package_path" : "application.zip",
|
||||
"id": "webextension@mochitest"
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ support-files =
|
||||
|
||||
[test_app_addons.html]
|
||||
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
[test_app_blocklist.html]
|
||||
skip-if = buildapp != 'mulet' # we need MOZ_B2G defined and the test to run in the parent process.
|
||||
[test_app_enabled.html]
|
||||
[test_app_update.html]
|
||||
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
|
193
dom/apps/tests/test_app_blocklist.html
Normal file
193
dom/apps/tests/test_app_blocklist.html
Normal file
@ -0,0 +1,193 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id={1208242}
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug {1208242}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1208242}">Mozilla Bug {1208242}</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
|
||||
var baseURL = "http://mochi.test:8888/tests/dom/apps/tests/addons/";
|
||||
var appManifestURL = baseURL + "update.webapp";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gGenerator = runTest();
|
||||
|
||||
// Utilities to turn off auto update of the blocklist.
|
||||
// Copied from toolkit/mozapps/extensions/test/browser/head.js
|
||||
var gCatMan = SpecialPowers.Cc["@mozilla.org/categorymanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsICategoryManager);
|
||||
|
||||
var UTIMER = "update-timer";
|
||||
var BLOCKLIST = "nsBlocklistService";
|
||||
|
||||
var blocklistUpdateConfig = "@mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400";
|
||||
|
||||
function disableBlocklistUpdateTimer() {
|
||||
info("Disabling " + UTIMER + " " + BLOCKLIST);
|
||||
blocklistUpdateConfig = gCatMan.getCategoryEntry(UTIMER, BLOCKLIST);
|
||||
gCatMan.deleteCategoryEntry(UTIMER, BLOCKLIST, true);
|
||||
}
|
||||
|
||||
function enableBlocklistUpdateTimer() {
|
||||
info("Enabling " + UTIMER + " " + BLOCKLIST);
|
||||
gCatMan.addCategoryEntry(UTIMER, BLOCKLIST, blocklistUpdateConfig, false, true);
|
||||
}
|
||||
|
||||
// End of utilities
|
||||
|
||||
function go() {
|
||||
disableBlocklistUpdateTimer();
|
||||
SpecialPowers.allowUnsignedAddons();
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "webapps-manage", "allow": 1, "context": document }],
|
||||
function() { gGenerator.next() });
|
||||
}
|
||||
|
||||
function continueTest() {
|
||||
try {
|
||||
gGenerator.next();
|
||||
} catch (e if e instanceof StopIteration) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function finish() {
|
||||
enableBlocklistUpdateTimer();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function cbError(aEvent) {
|
||||
ok(false, "Error callback invoked " +
|
||||
aEvent.target.error.name + " " + aEvent.target.error.message);
|
||||
finish();
|
||||
}
|
||||
|
||||
function mozAppsError() {
|
||||
ok(false, "mozApps error: " + this.error.name);
|
||||
SpecialPowers.debugUserCustomizations(false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function installApp(manifestURL) {
|
||||
info("About to install app at " + manifestURL);
|
||||
let req = navigator.mozApps.installPackage(manifestURL);
|
||||
req.onsuccess = function() {
|
||||
is(req.result.manifestURL, manifestURL, "app installed");
|
||||
if (req.result.installState == "installed") {
|
||||
is(req.result.manifest.version, "1.0", "correct version");
|
||||
is(req.result.installState, "installed", "app downloaded");
|
||||
continueTest();
|
||||
} else {
|
||||
req.result.ondownloadapplied = function() {
|
||||
is(req.result.manifest.version, "1.0", "correct version");
|
||||
is(req.result.installState, "installed", "app downloaded");
|
||||
continueTest();
|
||||
}
|
||||
|
||||
req.result.ondownloaderror = function() {
|
||||
ok(false, "unexpected installation error: " + req.result.downloadError.name);
|
||||
continueTest();
|
||||
}
|
||||
}
|
||||
}
|
||||
req.onerror = mozAppsError;
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test blocking of an add-on.
|
||||
*/
|
||||
function runTest() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
request = navigator.mozApps.mgmt.getAll();
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
yield undefined;
|
||||
var initialAppsCount = request.result.length;
|
||||
info("Starting with " + initialAppsCount + " apps installed.");
|
||||
|
||||
// Install valid addon app.
|
||||
var req = installApp(appManifestURL, false);
|
||||
yield undefined;
|
||||
|
||||
var app = req.result;
|
||||
|
||||
ok(app, "App is non-null");
|
||||
is(app.manifestURL, appManifestURL, "App manifest url is correct.");
|
||||
is(app.enabled, true, "App is enabled by default after install.");
|
||||
|
||||
// Check that the app is disabled
|
||||
navigator.mozApps.mgmt.onenabledstatechange = function(event) {
|
||||
ok(true, "onenabledstatechange received");
|
||||
is(event.application.enabled, false, "Application is disabled");
|
||||
continueTest();
|
||||
}
|
||||
|
||||
// Trigger the blocklist by passing an XML blocklist string.
|
||||
var blocklist =
|
||||
`<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1443544016000">
|
||||
<emItems>
|
||||
<emItem blockID="i00" id="webextension@mochitest">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="1"> </versionRange>
|
||||
</emItem>
|
||||
</emItems>
|
||||
</blocklist>`;
|
||||
|
||||
var bls = SpecialPowers.Cc["@mozilla.org/extensions/blocklist;1"]
|
||||
.getService(SpecialPowers.Ci.nsIBlocklistService).wrappedJSObject;
|
||||
bls._loadBlocklistFromString(blocklist);
|
||||
|
||||
//navigator.mozApps.mgmt.setEnabled(app, true);
|
||||
yield undefined;
|
||||
|
||||
// Cleaning up after ourselves.
|
||||
navigator.mozApps.mgmt.onuninstall = function(event) {
|
||||
var app = event.application;
|
||||
is(app.manifestURL, appManifestURL, "App uninstall event ok.");
|
||||
is(app.manifest.name, "Addon app", "App uninstall manifest ok.");
|
||||
continueTest();
|
||||
}
|
||||
request = navigator.mozApps.mgmt.uninstall(app);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
yield undefined;
|
||||
yield undefined;
|
||||
is(request.result, appManifestURL, "App uninstalled.");
|
||||
navigator.mozApps.mgmt.onuninstall = null;
|
||||
|
||||
request = navigator.mozApps.mgmt.getAll();
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
yield undefined;
|
||||
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
|
||||
}
|
||||
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef B2G_BDROID_BUILDCFG_H
|
||||
#define B2G_BDROID_BUILDCFG_H
|
||||
|
||||
/**
|
||||
* This header defines B2G common bluedroid build configuration.
|
||||
*
|
||||
* This header is included by
|
||||
* $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR)/bdroid_buildcfg.h,
|
||||
* which applies external configuration onto bluedroid.
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** HSP, HFP
|
||||
**
|
||||
******************************************************************************/
|
||||
/* AG feature masks */
|
||||
#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
|
||||
BTA_AG_FEAT_ECNR | \
|
||||
BTA_AG_FEAT_REJECT | \
|
||||
BTA_AG_FEAT_ECS | \
|
||||
BTA_AG_FEAT_EXTERR)
|
||||
|
||||
/* CHLD values */
|
||||
#define BTA_AG_CHLD_VAL "(0,1,2,3)"
|
||||
/* SDP AVRCP 1.5 feature */
|
||||
#define SDP_AVRCP_1_5 FALSE
|
||||
|
||||
/* BLE Feature */
|
||||
#define BTA_GATT_INCLUDED TRUE
|
||||
#define BLE_INCLUDED TRUE
|
||||
#define SMP_INCLUDED TRUE
|
||||
|
||||
#endif /* B2G_BDROID_BUILDCFG_H */
|
@ -2172,6 +2172,7 @@ nsGonkCameraControl::LoadRecorderProfiles()
|
||||
|
||||
nsTArray<RecorderProfile>::size_type bestIndexMatch = 0;
|
||||
int bestAreaMatch = 0;
|
||||
uint32_t bestPriorityMatch = UINT32_MAX;
|
||||
|
||||
// Limit profiles to those video sizes supported by the camera hardware...
|
||||
for (nsTArray<RecorderProfile>::size_type i = 0; i < profiles.Length(); ++i) {
|
||||
@ -2186,17 +2187,22 @@ nsGonkCameraControl::LoadRecorderProfiles()
|
||||
if (static_cast<uint32_t>(width) == sizes[n].width &&
|
||||
static_cast<uint32_t>(height) == sizes[n].height) {
|
||||
mRecorderProfiles.Put(profiles[i]->GetName(), profiles[i]);
|
||||
|
||||
// "Best" or default profile is the one with the lowest priority
|
||||
// value and largest area.
|
||||
int area = width * height;
|
||||
if (area > bestAreaMatch) {
|
||||
uint32_t priority = profiles[i]->GetPriority();
|
||||
if (bestPriorityMatch > priority ||
|
||||
(bestPriorityMatch == priority && area > bestAreaMatch)) {
|
||||
bestIndexMatch = i;
|
||||
bestAreaMatch = area;
|
||||
bestPriorityMatch = priority;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default profile is the one with the largest area.
|
||||
if (bestAreaMatch > 0) {
|
||||
nsAutoString name;
|
||||
name.AssignASCII("default");
|
||||
|
@ -31,9 +31,10 @@ namespace mozilla {
|
||||
struct ProfileConfig {
|
||||
const char* name;
|
||||
int quality;
|
||||
uint32_t priority;
|
||||
};
|
||||
|
||||
#define DEF_GONK_RECORDER_PROFILE(e, n) { n, e },
|
||||
#define DEF_GONK_RECORDER_PROFILE(e, n, p) { n, e, p },
|
||||
static const ProfileConfig ProfileList[] = {
|
||||
#include "GonkRecorderProfiles.def"
|
||||
};
|
||||
@ -44,9 +45,10 @@ struct ProfileConfigDetect {
|
||||
const char* name;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t priority;
|
||||
};
|
||||
|
||||
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h) { n, w, h },
|
||||
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h, p) { n, w, h, p },
|
||||
static const ProfileConfigDetect ProfileListDetect[] = {
|
||||
#include "GonkRecorderProfiles.def"
|
||||
};
|
||||
@ -322,6 +324,7 @@ GonkRecorderProfile::GetProfileHashtable(uint32_t aCameraId)
|
||||
|
||||
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", p.quality, p.name);
|
||||
profile->mName.AssignASCII(p.name);
|
||||
profile->mPriority = p.priority;
|
||||
profiles->Put(profile->GetName(), profile);
|
||||
}
|
||||
|
||||
@ -351,6 +354,7 @@ GonkRecorderProfile::GetProfileHashtable(uint32_t aCameraId)
|
||||
if (s.width == p.width && s.height == p.height) {
|
||||
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", q, p.name);
|
||||
profile->mName.AssignASCII(p.name);
|
||||
profile->mPriority = p.priority;
|
||||
profiles->Put(profile->GetName(), profile);
|
||||
break;
|
||||
}
|
||||
|
@ -19,20 +19,24 @@
|
||||
*/
|
||||
|
||||
#ifndef DEF_GONK_RECORDER_PROFILE
|
||||
#define DEF_GONK_RECORDER_PROFILE(e, n)
|
||||
#define DEF_GONK_RECORDER_PROFILE(e, n, p)
|
||||
#endif
|
||||
|
||||
#ifndef DEF_GONK_RECORDER_PROFILE_DETECT
|
||||
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h)
|
||||
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h, p)
|
||||
#endif
|
||||
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_LOW, "low")
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_HIGH, "high")
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_QCIF, "qcif")
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_CIF, "cif")
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_480P, "480p")
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_720P, "720p")
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_1080P, "1080p")
|
||||
/* Enum value, name, and priority. The supported profile with the
|
||||
* lowest priority and then largest area is selected as the default.
|
||||
*/
|
||||
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_LOW, "low", 900)
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_HIGH, "high", 900)
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_QCIF, "qcif", 300)
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_CIF, "cif", 300)
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_480P, "480p", 200)
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_720P, "720p", 100)
|
||||
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_1080P, "1080p", 0)
|
||||
|
||||
/**
|
||||
* The following profiles do not appear in all versions of the
|
||||
@ -40,15 +44,15 @@ DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_1080P, "1080p")
|
||||
* profiles may have more than one resolution, depending on the camera.
|
||||
*/
|
||||
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("4kuhd", 3840, 2160)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 864, 480)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 854, 480)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 800, 480)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 768, 480)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("vga", 640, 480)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("hvga", 480, 320)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("wqvga", 400, 240)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("qvga", 320, 240)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("4kuhd", 3840, 2160, 800)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 864, 480, 200)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 854, 480, 200)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 800, 480, 200)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 768, 480, 200)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("vga", 640, 480, 200)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("hvga", 480, 320, 300)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("wqvga", 400, 240, 300)
|
||||
DEF_GONK_RECORDER_PROFILE_DETECT("qvga", 320, 240, 300)
|
||||
|
||||
#undef DEF_GONK_RECORDER_PROFILE
|
||||
#undef DEF_GONK_RECORDER_PROFILE_DETECT
|
||||
|
@ -219,6 +219,7 @@ public:
|
||||
const nsString& GetName() const { return mName; }
|
||||
const nsString& GetContainer() const { return mContainer; }
|
||||
const nsString& GetMimeType() const { return mMimeType; }
|
||||
uint32_t GetPriority() const { return mPriority; }
|
||||
|
||||
virtual const Video& GetVideo() const = 0;
|
||||
virtual const Audio& GetAudio() const = 0;
|
||||
@ -229,6 +230,7 @@ public:
|
||||
nsString mName;
|
||||
nsString mContainer;
|
||||
nsString mMimeType;
|
||||
uint32_t mPriority;
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(RecorderProfile);
|
||||
|
@ -517,7 +517,6 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
++gMouseOrKeyboardEventCounter;
|
||||
|
||||
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aTargetContent);
|
||||
if (node &&
|
||||
(aEvent->mMessage == eKeyUp || aEvent->mMessage == eMouseUp ||
|
||||
@ -599,6 +598,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
StopTrackingDragGesture();
|
||||
sNormalLMouseEventInProcess = false;
|
||||
// then fall through...
|
||||
MOZ_FALLTHROUGH;
|
||||
case WidgetMouseEvent::eRightButton:
|
||||
case WidgetMouseEvent::eMiddleButton:
|
||||
SetClickCount(aPresContext, mouseEvent, aStatus);
|
||||
@ -652,6 +652,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
aEvent->mMessage = eVoidEvent;
|
||||
break;
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
case eMouseMove:
|
||||
case ePointerDown:
|
||||
case ePointerMove: {
|
||||
@ -712,6 +713,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
// then fall through...
|
||||
MOZ_FALLTHROUGH;
|
||||
case eBeforeKeyDown:
|
||||
case eKeyDown:
|
||||
case eAfterKeyDown:
|
||||
@ -1199,7 +1201,7 @@ EventStateManager::IsRemoteTarget(nsIContent* target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
CrossProcessSafeEvent(const WidgetEvent& aEvent)
|
||||
{
|
||||
switch (aEvent.mClass) {
|
||||
@ -1235,7 +1237,7 @@ CrossProcessSafeEvent(const WidgetEvent& aEvent)
|
||||
case eDrop:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
@ -1371,7 +1373,6 @@ EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
|
||||
}
|
||||
} // CreateClickHoldTimer
|
||||
|
||||
|
||||
//
|
||||
// KillClickHoldTimer
|
||||
//
|
||||
@ -1386,7 +1387,6 @@ EventStateManager::KillClickHoldTimer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// sClickHoldCallback
|
||||
//
|
||||
@ -1404,7 +1404,6 @@ EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM)
|
||||
|
||||
} // sAutoHideCallback
|
||||
|
||||
|
||||
//
|
||||
// FireContextClick
|
||||
//
|
||||
@ -1529,7 +1528,6 @@ EventStateManager::FireContextClick()
|
||||
|
||||
} // FireContextClick
|
||||
|
||||
|
||||
//
|
||||
// BeginTrackingDragGesture
|
||||
//
|
||||
@ -3048,8 +3046,9 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
if(WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
|
||||
GenerateMouseEnterExit(mouseEvent);
|
||||
}
|
||||
// This break was commented specially
|
||||
// break;
|
||||
// After firing the pointercancel event, a user agent must also fire a
|
||||
// pointerout event followed by a pointerleave event.
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
case ePointerUp: {
|
||||
WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
|
||||
@ -4203,8 +4202,8 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
|
||||
// Update the last known refPoint with the current refPoint.
|
||||
sLastRefPoint = aMouseEvent->refPoint;
|
||||
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
case ePointerMove:
|
||||
case ePointerDown:
|
||||
{
|
||||
@ -5862,4 +5861,3 @@ AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher()
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -195,6 +195,7 @@
|
||||
#include "mozilla/widget/PuppetBidiKeyboard.h"
|
||||
#include "mozilla/RemoteSpellCheckEngineChild.h"
|
||||
#include "GMPServiceChild.h"
|
||||
#include "GMPDecoderModule.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
|
||||
|
||||
@ -1463,6 +1464,13 @@ ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvNotifyGMPsChanged()
|
||||
{
|
||||
GMPDecoderModule::UpdateUsableCodecs();
|
||||
return true;
|
||||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
|
||||
const uint32_t& processType)
|
||||
|
@ -287,6 +287,8 @@ public:
|
||||
const nsString& aSessionId) override;
|
||||
virtual bool RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId) override;
|
||||
|
||||
virtual bool RecvNotifyGMPsChanged() override;
|
||||
|
||||
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override;
|
||||
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override;
|
||||
|
||||
|
@ -693,6 +693,7 @@ static const char* sObserverTopics[] = {
|
||||
"profiler-subprocess-gather",
|
||||
"profiler-subprocess",
|
||||
#endif
|
||||
"gmp-changed",
|
||||
};
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
@ -3297,6 +3298,9 @@ ContentParent::Observe(nsISupports* aSubject,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(aTopic, "gmp-changed")) {
|
||||
unused << SendNotifyGMPsChanged();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -677,6 +677,11 @@ child:
|
||||
*/
|
||||
async NotifyPresentationReceiverCleanUp(nsString aSessionId);
|
||||
|
||||
/**
|
||||
* Notify the child that the Gecko Media Plugins installed changed.
|
||||
*/
|
||||
async NotifyGMPsChanged();
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Tell the content process some attributes of itself. This is
|
||||
|
@ -1600,7 +1600,8 @@ MediaDecoderOwner*
|
||||
MediaDecoder::GetOwner()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mOwner;
|
||||
// mOwner is valid until shutdown.
|
||||
return !mShuttingDown ? mOwner : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1878,6 +1878,15 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
break;
|
||||
|
||||
case dom::MediaSourceEnum::Browser:
|
||||
// If no window id is passed in then default to the caller's window.
|
||||
// Functional defaults are helpful in tests, but also a natural outcome
|
||||
// of the constraints API's limited semantics for requiring input.
|
||||
if (!vc.mBrowserWindow.WasPassed()) {
|
||||
nsPIDOMWindow *outer = aWindow->GetOuterWindow();
|
||||
vc.mBrowserWindow.Construct(outer->WindowID());
|
||||
}
|
||||
// | Fall through
|
||||
// V
|
||||
case dom::MediaSourceEnum::Screen:
|
||||
case dom::MediaSourceEnum::Application:
|
||||
case dom::MediaSourceEnum::Window:
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nsPrintfCString.h"
|
||||
#endif
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "GMPDecoderModule.h"
|
||||
#include <limits>
|
||||
|
||||
namespace mozilla {
|
||||
@ -700,6 +701,27 @@ GeckoMediaPluginServiceParent::LoadFromEnvironment()
|
||||
mScannedPluginOnDisk = true;
|
||||
}
|
||||
|
||||
class NotifyObserversTask final : public nsRunnable {
|
||||
public:
|
||||
explicit NotifyObserversTask(const char* aTopic, nsString aData = EmptyString())
|
||||
: mTopic(aTopic)
|
||||
, mData(aData)
|
||||
{}
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
|
||||
MOZ_ASSERT(obsService);
|
||||
if (obsService) {
|
||||
obsService->NotifyObservers(nullptr, mTopic, mData.get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
~NotifyObserversTask() {}
|
||||
const char* mTopic;
|
||||
const nsString mData;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginServiceParent::PathRunnable::Run()
|
||||
{
|
||||
@ -710,6 +732,16 @@ GeckoMediaPluginServiceParent::PathRunnable::Run()
|
||||
mOperation == REMOVE_AND_DELETE_FROM_DISK,
|
||||
mDefer);
|
||||
}
|
||||
#ifndef MOZ_WIDGET_GONK // Bug 1214967: disabled on B2G due to inscrutable test failures.
|
||||
// For e10s, we must fire a notification so that all ContentParents notify
|
||||
// their children to update the codecs that the GMPDecoderModule can use.
|
||||
NS_DispatchToMainThread(new NotifyObserversTask("gmp-changed"), NS_DISPATCH_NORMAL);
|
||||
// For non-e10s, and for decoding in the chrome process, must update GMP
|
||||
// PDM's codecs list directly.
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
|
||||
GMPDecoderModule::UpdateUsableCodecs();
|
||||
}));
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -935,27 +967,6 @@ GeckoMediaPluginServiceParent::ClonePlugin(const GMPParent* aOriginal)
|
||||
return gmp.get();
|
||||
}
|
||||
|
||||
class NotifyObserversTask final : public nsRunnable {
|
||||
public:
|
||||
explicit NotifyObserversTask(const char* aTopic, nsString aData = EmptyString())
|
||||
: mTopic(aTopic)
|
||||
, mData(aData)
|
||||
{}
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
|
||||
MOZ_ASSERT(obsService);
|
||||
if (obsService) {
|
||||
obsService->NotifyObservers(nullptr, mTopic, mData.get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
~NotifyObserversTask() {}
|
||||
const char* mTopic;
|
||||
const nsString mData;
|
||||
};
|
||||
|
||||
void
|
||||
GeckoMediaPluginServiceParent::AddOnGMPThread(const nsAString& aDirectory)
|
||||
{
|
||||
|
@ -250,10 +250,6 @@ PDMFactory::CreatePDMs()
|
||||
return;
|
||||
}
|
||||
|
||||
if (sGMPDecoderEnabled) {
|
||||
m = new GMPDecoderModule();
|
||||
StartupPDM(m);
|
||||
}
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled) {
|
||||
m = new AndroidDecoderModule();
|
||||
@ -291,6 +287,11 @@ PDMFactory::CreatePDMs()
|
||||
|
||||
m = new AgnosticDecoderModule();
|
||||
StartupPDM(m);
|
||||
|
||||
if (sGMPDecoderEnabled) {
|
||||
m = new GMPDecoderModule();
|
||||
StartupPDM(m);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -11,8 +11,12 @@
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "gmp-audio-decode.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -89,6 +93,71 @@ GMPDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
HasGMPFor(const nsACString& aAPI,
|
||||
const nsACString& aCodec,
|
||||
const nsACString& aGMP)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
#ifdef XP_WIN
|
||||
// gmp-clearkey uses WMF for decoding, so if we're using clearkey we must
|
||||
// verify that WMF works before continuing.
|
||||
if (aGMP.EqualsLiteral("org.w3.clearkey")) {
|
||||
RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
|
||||
if (aCodec.EqualsLiteral("aac") &&
|
||||
!pdm->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) {
|
||||
return false;
|
||||
}
|
||||
if (aCodec.EqualsLiteral("h264") &&
|
||||
!pdm->SupportsMimeType(NS_LITERAL_CSTRING("video/avc"))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(aCodec);
|
||||
tags.AppendElement(aGMP);
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return false;
|
||||
}
|
||||
bool hasPlugin = false;
|
||||
if (NS_FAILED(mps->HasPluginForAPI(aAPI, &tags, &hasPlugin))) {
|
||||
return false;
|
||||
}
|
||||
return hasPlugin;
|
||||
}
|
||||
|
||||
StaticMutex sGMPCodecsMutex;
|
||||
|
||||
struct GMPCodecs {
|
||||
const char* mKeySystem;
|
||||
bool mHasAAC;
|
||||
bool mHasH264;
|
||||
};
|
||||
|
||||
static GMPCodecs sGMPCodecs[] = {
|
||||
{ "org.w3.clearkey", false, false },
|
||||
{ "com.adobe.primetime", false, false },
|
||||
};
|
||||
|
||||
void
|
||||
GMPDecoderModule::UpdateUsableCodecs()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
StaticMutexAutoLock lock(sGMPCodecsMutex);
|
||||
for (GMPCodecs& gmp : sGMPCodecs) {
|
||||
gmp.mHasAAC = HasGMPFor(NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
|
||||
NS_LITERAL_CSTRING("aac"),
|
||||
nsDependentCString(gmp.mKeySystem));
|
||||
gmp.mHasH264 = HasGMPFor(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
|
||||
NS_LITERAL_CSTRING("h264"),
|
||||
nsDependentCString(gmp.mKeySystem));
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t sPreferredAacGmp = 0;
|
||||
static uint32_t sPreferredH264Gmp = 0;
|
||||
|
||||
@ -96,6 +165,13 @@ static uint32_t sPreferredH264Gmp = 0;
|
||||
void
|
||||
GMPDecoderModule::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// GMPService::HasPluginForAPI is main thread only, so to implement
|
||||
// SupportsMimeType() we build a table of the codecs which each whitelisted
|
||||
// GMP has and update it when any GMPs are removed or added at runtime.
|
||||
UpdateUsableCodecs();
|
||||
|
||||
Preferences::AddUintVarCache(&sPreferredAacGmp,
|
||||
"media.gmp.decoder.aac", 0);
|
||||
Preferences::AddUintVarCache(&sPreferredH264Gmp,
|
||||
@ -115,7 +191,8 @@ GMPDecoderModule::PreferredGMP(const nsACString& aMimeType)
|
||||
}
|
||||
}
|
||||
|
||||
if (aMimeType.EqualsLiteral("video/avc")) {
|
||||
if (aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/mp4")) {
|
||||
switch (sPreferredH264Gmp) {
|
||||
case 1: rv.emplace(NS_LITERAL_CSTRING("org.w3.clearkey")); break;
|
||||
case 2: rv.emplace(NS_LITERAL_CSTRING("com.adobe.primetime")); break;
|
||||
@ -126,35 +203,28 @@ GMPDecoderModule::PreferredGMP(const nsACString& aMimeType)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
GMPDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||
const Maybe<nsCString>& aGMP)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
nsCString api;
|
||||
if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("aac"));
|
||||
api = NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER);
|
||||
} else if (aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/mp4")) {
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
api = NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER);
|
||||
} else {
|
||||
return false;
|
||||
const bool isAAC = aMimeType.EqualsLiteral("audio/mp4a-latm");
|
||||
const bool isH264 = aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/mp4");
|
||||
|
||||
StaticMutexAutoLock lock(sGMPCodecsMutex);
|
||||
for (GMPCodecs& gmp : sGMPCodecs) {
|
||||
if (isAAC && gmp.mHasAAC &&
|
||||
(aGMP.isNothing() || aGMP.value().EqualsASCII(gmp.mKeySystem))) {
|
||||
return true;
|
||||
}
|
||||
if (isH264 && gmp.mHasH264 &&
|
||||
(aGMP.isNothing() || aGMP.value().EqualsASCII(gmp.mKeySystem))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (aGMP.isSome()) {
|
||||
tags.AppendElement(aGMP.value());
|
||||
}
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return false;
|
||||
}
|
||||
bool hasPlugin = false;
|
||||
if (NS_FAILED(mps->HasPluginForAPI(api, &tags, &hasPlugin))) {
|
||||
return false;
|
||||
}
|
||||
return hasPlugin;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
bool
|
||||
SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
// Main thread only.
|
||||
static void Init();
|
||||
|
||||
static const Maybe<nsCString> PreferredGMP(const nsACString& aMimeType);
|
||||
@ -45,6 +46,8 @@ public:
|
||||
static bool SupportsMimeType(const nsACString& aMimeType,
|
||||
const Maybe<nsCString>& aGMP);
|
||||
|
||||
// Main thread only.
|
||||
static void UpdateUsableCodecs();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -1406,6 +1406,11 @@ const DEBUG_TEST_LOOP_FOREVER = false;
|
||||
// or end the mochitest if all the tests are done.
|
||||
function MediaTestManager() {
|
||||
|
||||
// Return how many seconds elapsed since |begin|.
|
||||
function elapsedTime(begin) {
|
||||
var end = new Date();
|
||||
return (end.getTime() - begin.getTime()) / 1000;
|
||||
}
|
||||
// Sets up a MediaTestManager to runs through the 'tests' array, which needs
|
||||
// to be one of, or have the same fields as, the g*Test arrays of tests. Uses
|
||||
// the user supplied 'startTest' function to initialize the test. This
|
||||
@ -1450,7 +1455,8 @@ function MediaTestManager() {
|
||||
this.tokens.push(token);
|
||||
this.numTestsRunning++;
|
||||
this.handlers[token] = handler;
|
||||
is(this.numTestsRunning, this.tokens.length, "[started " + token + "] Length of array should match number of running tests");
|
||||
is(this.numTestsRunning, this.tokens.length,
|
||||
"[started " + token + " t=" + elapsedTime(this.startTime) + "] Length of array should match number of running tests");
|
||||
}
|
||||
|
||||
// Registers that the test corresponding to 'token' has finished. Call when
|
||||
@ -1466,7 +1472,8 @@ function MediaTestManager() {
|
||||
|
||||
info("[finished " + token + "] remaining= " + this.tokens);
|
||||
this.numTestsRunning--;
|
||||
is(this.numTestsRunning, this.tokens.length, "[finished " + token + "] Length of array should match number of running tests");
|
||||
is(this.numTestsRunning, this.tokens.length,
|
||||
"[finished " + token + " t=" + elapsedTime(this.startTime) + "] Length of array should match number of running tests");
|
||||
if (this.tokens.length < PARALLEL_TESTS) {
|
||||
this.nextTest();
|
||||
}
|
||||
@ -1504,7 +1511,7 @@ function MediaTestManager() {
|
||||
var onCleanup = function() {
|
||||
var end = new Date();
|
||||
SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
|
||||
SimpleTest.info("Running time: " + (end.getTime() - this.startTime.getTime())/1000 + "s");
|
||||
SimpleTest.info("Running time: " + elapsedTime(this.startTime) + "s");
|
||||
SimpleTest.finish();
|
||||
}.bind(this);
|
||||
mediaTestCleanup(onCleanup);
|
||||
|
@ -390,6 +390,18 @@ function waitUntil(func, time) {
|
||||
var timeout = (promise, time, msg) =>
|
||||
Promise.race([promise, wait(time).then(() => Promise.reject(new Error(msg)))]);
|
||||
|
||||
/** Use event listener to call passed-in function on fire until it returns true */
|
||||
var listenUntil = (target, eventName, onFire) => {
|
||||
return new Promise(resolve => target.addEventListener(eventName,
|
||||
function callback() {
|
||||
var result = onFire();
|
||||
if (result) {
|
||||
target.removeEventListener(eventName, callback, false);
|
||||
resolve(result);
|
||||
}
|
||||
}, false));
|
||||
};
|
||||
|
||||
/*** Test control flow methods */
|
||||
|
||||
/**
|
||||
|
@ -2,13 +2,12 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const TIMEUPDATE_TIMEOUT_LENGTH = 10000;
|
||||
const ENDED_TIMEOUT_LENGTH = 30000;
|
||||
|
||||
/* Time we wait for the canplaythrough event to fire
|
||||
/* The time we wait depends primarily on the canplaythrough event firing
|
||||
* Note: this needs to be at least 30s because the
|
||||
* B2G emulator in VMs is really slow. */
|
||||
const CANPLAYTHROUGH_TIMEOUT_LENGTH = 60000;
|
||||
const VERIFYPLAYING_TIMEOUT_LENGTH = 60000;
|
||||
|
||||
/**
|
||||
* This class manages playback of a HTMLMediaElement with a MediaStream.
|
||||
@ -34,7 +33,8 @@ MediaStreamPlayback.prototype = {
|
||||
* from a previous run
|
||||
*/
|
||||
playMedia : function(isResume) {
|
||||
return this.startMedia(isResume)
|
||||
this.startMedia(isResume);
|
||||
return this.verifyPlaying()
|
||||
.then(() => this.stopMediaElement());
|
||||
},
|
||||
|
||||
@ -45,28 +45,34 @@ MediaStreamPlayback.prototype = {
|
||||
* is being resumed from a previous run
|
||||
*/
|
||||
startMedia : function(isResume) {
|
||||
var canPlayThroughFired = false;
|
||||
|
||||
// If we're playing this media element for the first time,
|
||||
// check that the time is zero.
|
||||
// If we're playing media element for the first time, check that time is zero.
|
||||
if (!isResume) {
|
||||
is(this.mediaElement.currentTime, 0,
|
||||
"Before starting the media element, currentTime = 0");
|
||||
}
|
||||
this.canPlayThroughFired = listenUntil(this.mediaElement, 'canplaythrough',
|
||||
() => true);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
/**
|
||||
* Callback fired when the canplaythrough event is fired. We only
|
||||
* run the logic of this function once, as this event can fire
|
||||
* multiple times while a HTMLMediaStream is playing content from
|
||||
* a real-time MediaStream.
|
||||
*/
|
||||
var canPlayThroughCallback = () => {
|
||||
// Disable the canplaythrough event listener to prevent multiple calls
|
||||
canPlayThroughFired = true;
|
||||
this.mediaElement.removeEventListener('canplaythrough',
|
||||
canPlayThroughCallback, false);
|
||||
// Hooks up the media stream to the media element and starts playing it
|
||||
this.mediaElement.srcObject = this.mediaStream;
|
||||
this.mediaElement.play();
|
||||
},
|
||||
|
||||
/**
|
||||
* Verifies that media is playing.
|
||||
*/
|
||||
verifyPlaying : function() {
|
||||
var lastStreamTime = this.mediaStream.currentTime;
|
||||
var lastElementTime = this.mediaElement.currentTime;
|
||||
|
||||
var mediaTimeProgressed = listenUntil(this.mediaElement, 'timeupdate',
|
||||
() => this.mediaStream.currentTime > lastStreamTime &&
|
||||
this.mediaElement.currentTime > lastElementTime);
|
||||
|
||||
return timeout(Promise.all([this.canPlayThroughFired, mediaTimeProgressed]),
|
||||
VERIFYPLAYING_TIMEOUT_LENGTH, "verifyPlaying timed out")
|
||||
.then(() => {
|
||||
is(this.mediaElement.paused, false,
|
||||
"Media element should be playing");
|
||||
is(this.mediaElement.duration, Number.POSITIVE_INFINITY,
|
||||
@ -93,45 +99,7 @@ MediaStreamPlayback.prototype = {
|
||||
is(this.mediaElement.src, "", "No src should be defined");
|
||||
is(this.mediaElement.currentSrc, "",
|
||||
"Current src should still be an empty string");
|
||||
|
||||
var timeUpdateCallback = () => {
|
||||
if (this.mediaStream.currentTime > 0 &&
|
||||
this.mediaElement.currentTime > 0) {
|
||||
this.mediaElement.removeEventListener('timeupdate',
|
||||
timeUpdateCallback, false);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// When timeupdate fires, we validate time has passed and move
|
||||
// onto the success condition
|
||||
this.mediaElement.addEventListener('timeupdate', timeUpdateCallback,
|
||||
false);
|
||||
|
||||
// If timeupdate doesn't fire in enough time, we fail the test
|
||||
setTimeout(() => {
|
||||
this.mediaElement.removeEventListener('timeupdate',
|
||||
timeUpdateCallback, false);
|
||||
reject(new Error("timeUpdate event never fired"));
|
||||
}, TIMEUPDATE_TIMEOUT_LENGTH);
|
||||
};
|
||||
|
||||
// Adds a listener intended to be fired when playback is available
|
||||
// without further buffering.
|
||||
this.mediaElement.addEventListener('canplaythrough', canPlayThroughCallback,
|
||||
false);
|
||||
|
||||
// Hooks up the media stream to the media element and starts playing it
|
||||
this.mediaElement.srcObject = this.mediaStream;
|
||||
this.mediaElement.play();
|
||||
|
||||
// If canplaythrough doesn't fire in enough time, we fail the test
|
||||
setTimeout(() => {
|
||||
this.mediaElement.removeEventListener('canplaythrough',
|
||||
canPlayThroughCallback, false);
|
||||
reject(new Error("canplaythrough event never fired"));
|
||||
}, CANPLAYTHROUGH_TIMEOUT_LENGTH);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -172,7 +140,8 @@ LocalMediaStreamPlayback.prototype = Object.create(MediaStreamPlayback.prototype
|
||||
*/
|
||||
playMediaWithMediaStreamTracksStop: {
|
||||
value: function(isResume) {
|
||||
return this.startMedia(isResume)
|
||||
this.startMedia(isResume);
|
||||
return this.verifyPlaying()
|
||||
.then(() => this.stopTracksForStreamInMediaPlayback())
|
||||
.then(() => this.stopMediaElement());
|
||||
}
|
||||
@ -217,7 +186,8 @@ LocalMediaStreamPlayback.prototype = Object.create(MediaStreamPlayback.prototype
|
||||
*/
|
||||
playMediaWithDeprecatedStreamStop : {
|
||||
value: function(isResume) {
|
||||
return this.startMedia(isResume)
|
||||
this.startMedia(isResume);
|
||||
return this.verifyPlaying()
|
||||
.then(() => this.deprecatedStopStreamInMediaPlayback())
|
||||
.then(() => this.stopMediaElement());
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failu
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
|
||||
[test_getUserMedia_basicScreenshare.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no screenshare on b2g/android # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_getUserMedia_basicTabshare.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no windowshare on b2g/android # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_getUserMedia_basicWindowshare.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no windowshare on b2g/android # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_getUserMedia_basicVideoAudio.html]
|
||||
|
@ -0,0 +1,66 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
title: "getUserMedia Basic Tabshare Test",
|
||||
bug: "1193075"
|
||||
});
|
||||
/**
|
||||
* Run a test to verify that we can complete a start and stop media playback
|
||||
* cycle for a tabshare LocalMediaStream on a video HTMLMediaElement.
|
||||
*
|
||||
* Additionally, exercise applyConstraints code for tabshare viewport offset.
|
||||
*/
|
||||
runTest(function () {
|
||||
const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
|
||||
if (IsMacOSX10_6orOlder() || isWinXP) {
|
||||
ok(true, "Screensharing disabled for OSX10.6 and WinXP");
|
||||
return;
|
||||
}
|
||||
var testVideo = createMediaElement('video', 'testVideo');
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => getUserMedia({ video: { mediaSource: "browser",
|
||||
scrollWithPage: true } }))
|
||||
.then(stream => {
|
||||
var playback = new LocalMediaStreamPlayback(testVideo, stream);
|
||||
return playback.playMediaWithDeprecatedStreamStop(false);
|
||||
})
|
||||
.then(() => getUserMedia({
|
||||
video: {
|
||||
mediaSource: "browser",
|
||||
viewportOffsetX: 0,
|
||||
viewportOffsetY: 0,
|
||||
viewportWidth: 100,
|
||||
viewportHeight: 100
|
||||
}
|
||||
}))
|
||||
.then(stream => {
|
||||
var playback = new LocalMediaStreamPlayback(testVideo, stream);
|
||||
playback.startMedia(false);
|
||||
return playback.verifyPlaying()
|
||||
.then(() => Promise.all([
|
||||
() => testVideo.srcObject.getVideoTracks()[0].applyConstraints({
|
||||
mediaSource: "browser",
|
||||
viewportOffsetX: 10,
|
||||
viewportOffsetY: 50,
|
||||
viewportWidth: 90,
|
||||
viewportHeight: 50
|
||||
}),
|
||||
() => listenUntil(testVideo, "resize", () => true)
|
||||
]))
|
||||
.then(() => playback.verifyPlaying()) // still playing
|
||||
.then(() => playback.deprecatedStopStreamInMediaPlayback())
|
||||
.then(() => playback.stopMediaElement());
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -72,9 +72,9 @@ var tests = [
|
||||
|
||||
var mustSupport = [
|
||||
'width', 'height', 'frameRate', 'facingMode', 'deviceId',
|
||||
// Yet to add:
|
||||
// 'aspectRatio', 'frameRate', 'volume', 'sampleRate', 'sampleSize',
|
||||
// 'echoCancellation', 'latency', 'groupId'
|
||||
// Yet to add:
|
||||
// 'aspectRatio', 'frameRate', 'volume', 'sampleRate', 'sampleSize',
|
||||
// 'echoCancellation', 'latency', 'groupId'
|
||||
|
||||
// http://fluffy.github.io/w3c-screen-share/#screen-based-video-constraints
|
||||
// OBE by http://w3c.github.io/mediacapture-screen-share
|
||||
@ -82,6 +82,7 @@ var mustSupport = [
|
||||
|
||||
// Experimental https://bugzilla.mozilla.org/show_bug.cgi?id=1131568#c3
|
||||
'browserWindow', 'scrollWithPage',
|
||||
'viewportOffsetX', 'viewportOffsetY', 'viewportWidth', 'viewportHeight'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -31,9 +31,17 @@ using namespace mozilla::gfx;
|
||||
NS_IMPL_ISUPPORTS(MediaEngineTabVideoSource, nsIDOMEventListener, nsITimerCallback)
|
||||
|
||||
MediaEngineTabVideoSource::MediaEngineTabVideoSource()
|
||||
: mData(NULL), mDataSize(0), mMonitor("MediaEngineTabVideoSource"), mTabSource(nullptr)
|
||||
{
|
||||
}
|
||||
: mBufWidthMax(0)
|
||||
, mBufHeightMax(0)
|
||||
, mWindowId(0)
|
||||
, mScrollWithPage(false)
|
||||
, mViewportOffsetX(0)
|
||||
, mViewportOffsetY(0)
|
||||
, mViewportWidth(0)
|
||||
, mViewportHeight(0)
|
||||
, mTimePerFrame(0)
|
||||
, mDataSize(0)
|
||||
, mMonitor("MediaEngineTabVideoSource") {}
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::StartRunnable::Run()
|
||||
@ -123,23 +131,39 @@ MediaEngineTabVideoSource::Allocate(const dom::MediaTrackConstraints& aConstrain
|
||||
const MediaEnginePrefs& aPrefs,
|
||||
const nsString& aDeviceId)
|
||||
{
|
||||
// windowId and scrollWithPage are not proper constraints, so just read them.
|
||||
// They have no well-defined behavior in advanced, so ignore them there.
|
||||
// windowId is not a proper constraint, so just read it.
|
||||
// It has no well-defined behavior in advanced, so ignore it there.
|
||||
|
||||
mWindowId = aConstraints.mBrowserWindow.WasPassed() ?
|
||||
aConstraints.mBrowserWindow.Value() : -1;
|
||||
|
||||
return Restart(aConstraints, aPrefs, aDeviceId);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints,
|
||||
const mozilla::MediaEnginePrefs& aPrefs,
|
||||
const nsString& aDeviceId)
|
||||
{
|
||||
// scrollWithPage is not proper a constraint, so just read it.
|
||||
// It has no well-defined behavior in advanced, so ignore it there.
|
||||
|
||||
mScrollWithPage = aConstraints.mScrollWithPage.WasPassed() ?
|
||||
aConstraints.mScrollWithPage.Value() : true;
|
||||
aConstraints.mScrollWithPage.Value() : false;
|
||||
|
||||
FlattenedConstraints c(aConstraints);
|
||||
|
||||
mBufWidthMax = c.mWidth.Clamp(c.mWidth.mIdeal.WasPassed() ?
|
||||
c.mWidth.mIdeal.Value() : DEFAULT_TABSHARE_VIDEO_MAX_WIDTH);
|
||||
mBufHeightMax = c.mHeight.Clamp(c.mHeight.mIdeal.WasPassed() ?
|
||||
c.mHeight.mIdeal.Value() : DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT);
|
||||
double frameRate = c.mFrameRate.Clamp(c.mFrameRate.mIdeal.WasPassed() ?
|
||||
c.mFrameRate.mIdeal.Value() : DEFAULT_TABSHARE_VIDEO_FRAMERATE);
|
||||
mBufWidthMax = c.mWidth.Get(DEFAULT_TABSHARE_VIDEO_MAX_WIDTH);
|
||||
mBufHeightMax = c.mHeight.Get(DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT);
|
||||
double frameRate = c.mFrameRate.Get(DEFAULT_TABSHARE_VIDEO_FRAMERATE);
|
||||
mTimePerFrame = std::max(10, int(1000.0 / (frameRate > 0? frameRate : 1)));
|
||||
|
||||
if (!mScrollWithPage) {
|
||||
mViewportOffsetX = c.mViewportOffsetX.Get(0);
|
||||
mViewportOffsetY = c.mViewportOffsetY.Get(0);
|
||||
mViewportWidth = c.mViewportWidth.Get(INT32_MAX);
|
||||
mViewportHeight = c.mViewportHeight.Get(INT32_MAX);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -192,30 +216,32 @@ MediaEngineTabVideoSource::Draw() {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t innerWidth, innerHeight;
|
||||
win->GetInnerWidth(&innerWidth);
|
||||
win->GetInnerHeight(&innerHeight);
|
||||
|
||||
if (innerWidth == 0 || innerHeight == 0) {
|
||||
if (mScrollWithPage || mViewportWidth == INT32_MAX) {
|
||||
win->GetInnerWidth(&mViewportWidth);
|
||||
}
|
||||
if (mScrollWithPage || mViewportHeight == INT32_MAX) {
|
||||
win->GetInnerHeight(&mViewportHeight);
|
||||
}
|
||||
if (!mViewportWidth || !mViewportHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
float pixelRatio;
|
||||
win->GetDevicePixelRatio(&pixelRatio);
|
||||
const int deviceInnerWidth = (int)(pixelRatio * innerWidth);
|
||||
const int deviceInnerHeight = (int)(pixelRatio * innerHeight);
|
||||
|
||||
IntSize size;
|
||||
{
|
||||
float pixelRatio;
|
||||
win->GetDevicePixelRatio(&pixelRatio);
|
||||
const int32_t deviceWidth = (int32_t)(pixelRatio * mViewportWidth);
|
||||
const int32_t deviceHeight = (int32_t)(pixelRatio * mViewportHeight);
|
||||
|
||||
if ((deviceInnerWidth <= mBufWidthMax) && (deviceInnerHeight <= mBufHeightMax)) {
|
||||
size = IntSize(deviceInnerWidth, deviceInnerHeight);
|
||||
} else {
|
||||
if ((deviceWidth <= mBufWidthMax) && (deviceHeight <= mBufHeightMax)) {
|
||||
size = IntSize(deviceWidth, deviceHeight);
|
||||
} else {
|
||||
const float scaleWidth = (float)mBufWidthMax / (float)deviceWidth;
|
||||
const float scaleHeight = (float)mBufHeightMax / (float)deviceHeight;
|
||||
const float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
|
||||
|
||||
const float scaleWidth = (float)mBufWidthMax / (float)deviceInnerWidth;
|
||||
const float scaleHeight = (float)mBufHeightMax / (float)deviceInnerHeight;
|
||||
const float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
|
||||
|
||||
size = IntSize((int)(scale * deviceInnerWidth), (int)(scale * deviceInnerHeight));
|
||||
size = IntSize((int)(scale * deviceWidth), (int)(scale * deviceHeight));
|
||||
}
|
||||
}
|
||||
|
||||
gfxImageFormat format = gfxImageFormat::RGB24;
|
||||
@ -225,28 +251,31 @@ MediaEngineTabVideoSource::Draw() {
|
||||
mDataSize = stride * size.height;
|
||||
mData = static_cast<unsigned char*>(malloc(mDataSize));
|
||||
}
|
||||
|
||||
if (!mData) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsPresContext> presContext;
|
||||
nsIDocShell* docshell = win->GetDocShell();
|
||||
if (docshell) {
|
||||
docshell->GetPresContext(getter_AddRefs(presContext));
|
||||
}
|
||||
if (!presContext) {
|
||||
return;
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
{
|
||||
RefPtr<nsPresContext> presContext;
|
||||
nsIDocShell* docshell = win->GetDocShell();
|
||||
if (docshell) {
|
||||
docshell->GetPresContext(getter_AddRefs(presContext));
|
||||
}
|
||||
if (!presContext) {
|
||||
return;
|
||||
}
|
||||
presShell = presContext->PresShell();
|
||||
}
|
||||
|
||||
nscolor bgColor = NS_RGB(255, 255, 255);
|
||||
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||
uint32_t renderDocFlags = 0;
|
||||
if (!mScrollWithPage) {
|
||||
renderDocFlags |= nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
|
||||
}
|
||||
nsRect r(0, 0, nsPresContext::CSSPixelsToAppUnits((float)innerWidth),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)innerHeight));
|
||||
uint32_t renderDocFlags = mScrollWithPage? 0 :
|
||||
(nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
|
||||
nsIPresShell::RENDER_DOCUMENT_RELATIVE);
|
||||
nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight));
|
||||
|
||||
RefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer();
|
||||
RefPtr<DrawTarget> dt =
|
||||
@ -259,8 +288,8 @@ MediaEngineTabVideoSource::Draw() {
|
||||
return;
|
||||
}
|
||||
RefPtr<gfxContext> context = new gfxContext(dt);
|
||||
context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/innerWidth),
|
||||
(((float) size.height)/innerHeight)));
|
||||
context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/mViewportWidth),
|
||||
(((float) size.height)/mViewportHeight)));
|
||||
|
||||
NS_ENSURE_SUCCESS_VOID(presShell->RenderDocument(r, renderDocFlags, bgColor, context));
|
||||
|
||||
@ -291,15 +320,6 @@ MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints,
|
||||
const mozilla::MediaEnginePrefs& aPrefs,
|
||||
const nsString& aDeviceId)
|
||||
{
|
||||
// TODO
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t)
|
||||
{
|
||||
|
@ -76,11 +76,15 @@ protected:
|
||||
~MediaEngineTabVideoSource() {}
|
||||
|
||||
private:
|
||||
int mBufWidthMax;
|
||||
int mBufHeightMax;
|
||||
int32_t mBufWidthMax;
|
||||
int32_t mBufHeightMax;
|
||||
int64_t mWindowId;
|
||||
bool mScrollWithPage;
|
||||
int mTimePerFrame;
|
||||
int32_t mViewportOffsetX;
|
||||
int32_t mViewportOffsetY;
|
||||
int32_t mViewportWidth;
|
||||
int32_t mViewportHeight;
|
||||
int32_t mTimePerFrame;
|
||||
ScopedFreePtr<unsigned char> mData;
|
||||
size_t mDataSize;
|
||||
nsCOMPtr<nsIDOMWindow> mWindow;
|
||||
|
@ -48,6 +48,9 @@ struct NormalizedConstraintSet
|
||||
template<class ConstrainRange>
|
||||
void SetFrom(const ConstrainRange& aOther);
|
||||
ValueType Clamp(ValueType n) const { return std::max(mMin, std::min(n, mMax)); }
|
||||
ValueType Get(ValueType defaultValue) const {
|
||||
return Clamp(mIdeal.WasPassed() ? mIdeal.Value() : defaultValue);
|
||||
}
|
||||
bool Intersects(const Range& aOther) const {
|
||||
return mMax >= aOther.mMin && mMin <= aOther.mMax;
|
||||
}
|
||||
@ -72,12 +75,17 @@ struct NormalizedConstraintSet
|
||||
// Do you need to add your constraint here? Only if your code uses flattening
|
||||
LongRange mWidth, mHeight;
|
||||
DoubleRange mFrameRate;
|
||||
LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
|
||||
|
||||
NormalizedConstraintSet(const dom::MediaTrackConstraintSet& aOther,
|
||||
bool advanced)
|
||||
: mWidth(aOther.mWidth, advanced)
|
||||
, mHeight(aOther.mHeight, advanced)
|
||||
, mFrameRate(aOther.mFrameRate, advanced) {}
|
||||
, mFrameRate(aOther.mFrameRate, advanced)
|
||||
, mViewportOffsetX(aOther.mViewportOffsetX, advanced)
|
||||
, mViewportOffsetY(aOther.mViewportOffsetY, advanced)
|
||||
, mViewportWidth(aOther.mViewportWidth, advanced)
|
||||
, mViewportHeight(aOther.mViewportHeight, advanced) {}
|
||||
};
|
||||
|
||||
struct FlattenedConstraints : public NormalizedConstraintSet
|
||||
|
@ -153,6 +153,9 @@ PluginProcessParent::Launch(mozilla::UniquePtr<LaunchCompleteTask> aLaunchComple
|
||||
else if (base::PROCESS_ARCH_ARM & pluginLibArchitectures & containerArchitectures) {
|
||||
selectedArchitecture = base::PROCESS_ARCH_ARM;
|
||||
}
|
||||
else if (base::PROCESS_ARCH_MIPS & pluginLibArchitectures & containerArchitectures) {
|
||||
selectedArchitecture = base::PROCESS_ARCH_MIPS;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ dictionary MediaTrackConstraintSet {
|
||||
long long browserWindow;
|
||||
boolean scrollWithPage;
|
||||
ConstrainDOMString deviceId;
|
||||
ConstrainLong viewportOffsetX;
|
||||
ConstrainLong viewportOffsetY;
|
||||
ConstrainLong viewportWidth;
|
||||
ConstrainLong viewportHeight;
|
||||
};
|
||||
|
||||
dictionary MediaTrackConstraints : MediaTrackConstraintSet {
|
||||
|
@ -29,7 +29,12 @@ dictionary MediaTrackSupportedConstraints {
|
||||
boolean mediaSource = true;
|
||||
|
||||
// Experimental https://bugzilla.mozilla.org/show_bug.cgi?id=1131568#c3
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1193075
|
||||
|
||||
boolean browserWindow = true;
|
||||
boolean scrollWithPage = true;
|
||||
boolean viewportOffsetX = true;
|
||||
boolean viewportOffsetY = true;
|
||||
boolean viewportWidth = true;
|
||||
boolean viewportHeight = true;
|
||||
};
|
||||
|
@ -133,7 +133,8 @@ enum class LogReason : int {
|
||||
MustBeMoreThanThis = -1,
|
||||
// Start. Do not insert, always add at end. If you remove items,
|
||||
// make sure the other items retain their values.
|
||||
|
||||
D3D11InvalidCallDeviceRemoved = 0,
|
||||
D3D11InvalidCall = 1,
|
||||
// End
|
||||
MustBeLessThanThis = 101,
|
||||
};
|
||||
|
@ -27,10 +27,10 @@ SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAlloc
|
||||
TextureFlags aFlags,
|
||||
UniquePtr<gl::SharedSurface> surf,
|
||||
gl::SurfaceFactory* factory)
|
||||
: TextureClient(aAllocator, aFlags | TextureFlags::RECYCLE)
|
||||
: TextureClient(aAllocator,
|
||||
aFlags | TextureFlags::RECYCLE | surf->GetTextureFlags())
|
||||
, mSurf(Move(surf))
|
||||
{
|
||||
AddFlags(mSurf->GetTextureFlags());
|
||||
}
|
||||
|
||||
SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
|
||||
|
@ -480,6 +480,10 @@ CompositorD3D11::CreateRenderTarget(const gfx::IntRect& aRect,
|
||||
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aRect.width, aRect.height, 1, 1,
|
||||
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
|
||||
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in CreateRenderTarget";
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> texture;
|
||||
HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
|
||||
if (Failed(hr) || !texture) {
|
||||
@ -513,6 +517,10 @@ CompositorD3D11::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
|
||||
aRect.width, aRect.height, 1, 1,
|
||||
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
|
||||
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in CreateRenderTargetFromSource";
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> texture;
|
||||
HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
|
||||
NS_ASSERTION(texture, "Could not create texture");
|
||||
@ -1015,6 +1023,10 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
Rect* aClipRectOut,
|
||||
Rect* aRenderBoundsOut)
|
||||
{
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in BeginFrame";
|
||||
}
|
||||
|
||||
// Don't composite if we are minimised. Other than for the sake of efficency,
|
||||
// this is important because resizing our buffers when mimised will fail and
|
||||
// cause a crash when we're restored.
|
||||
@ -1025,10 +1037,9 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
}
|
||||
|
||||
IntSize oldSize = mSize;
|
||||
UpdateRenderTarget();
|
||||
|
||||
// Failed to create a render target or the view.
|
||||
if (!mDefaultRT || !mDefaultRT->mRTView ||
|
||||
if (!UpdateRenderTarget() || !mDefaultRT || !mDefaultRT->mRTView ||
|
||||
mSize.width <= 0 || mSize.height <= 0) {
|
||||
*aRenderBoundsOut = Rect();
|
||||
return;
|
||||
@ -1140,7 +1151,10 @@ CompositorD3D11::EndFrame()
|
||||
params.pDirtyRects = params.DirtyRectsCount ? rects.data() : nullptr;
|
||||
chain->Present1(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0, ¶ms);
|
||||
} else {
|
||||
mSwapChain->Present(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
|
||||
hr = mSwapChain->Present(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
|
||||
if (Failed(hr)) {
|
||||
gfxCriticalNote << "D3D11 swap chain preset failed " << hexa(hr);
|
||||
}
|
||||
}
|
||||
mDisableSequenceForNextFrame = false;
|
||||
if (mTarget) {
|
||||
@ -1224,26 +1238,33 @@ CompositorD3D11::VerifyBufferSize()
|
||||
hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
0);
|
||||
if (Failed(hr)) {
|
||||
gfxCriticalNote << "D3D11 swap resize buffers failed " << hexa(hr) << " on " << mSize;
|
||||
}
|
||||
|
||||
return Succeeded(hr);
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
CompositorD3D11::UpdateRenderTarget()
|
||||
{
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in UpdateRenderTarget";
|
||||
}
|
||||
|
||||
EnsureSize();
|
||||
if (!VerifyBufferSize()) {
|
||||
gfxCriticalNote << "Failed VerifyBufferSize in UpdateRenderTarget " << mSize;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDefaultRT) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mSize.width <= 0 || mSize.height <= 0) {
|
||||
gfxCriticalNote << "Invalid size in UpdateRenderTarget " << mSize;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
@ -1255,16 +1276,18 @@ CompositorD3D11::UpdateRenderTarget()
|
||||
// This happens on some GPUs/drivers when there's a TDR.
|
||||
if (mDevice->GetDeviceRemovedReason() != S_OK) {
|
||||
gfxCriticalError() << "GetBuffer returned invalid call!";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Failed(hr)) {
|
||||
gfxCriticalNote << "Failed in UpdateRenderTarget " << hexa(hr);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
mDefaultRT = new CompositingRenderTargetD3D11(backBuf, IntPoint(0, 0));
|
||||
mDefaultRT->SetSize(mSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1282,6 +1305,10 @@ DeviceAttachmentsD3D11::InitSyncObject()
|
||||
D3D11_BIND_RENDER_TARGET);
|
||||
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in InitSyncObject";
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> texture;
|
||||
HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
|
||||
if (Failed(hr, "create sync texture")) {
|
||||
@ -1410,6 +1437,10 @@ CompositorD3D11::PaintToTarget()
|
||||
|
||||
RefPtr<ID3D11Texture2D> readTexture;
|
||||
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in PaintToTarget";
|
||||
}
|
||||
|
||||
hr = mDevice->CreateTexture2D(&softDesc, nullptr, getter_AddRefs(readTexture));
|
||||
if (Failed(hr)) {
|
||||
gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Failed in PaintToTarget 2";
|
||||
@ -1457,10 +1488,20 @@ CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity)
|
||||
MOZ_CRASH("Unrecoverable D3D11 error");
|
||||
}
|
||||
|
||||
if (mDevice != gfxWindowsPlatform::GetPlatform()->GetD3D11Device()) {
|
||||
gfxCriticalError() << "Out of sync D3D11 devices in HandleError";
|
||||
}
|
||||
|
||||
HRESULT hrOnReset = S_OK;
|
||||
bool deviceRemoved = hr == DXGI_ERROR_DEVICE_REMOVED;
|
||||
|
||||
if (deviceRemoved && mDevice) {
|
||||
hr = mDevice->GetDeviceRemovedReason();
|
||||
hrOnReset = mDevice->GetDeviceRemovedReason();
|
||||
} else if (hr == DXGI_ERROR_INVALID_CALL && mDevice) {
|
||||
hrOnReset = mDevice->GetDeviceRemovedReason();
|
||||
if (hrOnReset != S_OK) {
|
||||
deviceRemoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Device reset may not be an error on our side, but can mess things up so
|
||||
@ -1468,11 +1509,11 @@ CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity)
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(!deviceRemoved))
|
||||
<< (deviceRemoved ? "[CompositorD3D11] device removed with error code: "
|
||||
: "[CompositorD3D11] error code: ")
|
||||
<< hexa(hr);
|
||||
<< hexa(hr) << ", " << hexa(hrOnReset);
|
||||
|
||||
// Always crash if we are making invalid calls
|
||||
// Crash if we are making invalid calls outside of device removal
|
||||
if (hr == DXGI_ERROR_INVALID_CALL) {
|
||||
MOZ_CRASH("Invalid D3D11 api call");
|
||||
gfxCrash(deviceRemoved ? LogReason::D3D11InvalidCallDeviceRemoved : LogReason::D3D11InvalidCall) << "Invalid D3D11 api call";
|
||||
}
|
||||
|
||||
if (aSeverity == Recoverable) {
|
||||
|
@ -167,7 +167,7 @@ private:
|
||||
// ensure mSize is up to date with respect to mWidget
|
||||
void EnsureSize();
|
||||
bool VerifyBufferSize();
|
||||
void UpdateRenderTarget();
|
||||
bool UpdateRenderTarget();
|
||||
bool UpdateConstantBuffers();
|
||||
void SetSamplerForFilter(gfx::Filter aFilter);
|
||||
void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
|
||||
|
@ -71,7 +71,8 @@ enum ProcessArchitecture {
|
||||
PROCESS_ARCH_I386 = 0x1,
|
||||
PROCESS_ARCH_X86_64 = 0x2,
|
||||
PROCESS_ARCH_PPC = 0x4,
|
||||
PROCESS_ARCH_ARM = 0x8
|
||||
PROCESS_ARCH_ARM = 0x8,
|
||||
PROCESS_ARCH_MIPS = 0x10
|
||||
};
|
||||
|
||||
inline ProcessArchitecture GetCurrentProcessArchitecture()
|
||||
@ -85,6 +86,8 @@ inline ProcessArchitecture GetCurrentProcessArchitecture()
|
||||
currentArchitecture = base::PROCESS_ARCH_PPC;
|
||||
#elif defined(ARCH_CPU_ARMEL)
|
||||
currentArchitecture = base::PROCESS_ARCH_ARM;
|
||||
#elif defined(ARCH_CPU_MIPS)
|
||||
currentArchitecture = base::PROCESS_ARCH_MIPS;
|
||||
#endif
|
||||
return currentArchitecture;
|
||||
}
|
||||
|
@ -42,12 +42,11 @@ using mozilla::UniquePtr;
|
||||
struct KeywordInfo {
|
||||
const char* chars; // C string with keyword text
|
||||
TokenKind tokentype;
|
||||
JSVersion version;
|
||||
};
|
||||
|
||||
static const KeywordInfo keywords[] = {
|
||||
#define KEYWORD_INFO(keyword, name, type, version) \
|
||||
{js_##keyword##_str, type, version},
|
||||
#define KEYWORD_INFO(keyword, name, type) \
|
||||
{js_##keyword##_str, type},
|
||||
FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_INFO)
|
||||
#undef KEYWORD_INFO
|
||||
};
|
||||
@ -997,24 +996,21 @@ TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp)
|
||||
return reportError(JSMSG_RESERVED_ID, kw->chars);
|
||||
}
|
||||
|
||||
if (kw->tokentype != TOK_STRICT_RESERVED) {
|
||||
if (kw->version <= versionNumber()) {
|
||||
// Treat 'let' as an identifier and contextually a keyword in
|
||||
// sloppy mode. It is always a keyword in strict mode.
|
||||
if (kw->tokentype == TOK_LET && !strictMode())
|
||||
return true;
|
||||
if (kw->tokentype == TOK_STRICT_RESERVED)
|
||||
return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
|
||||
|
||||
// Working keyword.
|
||||
if (ttp) {
|
||||
*ttp = kw->tokentype;
|
||||
return true;
|
||||
}
|
||||
return reportError(JSMSG_RESERVED_ID, kw->chars);
|
||||
}
|
||||
// Treat 'let' as an identifier and contextually a keyword in sloppy mode.
|
||||
// It is always a keyword in strict mode.
|
||||
if (kw->tokentype == TOK_LET && !strictMode())
|
||||
return true;
|
||||
|
||||
// Working keyword.
|
||||
if (ttp) {
|
||||
*ttp = kw->tokentype;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Strict reserved word.
|
||||
return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
|
||||
return reportError(JSMSG_RESERVED_ID, kw->chars);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -6,7 +6,7 @@
|
||||
//
|
||||
// These should not run with --no-asmjs.
|
||||
|
||||
if (!isAsmJSCompilationAvailable())
|
||||
if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
|
||||
quit(0);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -492,8 +492,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
// Push the return address and make a call. On platforms where this function
|
||||
// is not defined, push the link register (pushReturnAddress) at the entry
|
||||
// point of the callee.
|
||||
void callAndPushReturnAddress(Register reg) DEFINED_ON(mips32, x86_shared);
|
||||
void callAndPushReturnAddress(Label* label) DEFINED_ON(mips32, x86_shared);
|
||||
void callAndPushReturnAddress(Register reg) DEFINED_ON(mips_shared, x86_shared);
|
||||
void callAndPushReturnAddress(Label* label) DEFINED_ON(mips_shared, x86_shared);
|
||||
|
||||
void pushReturnAddress() DEFINED_ON(arm, arm64);
|
||||
|
||||
|
@ -111,11 +111,22 @@ CodeGeneratorMIPSShared::visitTestIAndBranch(LTestIAndBranch* test)
|
||||
void
|
||||
CodeGeneratorMIPSShared::visitCompare(LCompare* comp)
|
||||
{
|
||||
Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop());
|
||||
MCompare* mir = comp->mir();
|
||||
Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop());
|
||||
const LAllocation* left = comp->getOperand(0);
|
||||
const LAllocation* right = comp->getOperand(1);
|
||||
const LDefinition* def = comp->getDef(0);
|
||||
|
||||
#ifdef JS_CODEGEN_MIPS64
|
||||
if (mir->compareType() == MCompare::Compare_Object) {
|
||||
if (right->isGeneralReg())
|
||||
masm.cmpPtrSet(cond, ToRegister(left), ToRegister(right), ToRegister(def));
|
||||
else
|
||||
masm.cmpPtrSet(cond, ToRegister(left), ToAddress(right), ToRegister(def));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (right->isConstant())
|
||||
masm.cmp32Set(cond, ToRegister(left), Imm32(ToInt32(right)), ToRegister(def));
|
||||
else if (right->isGeneralReg())
|
||||
@ -127,7 +138,23 @@ CodeGeneratorMIPSShared::visitCompare(LCompare* comp)
|
||||
void
|
||||
CodeGeneratorMIPSShared::visitCompareAndBranch(LCompareAndBranch* comp)
|
||||
{
|
||||
Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop());
|
||||
MCompare* mir = comp->cmpMir();
|
||||
Assembler::Condition cond = JSOpToCondition(mir->compareType(), comp->jsop());
|
||||
|
||||
#ifdef JS_CODEGEN_MIPS64
|
||||
if (mir->compareType() == MCompare::Compare_Object) {
|
||||
if (comp->right()->isGeneralReg()) {
|
||||
emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond,
|
||||
comp->ifTrue(), comp->ifFalse());
|
||||
} else {
|
||||
masm.loadPtr(ToAddress(comp->right()), ScratchRegister);
|
||||
emitBranch(ToRegister(comp->left()), ScratchRegister, cond,
|
||||
comp->ifTrue(), comp->ifFalse());
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (comp->right()->isConstant()) {
|
||||
emitBranch(ToRegister(comp->left()), Imm32(ToInt32(comp->right())), cond,
|
||||
comp->ifTrue(), comp->ifFalse());
|
||||
@ -198,16 +225,6 @@ CodeGeneratorMIPSShared::bailout(LSnapshot* snapshot)
|
||||
bailoutFrom(&label, snapshot);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPSShared::visitOutOfLineBailout(OutOfLineBailout* ool)
|
||||
{
|
||||
// Push snapshotOffset and make sure stack is aligned.
|
||||
masm.subPtr(Imm32(2 * sizeof(void*)), StackPointer);
|
||||
masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0));
|
||||
|
||||
masm.jump(&deoptLabel_);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPSShared::visitMinMaxD(LMinMaxD* ins)
|
||||
{
|
||||
|
@ -175,7 +175,7 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared
|
||||
virtual void visitTruncateFToInt32(LTruncateFToInt32* ins);
|
||||
|
||||
// Out of line visitors.
|
||||
void visitOutOfLineBailout(OutOfLineBailout* ool);
|
||||
virtual void visitOutOfLineBailout(OutOfLineBailout* ool) = 0;
|
||||
protected:
|
||||
virtual ValueOperand ToOutValue(LInstruction* ins) = 0;
|
||||
void memoryBarrier(MemoryBarrierBits barrier);
|
||||
|
@ -898,6 +898,24 @@ MacroAssembler::call(JitCode* c)
|
||||
callJitNoProfiler(ScratchRegister);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callAndPushReturnAddress(Register callee)
|
||||
{
|
||||
// Push return address during jalr delay slot.
|
||||
subPtr(Imm32(sizeof(intptr_t)), StackPointer);
|
||||
as_jalr(callee);
|
||||
storePtr(ra, Address(StackPointer, 0));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callAndPushReturnAddress(Label* label)
|
||||
{
|
||||
// Push return address during bal delay slot.
|
||||
subPtr(Imm32(sizeof(intptr_t)), StackPointer);
|
||||
ma_bal(label, DontFillDelaySlot);
|
||||
storePtr(ra, Address(StackPointer, 0));
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Jit Frames.
|
||||
|
||||
|
@ -46,6 +46,16 @@ class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPS
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS::visitOutOfLineBailout(OutOfLineBailout* ool)
|
||||
{
|
||||
// Push snapshotOffset and make sure stack is aligned.
|
||||
masm.subPtr(Imm32(2 * sizeof(void*)), StackPointer);
|
||||
masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0));
|
||||
|
||||
masm.jump(&deoptLabel_);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
|
||||
{
|
||||
|
@ -40,6 +40,7 @@ class CodeGeneratorMIPS : public CodeGeneratorMIPSShared
|
||||
virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir);
|
||||
|
||||
// Out of line visitors.
|
||||
void visitOutOfLineBailout(OutOfLineBailout* ool);
|
||||
void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
|
||||
protected:
|
||||
ValueOperand ToValue(LInstruction* ins, size_t pos);
|
||||
|
@ -2562,27 +2562,6 @@ MacroAssembler::reserveStack(uint32_t amount)
|
||||
adjustFrame(amount);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Simple call functions.
|
||||
|
||||
void
|
||||
MacroAssembler::callAndPushReturnAddress(Register callee)
|
||||
{
|
||||
// Push return address during jalr delay slot.
|
||||
subPtr(Imm32(sizeof(intptr_t)), StackPointer);
|
||||
as_jalr(callee);
|
||||
storePtr(ra, Address(StackPointer, 0));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callAndPushReturnAddress(Label* label)
|
||||
{
|
||||
// Push return address during bal delay slot.
|
||||
subPtr(Imm32(sizeof(intptr_t)), StackPointer);
|
||||
ma_bal(label, DontFillDelaySlot);
|
||||
storePtr(ra, Address(StackPointer, 0));
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
|
@ -14,7 +14,7 @@ using namespace js::jit;
|
||||
|
||||
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
|
||||
BailoutStack* bailout)
|
||||
: machine_(bailout->machine())
|
||||
: machine_(bailout->machineState())
|
||||
{
|
||||
uint8_t* sp = bailout->parentStackPointer();
|
||||
framePointer_ = sp + bailout->frameSize();
|
||||
|
@ -15,60 +15,27 @@ namespace jit {
|
||||
|
||||
class BailoutStack
|
||||
{
|
||||
uintptr_t frameClassId_;
|
||||
// This is pushed in the bailout handler. Both entry points into the
|
||||
// handler inserts their own value int lr, which is then placed onto the
|
||||
// stack along with frameClassId_ above. This should be migrated to ip.
|
||||
public:
|
||||
union {
|
||||
uintptr_t frameSize_;
|
||||
uintptr_t tableOffset_;
|
||||
};
|
||||
|
||||
protected:
|
||||
RegisterDump::FPUArray fpregs_;
|
||||
RegisterDump::GPRArray regs_;
|
||||
|
||||
uintptr_t frameSize_;
|
||||
uintptr_t snapshotOffset_;
|
||||
uintptr_t padding_;
|
||||
|
||||
public:
|
||||
FrameSizeClass frameClass() const {
|
||||
return FrameSizeClass::FromClass(frameClassId_);
|
||||
}
|
||||
uintptr_t tableOffset() const {
|
||||
MOZ_ASSERT(frameClass() != FrameSizeClass::None());
|
||||
return tableOffset_;
|
||||
}
|
||||
uint32_t frameSize() const {
|
||||
if (frameClass() == FrameSizeClass::None())
|
||||
return frameSize_;
|
||||
return frameClass().frameSize();
|
||||
}
|
||||
MachineState machine() {
|
||||
MachineState machineState() {
|
||||
return MachineState::FromBailout(regs_, fpregs_);
|
||||
}
|
||||
SnapshotOffset snapshotOffset() const {
|
||||
MOZ_ASSERT(frameClass() == FrameSizeClass::None());
|
||||
uint32_t snapshotOffset() const {
|
||||
return snapshotOffset_;
|
||||
}
|
||||
uint8_t* parentStackPointer() const {
|
||||
if (frameClass() == FrameSizeClass::None())
|
||||
return (uint8_t*)this + sizeof(BailoutStack);
|
||||
return (uint8_t*)this + offsetof(BailoutStack, snapshotOffset_);
|
||||
uint32_t frameSize() const {
|
||||
return frameSize_;
|
||||
}
|
||||
static size_t offsetOfFrameClass() {
|
||||
return offsetof(BailoutStack, frameClassId_);
|
||||
uint8_t* parentStackPointer() {
|
||||
return (uint8_t*)this + sizeof(BailoutStack);
|
||||
}
|
||||
static size_t offsetOfFrameSize() {
|
||||
return offsetof(BailoutStack, frameSize_);
|
||||
}
|
||||
static size_t offsetOfFpRegs() {
|
||||
return offsetof(BailoutStack, fpregs_);
|
||||
}
|
||||
static size_t offsetOfRegs() {
|
||||
return offsetof(BailoutStack, regs_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
290
js/src/jit/mips64/CodeGenerator-mips64.cpp
Normal file
290
js/src/jit/mips64/CodeGenerator-mips64.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/mips64/CodeGenerator-mips64.h"
|
||||
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include "jit/CodeGenerator.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "jit/shared/CodeGenerator-shared-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPS64>
|
||||
{
|
||||
MTableSwitch* mir_;
|
||||
CodeLabel jumpLabel_;
|
||||
|
||||
void accept(CodeGeneratorMIPS64* codegen) {
|
||||
codegen->visitOutOfLineTableSwitch(this);
|
||||
}
|
||||
|
||||
public:
|
||||
OutOfLineTableSwitch(MTableSwitch* mir)
|
||||
: mir_(mir)
|
||||
{}
|
||||
|
||||
MTableSwitch* mir() const {
|
||||
return mir_;
|
||||
}
|
||||
|
||||
CodeLabel* jumpLabel() {
|
||||
return &jumpLabel_;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitOutOfLineBailout(OutOfLineBailout* ool)
|
||||
{
|
||||
masm.push(ImmWord(ool->snapshot()->snapshotOffset()));
|
||||
|
||||
masm.jump(&deoptLabel_);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
|
||||
{
|
||||
MTableSwitch* mir = ool->mir();
|
||||
|
||||
masm.haltingAlign(sizeof(void*));
|
||||
masm.bind(ool->jumpLabel()->src());
|
||||
masm.addCodeLabel(*ool->jumpLabel());
|
||||
|
||||
for (size_t i = 0; i < mir->numCases(); i++) {
|
||||
LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
|
||||
Label* caseheader = caseblock->label();
|
||||
uint32_t caseoffset = caseheader->offset();
|
||||
|
||||
// The entries of the jump table need to be absolute addresses and thus
|
||||
// must be patched after codegen is finished. Each table entry uses 8
|
||||
// instructions (4 for load address, 2 for branch, and 2 padding).
|
||||
CodeLabel cl;
|
||||
masm.ma_li(ScratchRegister, cl.dest());
|
||||
masm.branch(ScratchRegister);
|
||||
masm.as_nop();
|
||||
masm.as_nop();
|
||||
cl.src()->bind(caseoffset);
|
||||
masm.addCodeLabel(cl);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::emitTableSwitchDispatch(MTableSwitch* mir, Register index,
|
||||
Register address)
|
||||
{
|
||||
Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
|
||||
|
||||
// Lower value with low value
|
||||
if (mir->low() != 0)
|
||||
masm.subPtr(Imm32(mir->low()), index);
|
||||
|
||||
// Jump to default case if input is out of range
|
||||
int32_t cases = mir->numCases();
|
||||
masm.branch32(Assembler::AboveOrEqual, index, Imm32(cases), defaultcase);
|
||||
|
||||
// To fill in the CodeLabels for the case entries, we need to first
|
||||
// generate the case entries (we don't yet know their offsets in the
|
||||
// instruction stream).
|
||||
OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
|
||||
addOutOfLineCode(ool, mir);
|
||||
|
||||
// Compute the position where a pointer to the right case stands.
|
||||
masm.ma_li(address, ool->jumpLabel()->dest());
|
||||
// index = size of table entry * index.
|
||||
// See CodeGeneratorMIPS64::visitOutOfLineTableSwitch
|
||||
masm.lshiftPtr(Imm32(5), index);
|
||||
masm.addPtr(index, address);
|
||||
|
||||
masm.branch(address);
|
||||
}
|
||||
|
||||
FrameSizeClass
|
||||
FrameSizeClass::FromDepth(uint32_t frameDepth)
|
||||
{
|
||||
return FrameSizeClass::None();
|
||||
}
|
||||
|
||||
FrameSizeClass
|
||||
FrameSizeClass::ClassLimit()
|
||||
{
|
||||
return FrameSizeClass(0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FrameSizeClass::frameSize() const
|
||||
{
|
||||
MOZ_CRASH("MIPS64 does not use frame size classes");
|
||||
}
|
||||
|
||||
ValueOperand
|
||||
CodeGeneratorMIPS64::ToValue(LInstruction* ins, size_t pos)
|
||||
{
|
||||
return ValueOperand(ToRegister(ins->getOperand(pos)));
|
||||
}
|
||||
|
||||
ValueOperand
|
||||
CodeGeneratorMIPS64::ToOutValue(LInstruction* ins)
|
||||
{
|
||||
return ValueOperand(ToRegister(ins->getDef(0)));
|
||||
}
|
||||
|
||||
ValueOperand
|
||||
CodeGeneratorMIPS64::ToTempValue(LInstruction* ins, size_t pos)
|
||||
{
|
||||
return ValueOperand(ToRegister(ins->getTemp(pos)));
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitBox(LBox* box)
|
||||
{
|
||||
const LAllocation* in = box->getOperand(0);
|
||||
const LDefinition* result = box->getDef(0);
|
||||
|
||||
if (IsFloatingPointType(box->type())) {
|
||||
FloatRegister reg = ToFloatRegister(in);
|
||||
if (box->type() == MIRType_Float32) {
|
||||
masm.convertFloat32ToDouble(reg, ScratchDoubleReg);
|
||||
reg = ScratchDoubleReg;
|
||||
}
|
||||
masm.moveFromDouble(reg, ToRegister(result));
|
||||
} else {
|
||||
masm.boxValue(ValueTypeFromMIRType(box->type()), ToRegister(in), ToRegister(result));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitUnbox(LUnbox* unbox)
|
||||
{
|
||||
MUnbox* mir = unbox->mir();
|
||||
|
||||
if (mir->fallible()) {
|
||||
const ValueOperand value = ToValue(unbox, LUnbox::Input);
|
||||
masm.splitTag(value, SecondScratchReg);
|
||||
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(MIRTypeToTag(mir->type())),
|
||||
unbox->snapshot());
|
||||
}
|
||||
|
||||
Operand input = ToOperand(unbox->getOperand(LUnbox::Input));
|
||||
Register result = ToRegister(unbox->output());
|
||||
switch (mir->type()) {
|
||||
case MIRType_Int32:
|
||||
masm.unboxInt32(input, result);
|
||||
break;
|
||||
case MIRType_Boolean:
|
||||
masm.unboxBoolean(input, result);
|
||||
break;
|
||||
case MIRType_Object:
|
||||
masm.unboxObject(input, result);
|
||||
break;
|
||||
case MIRType_String:
|
||||
masm.unboxString(input, result);
|
||||
break;
|
||||
case MIRType_Symbol:
|
||||
masm.unboxSymbol(input, result);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Given MIRType cannot be unboxed.");
|
||||
}
|
||||
}
|
||||
|
||||
Register
|
||||
CodeGeneratorMIPS64::splitTagForTest(const ValueOperand& value)
|
||||
{
|
||||
MOZ_ASSERT(value.valueReg() != SecondScratchReg);
|
||||
masm.splitTag(value.valueReg(), SecondScratchReg);
|
||||
return SecondScratchReg;
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitCompareB(LCompareB* lir)
|
||||
{
|
||||
MCompare* mir = lir->mir();
|
||||
|
||||
const ValueOperand lhs = ToValue(lir, LCompareB::Lhs);
|
||||
const LAllocation* rhs = lir->rhs();
|
||||
const Register output = ToRegister(lir->output());
|
||||
|
||||
MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
|
||||
Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
|
||||
|
||||
// Load boxed boolean in ScratchRegister.
|
||||
if (rhs->isConstant())
|
||||
masm.moveValue(*rhs->toConstant(), ScratchRegister);
|
||||
else
|
||||
masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchRegister);
|
||||
|
||||
// Perform the comparison.
|
||||
masm.cmpPtrSet(cond, lhs.valueReg(), ScratchRegister, output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitCompareBAndBranch(LCompareBAndBranch* lir)
|
||||
{
|
||||
MCompare* mir = lir->cmpMir();
|
||||
const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs);
|
||||
const LAllocation* rhs = lir->rhs();
|
||||
|
||||
MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
|
||||
|
||||
// Load boxed boolean in ScratchRegister.
|
||||
if (rhs->isConstant())
|
||||
masm.moveValue(*rhs->toConstant(), ScratchRegister);
|
||||
else
|
||||
masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchRegister);
|
||||
|
||||
// Perform the comparison.
|
||||
Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
|
||||
emitBranch(lhs.valueReg(), ScratchRegister, cond, lir->ifTrue(), lir->ifFalse());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitCompareBitwise(LCompareBitwise* lir)
|
||||
{
|
||||
MCompare* mir = lir->mir();
|
||||
Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
|
||||
const ValueOperand lhs = ToValue(lir, LCompareBitwise::LhsInput);
|
||||
const ValueOperand rhs = ToValue(lir, LCompareBitwise::RhsInput);
|
||||
const Register output = ToRegister(lir->output());
|
||||
|
||||
MOZ_ASSERT(IsEqualityOp(mir->jsop()));
|
||||
|
||||
masm.cmpPtrSet(cond, lhs.valueReg(), rhs.valueReg(), output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir)
|
||||
{
|
||||
MCompare* mir = lir->cmpMir();
|
||||
Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
|
||||
const ValueOperand lhs = ToValue(lir, LCompareBitwiseAndBranch::LhsInput);
|
||||
const ValueOperand rhs = ToValue(lir, LCompareBitwiseAndBranch::RhsInput);
|
||||
|
||||
MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ ||
|
||||
mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
|
||||
|
||||
emitBranch(lhs.valueReg(), rhs.valueReg(), cond, lir->ifTrue(), lir->ifFalse());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS64::setReturnDoubleRegs(LiveRegisterSet* regs)
|
||||
{
|
||||
MOZ_ASSERT(ReturnFloat32Reg.reg_ == FloatRegisters::f0);
|
||||
MOZ_ASSERT(ReturnDoubleReg.reg_ == FloatRegisters::f0);
|
||||
FloatRegister f1 = { FloatRegisters::f1, FloatRegisters::Single };
|
||||
regs->add(ReturnFloat32Reg);
|
||||
regs->add(f1);
|
||||
regs->add(ReturnDoubleReg);
|
||||
}
|
76
js/src/jit/mips64/CodeGenerator-mips64.h
Normal file
76
js/src/jit/mips64/CodeGenerator-mips64.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_mips64_CodeGenerator_mips64_h
|
||||
#define jit_mips64_CodeGenerator_mips64_h
|
||||
|
||||
#include "jit/mips-shared/CodeGenerator-mips-shared.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class CodeGeneratorMIPS64 : public CodeGeneratorMIPSShared
|
||||
{
|
||||
protected:
|
||||
void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value,
|
||||
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
|
||||
{
|
||||
MOZ_ASSERT(value.valueReg() != SecondScratchReg);
|
||||
masm.splitTag(value.valueReg(), SecondScratchReg);
|
||||
emitBranch(SecondScratchReg, ImmTag(JSVAL_TAG_NULL), cond, ifTrue, ifFalse);
|
||||
}
|
||||
void testUndefinedEmitBranch(Assembler::Condition cond, const ValueOperand& value,
|
||||
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
|
||||
{
|
||||
MOZ_ASSERT(value.valueReg() != SecondScratchReg);
|
||||
masm.splitTag(value.valueReg(), SecondScratchReg);
|
||||
emitBranch(SecondScratchReg, ImmTag(JSVAL_TAG_UNDEFINED), cond, ifTrue, ifFalse);
|
||||
}
|
||||
void testObjectEmitBranch(Assembler::Condition cond, const ValueOperand& value,
|
||||
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
|
||||
{
|
||||
MOZ_ASSERT(value.valueReg() != SecondScratchReg);
|
||||
masm.splitTag(value.valueReg(), SecondScratchReg);
|
||||
emitBranch(SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), cond, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
|
||||
|
||||
public:
|
||||
virtual void visitCompareB(LCompareB* lir);
|
||||
virtual void visitCompareBAndBranch(LCompareBAndBranch* lir);
|
||||
virtual void visitCompareBitwise(LCompareBitwise* lir);
|
||||
virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir);
|
||||
|
||||
// Out of line visitors.
|
||||
void visitOutOfLineBailout(OutOfLineBailout* ool);
|
||||
void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
|
||||
protected:
|
||||
ValueOperand ToValue(LInstruction* ins, size_t pos);
|
||||
ValueOperand ToOutValue(LInstruction* ins);
|
||||
ValueOperand ToTempValue(LInstruction* ins, size_t pos);
|
||||
|
||||
// Functions for LTestVAndBranch.
|
||||
Register splitTagForTest(const ValueOperand& value);
|
||||
|
||||
public:
|
||||
CodeGeneratorMIPS64(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
|
||||
: CodeGeneratorMIPSShared(gen, graph, masm)
|
||||
{ }
|
||||
|
||||
public:
|
||||
void visitBox(LBox* box);
|
||||
void visitUnbox(LUnbox* unbox);
|
||||
|
||||
void setReturnDoubleRegs(LiveRegisterSet* regs);
|
||||
};
|
||||
|
||||
typedef CodeGeneratorMIPS64 CodeGeneratorSpecific;
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
#endif /* jit_mips64_CodeGenerator_mips64_h */
|
@ -573,20 +573,14 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
|
||||
* (See: JitRuntime::generateBailoutHandler).
|
||||
*/
|
||||
static void
|
||||
PushBailoutFrame(MacroAssembler& masm, uint32_t frameClass, Register spArg)
|
||||
PushBailoutFrame(MacroAssembler& masm, Register spArg)
|
||||
{
|
||||
// Make sure that alignment is proper.
|
||||
masm.checkStackAlignment();
|
||||
|
||||
// Push registers such that we can access them from [base + code].
|
||||
masm.PushRegsInMask(AllRegs);
|
||||
|
||||
// Push the frameSize_ or tableOffset_ stored in ra
|
||||
// Push the frameSize_ stored in ra
|
||||
// See: CodeGeneratorMIPS64::generateOutOfLineCode()
|
||||
masm.push(ra);
|
||||
|
||||
// Push frame class to stack
|
||||
masm.push(ImmWord(frameClass));
|
||||
// Push registers such that we can access them from [base + code].
|
||||
masm.PushRegsInMask(AllRegs);
|
||||
|
||||
// Put pointer to BailoutStack as first argument to the Bailout()
|
||||
masm.movePtr(StackPointer, spArg);
|
||||
@ -595,12 +589,11 @@ PushBailoutFrame(MacroAssembler& masm, uint32_t frameClass, Register spArg)
|
||||
static void
|
||||
GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
{
|
||||
PushBailoutFrame(masm, frameClass, a0);
|
||||
PushBailoutFrame(masm, a0);
|
||||
|
||||
// Put pointer to BailoutInfo
|
||||
static const uint32_t sizeOfBailoutInfo = sizeof(uintptr_t) * 2;
|
||||
masm.subPtr(Imm32(sizeOfBailoutInfo), StackPointer);
|
||||
masm.storePtr(ImmPtr(nullptr), Address(StackPointer, 0));
|
||||
masm.movePtr(StackPointer, a1);
|
||||
|
||||
masm.setupAlignedABICall();
|
||||
@ -611,6 +604,13 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
// Get BailoutInfo pointer
|
||||
masm.loadPtr(Address(StackPointer, 0), a2);
|
||||
|
||||
// Stack is:
|
||||
// [frame]
|
||||
// snapshotOffset
|
||||
// frameSize
|
||||
// [bailoutFrame]
|
||||
// [bailoutInfo]
|
||||
//
|
||||
// Remove both the bailout frame and the topmost Ion frame's stack.
|
||||
// Load frameSize from stack
|
||||
masm.loadPtr(Address(StackPointer,
|
||||
|
@ -781,7 +781,8 @@ class AsmJSHeapAccess
|
||||
cmpDelta_ = cmp == NoLengthCheck ? 0 : insnOffset - cmp;
|
||||
MOZ_ASSERT(offsetWithinWholeSimdVector_ == offsetWithinWholeSimdVector);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
|
||||
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
explicit AsmJSHeapAccess(uint32_t insnOffset)
|
||||
{
|
||||
mozilla::PodZero(this); // zero padding for Valgrind
|
||||
|
@ -1597,8 +1597,8 @@ CodeGeneratorShared::jumpToBlock(MBasicBlock* mir)
|
||||
}
|
||||
}
|
||||
|
||||
// This function is not used for MIPS. MIPS has branchToBlock.
|
||||
#ifndef JS_CODEGEN_MIPS32
|
||||
// This function is not used for MIPS/MIPS64. MIPS has branchToBlock.
|
||||
#if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64)
|
||||
void
|
||||
CodeGeneratorShared::jumpToBlock(MBasicBlock* mir, Assembler::Condition cond)
|
||||
{
|
||||
|
@ -471,7 +471,7 @@ class CodeGeneratorShared : public LElementVisitor
|
||||
void jumpToBlock(MBasicBlock* mir);
|
||||
|
||||
// This function is not used for MIPS. MIPS has branchToBlock.
|
||||
#ifndef JS_CODEGEN_MIPS32
|
||||
#if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64)
|
||||
void jumpToBlock(MBasicBlock* mir, Assembler::Condition cond);
|
||||
#endif
|
||||
|
||||
|
@ -190,7 +190,7 @@ LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefini
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE,
|
||||
LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegisters::Double))));
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2)));
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
MOZ_CRASH();
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "vm/Keywords.h"
|
||||
|
||||
static const char * const keyword_list[] = {
|
||||
#define KEYWORD_STRING(keyword, name, type, version) #keyword,
|
||||
#define KEYWORD_STRING(keyword, name, type) #keyword,
|
||||
FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_STRING)
|
||||
#undef KEYWORD_STRING
|
||||
};
|
||||
|
@ -515,6 +515,7 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
|
||||
'jit/mips64/Bailouts-mips64.cpp',
|
||||
'jit/mips64/BaselineCompiler-mips64.cpp',
|
||||
'jit/mips64/BaselineIC-mips64.cpp',
|
||||
'jit/mips64/CodeGenerator-mips64.cpp',
|
||||
'jit/mips64/Lowering-mips64.cpp',
|
||||
'jit/mips64/SharedIC-mips64.cpp',
|
||||
'jit/mips64/Trampoline-mips64.cpp',
|
||||
|
@ -10,58 +10,58 @@
|
||||
#define vm_Keywords_h
|
||||
|
||||
#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \
|
||||
macro(false, false_, TOK_FALSE, JSVERSION_DEFAULT) \
|
||||
macro(true, true_, TOK_TRUE, JSVERSION_DEFAULT) \
|
||||
macro(null, null, TOK_NULL, JSVERSION_DEFAULT) \
|
||||
macro(false, false_, TOK_FALSE) \
|
||||
macro(true, true_, TOK_TRUE) \
|
||||
macro(null, null, TOK_NULL) \
|
||||
/* Keywords. */ \
|
||||
macro(break, break_, TOK_BREAK, JSVERSION_DEFAULT) \
|
||||
macro(case, case_, TOK_CASE, JSVERSION_DEFAULT) \
|
||||
macro(catch, catch_, TOK_CATCH, JSVERSION_DEFAULT) \
|
||||
macro(const, const_, TOK_CONST, JSVERSION_DEFAULT) \
|
||||
macro(continue, continue_, TOK_CONTINUE, JSVERSION_DEFAULT) \
|
||||
macro(debugger, debugger, TOK_DEBUGGER, JSVERSION_DEFAULT) \
|
||||
macro(default, default_, TOK_DEFAULT, JSVERSION_DEFAULT) \
|
||||
macro(delete, delete_, TOK_DELETE, JSVERSION_DEFAULT) \
|
||||
macro(do, do_, TOK_DO, JSVERSION_DEFAULT) \
|
||||
macro(else, else_, TOK_ELSE, JSVERSION_DEFAULT) \
|
||||
macro(finally, finally_, TOK_FINALLY, JSVERSION_DEFAULT) \
|
||||
macro(for, for_, TOK_FOR, JSVERSION_DEFAULT) \
|
||||
macro(function, function, TOK_FUNCTION, JSVERSION_DEFAULT) \
|
||||
macro(if, if_, TOK_IF, JSVERSION_DEFAULT) \
|
||||
macro(in, in, TOK_IN, JSVERSION_DEFAULT) \
|
||||
macro(instanceof, instanceof, TOK_INSTANCEOF, JSVERSION_DEFAULT) \
|
||||
macro(new, new_, TOK_NEW, JSVERSION_DEFAULT) \
|
||||
macro(return, return_, TOK_RETURN, JSVERSION_DEFAULT) \
|
||||
macro(switch, switch_, TOK_SWITCH, JSVERSION_DEFAULT) \
|
||||
macro(this, this_, TOK_THIS, JSVERSION_DEFAULT) \
|
||||
macro(throw, throw_, TOK_THROW, JSVERSION_DEFAULT) \
|
||||
macro(try, try_, TOK_TRY, JSVERSION_DEFAULT) \
|
||||
macro(typeof, typeof, TOK_TYPEOF, JSVERSION_DEFAULT) \
|
||||
macro(var, var, TOK_VAR, JSVERSION_DEFAULT) \
|
||||
macro(void, void_, TOK_VOID, JSVERSION_DEFAULT) \
|
||||
macro(while, while_, TOK_WHILE, JSVERSION_DEFAULT) \
|
||||
macro(with, with, TOK_WITH, JSVERSION_DEFAULT) \
|
||||
macro(import, import, TOK_IMPORT, JSVERSION_DEFAULT) \
|
||||
macro(export, export, TOK_EXPORT, JSVERSION_DEFAULT) \
|
||||
macro(class, class_, TOK_CLASS, JSVERSION_DEFAULT) \
|
||||
macro(extends, extends, TOK_EXTENDS, JSVERSION_DEFAULT) \
|
||||
macro(super, super, TOK_SUPER, JSVERSION_DEFAULT) \
|
||||
macro(break, break_, TOK_BREAK) \
|
||||
macro(case, case_, TOK_CASE) \
|
||||
macro(catch, catch_, TOK_CATCH) \
|
||||
macro(const, const_, TOK_CONST) \
|
||||
macro(continue, continue_, TOK_CONTINUE) \
|
||||
macro(debugger, debugger, TOK_DEBUGGER) \
|
||||
macro(default, default_, TOK_DEFAULT) \
|
||||
macro(delete, delete_, TOK_DELETE) \
|
||||
macro(do, do_, TOK_DO) \
|
||||
macro(else, else_, TOK_ELSE) \
|
||||
macro(finally, finally_, TOK_FINALLY) \
|
||||
macro(for, for_, TOK_FOR) \
|
||||
macro(function, function, TOK_FUNCTION) \
|
||||
macro(if, if_, TOK_IF) \
|
||||
macro(in, in, TOK_IN) \
|
||||
macro(instanceof, instanceof, TOK_INSTANCEOF) \
|
||||
macro(new, new_, TOK_NEW) \
|
||||
macro(return, return_, TOK_RETURN) \
|
||||
macro(switch, switch_, TOK_SWITCH) \
|
||||
macro(this, this_, TOK_THIS) \
|
||||
macro(throw, throw_, TOK_THROW) \
|
||||
macro(try, try_, TOK_TRY) \
|
||||
macro(typeof, typeof, TOK_TYPEOF) \
|
||||
macro(var, var, TOK_VAR) \
|
||||
macro(void, void_, TOK_VOID) \
|
||||
macro(while, while_, TOK_WHILE) \
|
||||
macro(with, with, TOK_WITH) \
|
||||
macro(import, import, TOK_IMPORT) \
|
||||
macro(export, export, TOK_EXPORT) \
|
||||
macro(class, class_, TOK_CLASS) \
|
||||
macro(extends, extends, TOK_EXTENDS) \
|
||||
macro(super, super, TOK_SUPER) \
|
||||
/* Reserved keywords. */ \
|
||||
macro(enum, enum_, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(enum, enum_, TOK_RESERVED) \
|
||||
/* Future reserved keywords, but only in strict mode. */ \
|
||||
macro(implements, implements, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(interface, interface, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(package, package, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(private, private_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(protected, protected_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(implements, implements, TOK_STRICT_RESERVED) \
|
||||
macro(interface, interface, TOK_STRICT_RESERVED) \
|
||||
macro(package, package, TOK_STRICT_RESERVED) \
|
||||
macro(private, private_, TOK_STRICT_RESERVED) \
|
||||
macro(protected, protected_, TOK_STRICT_RESERVED) \
|
||||
macro(public, public_, TOK_STRICT_RESERVED) \
|
||||
macro(static, static_, TOK_STRICT_RESERVED) \
|
||||
/* \
|
||||
* Yield is a token inside function*. Outside of a function*, it is a \
|
||||
* future reserved keyword in strict mode, but a keyword in JS1.7 even \
|
||||
* when strict. Punt logic to parser. \
|
||||
*/ \
|
||||
macro(yield, yield, TOK_YIELD, JSVERSION_DEFAULT) \
|
||||
macro(let, let, TOK_LET, JSVERSION_DEFAULT)
|
||||
macro(yield, yield, TOK_YIELD) \
|
||||
macro(let, let, TOK_LET)
|
||||
|
||||
#endif /* vm_Keywords_h */
|
||||
|
@ -385,13 +385,15 @@ QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote)
|
||||
}
|
||||
|
||||
Fprinter::Fprinter(FILE* fp)
|
||||
: file_(nullptr)
|
||||
: file_(nullptr),
|
||||
init_(false)
|
||||
{
|
||||
init(fp);
|
||||
}
|
||||
|
||||
Fprinter::Fprinter()
|
||||
: file_(nullptr)
|
||||
: file_(nullptr),
|
||||
init_(false)
|
||||
{ }
|
||||
|
||||
Fprinter::~Fprinter()
|
||||
|
@ -65,9 +65,6 @@ public:
|
||||
return mPresContext;
|
||||
}
|
||||
|
||||
nsCSSFrameConstructor* FrameConstructor() const
|
||||
{ return PresContext()->FrameConstructor(); }
|
||||
|
||||
// Should be called when a frame is going to be destroyed and
|
||||
// WillDestroyFrameTree hasn't been called yet.
|
||||
void NotifyDestroyingFrame(nsIFrame* aFrame);
|
||||
@ -138,6 +135,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
nsCSSFrameConstructor* FrameConstructor() const
|
||||
{ return PresContext()->FrameConstructor(); }
|
||||
|
||||
// Used when restyling an element with a frame.
|
||||
void ComputeAndProcessStyleChange(nsIFrame* aFrame,
|
||||
nsChangeHint aMinChange,
|
||||
|
@ -5088,17 +5088,6 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
result = Matrix4x4::From2D(svgTransform);
|
||||
}
|
||||
|
||||
if (aProperties.mChildPerspective > 0.0) {
|
||||
Matrix4x4 perspective;
|
||||
perspective._34 =
|
||||
-1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel);
|
||||
/* At the point when perspective is applied, we have been translated to the transform origin.
|
||||
* The translation to the perspective origin is the difference between these values.
|
||||
*/
|
||||
perspective.ChangeBasis(aProperties.GetToPerspectiveOrigin() - aProperties.mToTransformOrigin);
|
||||
result = result * perspective;
|
||||
}
|
||||
|
||||
/* Account for the transform-origin property by translating the
|
||||
* coordinate space to the new origin.
|
||||
*/
|
||||
@ -5110,12 +5099,15 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y),
|
||||
0);
|
||||
|
||||
bool hasPerspective = aProperties.mChildPerspective > 0.0;
|
||||
|
||||
if (!hasSVGTransforms || !hasTransformFromSVGParent) {
|
||||
// This is a simplification of the following |else| block, the
|
||||
// simplification being possible because we don't need to apply
|
||||
// mToTransformOrigin between two transforms.
|
||||
Point3D offsets = roundedOrigin + aProperties.mToTransformOrigin;
|
||||
if (aOffsetByOrigin) {
|
||||
if (aOffsetByOrigin &&
|
||||
!hasPerspective) {
|
||||
// We can fold the final translation by roundedOrigin into the first matrix
|
||||
// basis change translation. This is more stable against variation due to
|
||||
// insufficient floating point precision than reversing the translation
|
||||
@ -5149,7 +5141,8 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
// for mToTransformOrigin so we don't include that. We also need to reapply
|
||||
// refBoxOffset.
|
||||
Point3D offsets = roundedOrigin + refBoxOffset;
|
||||
if (aOffsetByOrigin) {
|
||||
if (aOffsetByOrigin &&
|
||||
!hasPerspective) {
|
||||
result.PreTranslate(-refBoxOffset);
|
||||
result.PostTranslate(offsets);
|
||||
} else {
|
||||
@ -5157,6 +5150,19 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPerspective) {
|
||||
Matrix4x4 perspective;
|
||||
perspective._34 =
|
||||
-1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel);
|
||||
|
||||
perspective.ChangeBasis(aProperties.GetToPerspectiveOrigin() + roundedOrigin);
|
||||
result = result * perspective;
|
||||
|
||||
if (aOffsetByOrigin) {
|
||||
result.PreTranslate(roundedOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
if (aDoPreserves3D && frame && frame->Combines3DTransformWithAncestors()) {
|
||||
// Include the transform set on our parent
|
||||
NS_ASSERTION(frame->GetParent() &&
|
||||
|
@ -430,7 +430,7 @@ public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsIFrame)
|
||||
|
||||
nsPresContext* PresContext() const {
|
||||
return StyleContext()->RuleNode()->PresContext();
|
||||
return StyleContext()->PresContext();
|
||||
}
|
||||
|
||||
/**
|
||||
|
BIN
layout/reftests/svg/filters/mozilla-banner.gif
Normal file
BIN
layout/reftests/svg/filters/mozilla-banner.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
@ -47,6 +47,7 @@ fuzzy(1,6400) == feGaussianBlur-1.svg feGaussianBlur-1-ref.svg
|
||||
== feGaussianBlur-6.svg feGaussianBlur-6-ref.svg
|
||||
skip-if(d2d) pref(layers.acceleration.disabled,true) == feGaussianBlur-cap-large-directional-radius-on-software.html feGaussianBlur-cap-large-directional-radius-on-software-ref.html
|
||||
|
||||
!= feImage-1.svg about:blank # (Make sure our image renders at all)
|
||||
== feImage-1.svg feImage-1-ref.svg
|
||||
== feImage-scale-to-primitive-subregion.html feImage-scale-to-primitive-subregion-ref.html
|
||||
|
||||
|
@ -265,22 +265,6 @@ public:
|
||||
// Tell this style context to cache aStruct as the struct for aSID
|
||||
void SetStyle(nsStyleStructID aSID, void* aStruct);
|
||||
|
||||
// Setters for inherit structs only, since rulenode only sets those eagerly.
|
||||
#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
|
||||
void SetStyle##name_ (nsStyle##name_ * aStruct) { \
|
||||
void *& slot = \
|
||||
mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]; \
|
||||
NS_ASSERTION(!slot || \
|
||||
(mBits & \
|
||||
nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \
|
||||
"Going to leak styledata"); \
|
||||
slot = aStruct; \
|
||||
}
|
||||
#define STYLE_STRUCT_RESET(name_, checkdata_cb_) /* nothing */
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT_RESET
|
||||
#undef STYLE_STRUCT_INHERITED
|
||||
|
||||
/**
|
||||
* Returns whether this style context has cached style data for a
|
||||
* given style struct and it does NOT own that struct. This can
|
||||
|
@ -2190,7 +2190,7 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
|
||||
ALOGW("sub-sidx boxes not supported yet");
|
||||
}
|
||||
bool sap = d3 & 0x80000000;
|
||||
bool saptype = d3 >> 28;
|
||||
uint32_t saptype = (d3 >> 28) & 0x3;
|
||||
if (!sap || saptype > 2) {
|
||||
ALOGW("not a stream access point, or unsupported type");
|
||||
}
|
||||
|
@ -124,3 +124,6 @@ if CONFIG['GNU_CXX']:
|
||||
if CONFIG['_MSC_VER']:
|
||||
# Error 4804 is "'>' : unsafe use of type 'bool' in operation"
|
||||
SOURCES['/mfbt/Compression.cpp'].flags += ['-wd4804']
|
||||
|
||||
if CONFIG['MOZ_NEEDS_LIBATOMIC']:
|
||||
OS_LIBS += ['atomic']
|
||||
|
@ -90,11 +90,6 @@ public class Launcher extends FragmentActivity
|
||||
IntentHelper.init(this);
|
||||
mScreenStateObserver = new ScreenStateObserver(this);
|
||||
|
||||
// Disable the default lockscreen.
|
||||
KeyguardManager keyguardManager = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);
|
||||
KeyguardLock lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
|
||||
lock.disableKeyguard();
|
||||
|
||||
initGecko();
|
||||
|
||||
GeckoAppShell.setGeckoInterface(new BaseGeckoInterface(this));
|
||||
|
@ -13,7 +13,7 @@ MOZ_APP_UA_NAME=Firefox
|
||||
|
||||
MOZ_UA_OS_AGNOSTIC=1
|
||||
|
||||
MOZ_B2G_VERSION=2.5.0.0-prerelease
|
||||
MOZ_B2G_VERSION=2.6.0.0-prerelease
|
||||
MOZ_B2G_OS_NAME=Boot2Gecko
|
||||
|
||||
MOZ_BRANDING_DIRECTORY=mobile/android/b2gdroid/branding/unofficial
|
||||
|
@ -17,7 +17,7 @@ interface nsIFile;
|
||||
* 3) Support for uniquely identifying cached data in cases when the URL
|
||||
* is insufficient (e.g., HTTP form submission).
|
||||
*/
|
||||
[scriptable, uuid(436b939d-e391-48e5-ba64-ab0e496e3400)]
|
||||
[scriptable, uuid(dd1d6122-5ecf-4fe4-8f0f-995e7ab3121a)]
|
||||
interface nsICachingChannel : nsICacheInfoChannel
|
||||
{
|
||||
/**
|
||||
@ -53,6 +53,11 @@ interface nsICachingChannel : nsICacheInfoChannel
|
||||
*/
|
||||
attribute boolean cacheOnlyMetadata;
|
||||
|
||||
/**
|
||||
* Tells the channel to use the pinning storage.
|
||||
*/
|
||||
attribute boolean pin;
|
||||
|
||||
/**************************************************************************
|
||||
* Caching channel specific load flags:
|
||||
*/
|
||||
|
@ -24,7 +24,7 @@ interface nsIVerificationCallback;
|
||||
* https://wiki.mozilla.org/FirefoxOS/New_security_model/Packaging
|
||||
*/
|
||||
|
||||
[scriptable, uuid(edf91fee-ef4a-4479-9136-27eb3b7a6312)]
|
||||
[scriptable, uuid(2963609c-370b-4a76-9858-6f05121d0473)]
|
||||
interface nsIPackagedAppUtils : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -55,6 +55,12 @@ interface nsIPackagedAppUtils : nsISupports
|
||||
* manifest is verified.
|
||||
*/
|
||||
readonly attribute ACString packageIdentifier;
|
||||
|
||||
/**
|
||||
* The moz-package-location in the manifest of this signed package.
|
||||
* Only available after the manifest is verified.
|
||||
*/
|
||||
readonly attribute ACString packageOrigin;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(AppCacheStorage, CacheStorage)
|
||||
|
||||
AppCacheStorage::AppCacheStorage(nsILoadContextInfo* aInfo,
|
||||
nsIApplicationCache* aAppCache)
|
||||
: CacheStorage(aInfo, true /* disk */, false /* lookup app cache */, false /* skip size check */)
|
||||
: CacheStorage(aInfo, true /* disk */, false /* lookup app cache */, false /* skip size check */, false /* pin */)
|
||||
, mAppCache(aAppCache)
|
||||
{
|
||||
MOZ_COUNT_CTOR(AppCacheStorage);
|
||||
|
@ -87,6 +87,8 @@ CacheEntry::Callback::Callback(CacheEntry* aEntry,
|
||||
, mRecheckAfterWrite(false)
|
||||
, mNotWanted(false)
|
||||
, mSecret(aSecret)
|
||||
, mDoomWhenFoundPinned(false)
|
||||
, mDoomWhenFoundNonPinned(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CacheEntry::Callback);
|
||||
|
||||
@ -96,6 +98,22 @@ CacheEntry::Callback::Callback(CacheEntry* aEntry,
|
||||
mEntry->AddHandleRef();
|
||||
}
|
||||
|
||||
CacheEntry::Callback::Callback(CacheEntry* aEntry, bool aDoomWhenFoundInPinStatus)
|
||||
: mEntry(aEntry)
|
||||
, mReadOnly(false)
|
||||
, mRevalidating(false)
|
||||
, mCheckOnAnyThread(true)
|
||||
, mRecheckAfterWrite(false)
|
||||
, mNotWanted(false)
|
||||
, mSecret(false)
|
||||
, mDoomWhenFoundPinned(aDoomWhenFoundInPinStatus == true)
|
||||
, mDoomWhenFoundNonPinned(aDoomWhenFoundInPinStatus == false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CacheEntry::Callback);
|
||||
MOZ_ASSERT(mEntry->HandlesCount());
|
||||
mEntry->AddHandleRef();
|
||||
}
|
||||
|
||||
CacheEntry::Callback::Callback(CacheEntry::Callback const &aThat)
|
||||
: mEntry(aThat.mEntry)
|
||||
, mCallback(aThat.mCallback)
|
||||
@ -106,6 +124,8 @@ CacheEntry::Callback::Callback(CacheEntry::Callback const &aThat)
|
||||
, mRecheckAfterWrite(aThat.mRecheckAfterWrite)
|
||||
, mNotWanted(aThat.mNotWanted)
|
||||
, mSecret(aThat.mSecret)
|
||||
, mDoomWhenFoundPinned(aThat.mDoomWhenFoundPinned)
|
||||
, mDoomWhenFoundNonPinned(aThat.mDoomWhenFoundNonPinned)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CacheEntry::Callback);
|
||||
|
||||
@ -136,6 +156,20 @@ void CacheEntry::Callback::ExchangeEntry(CacheEntry* aEntry)
|
||||
mEntry = aEntry;
|
||||
}
|
||||
|
||||
bool CacheEntry::Callback::DeferDoom(bool *aDoom) const
|
||||
{
|
||||
MOZ_ASSERT(mEntry->mPinningKnown);
|
||||
|
||||
if (MOZ_UNLIKELY(mDoomWhenFoundNonPinned) || MOZ_UNLIKELY(mDoomWhenFoundPinned)) {
|
||||
*aDoom = (MOZ_UNLIKELY(mDoomWhenFoundNonPinned) && MOZ_LIKELY(!mEntry->mPinned)) ||
|
||||
(MOZ_UNLIKELY(mDoomWhenFoundPinned) && MOZ_UNLIKELY(mEntry->mPinned));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult CacheEntry::Callback::OnCheckThread(bool *aOnCheckThread) const
|
||||
{
|
||||
if (!mCheckOnAnyThread) {
|
||||
@ -164,7 +198,8 @@ CacheEntry::CacheEntry(const nsACString& aStorageID,
|
||||
nsIURI* aURI,
|
||||
const nsACString& aEnhanceID,
|
||||
bool aUseDisk,
|
||||
bool aSkipSizeCheck)
|
||||
bool aSkipSizeCheck,
|
||||
bool aPin)
|
||||
: mFrecency(0)
|
||||
, mSortingExpirationTime(uint32_t(-1))
|
||||
, mLock("CacheEntry")
|
||||
@ -174,10 +209,12 @@ CacheEntry::CacheEntry(const nsACString& aStorageID,
|
||||
, mStorageID(aStorageID)
|
||||
, mUseDisk(aUseDisk)
|
||||
, mSkipSizeCheck(aSkipSizeCheck)
|
||||
, mIsDoomed(false)
|
||||
, mSecurityInfoLoaded(false)
|
||||
, mPreventCallbacks(false)
|
||||
, mHasData(false)
|
||||
, mPinned(aPin)
|
||||
, mPinningKnown(false)
|
||||
, mIsDoomed(false)
|
||||
, mState(NOTLOADED)
|
||||
, mRegistration(NEVERREGISTERED)
|
||||
, mWriter(nullptr)
|
||||
@ -350,16 +387,18 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
|
||||
if (NS_SUCCEEDED(CacheIndex::HasEntry(fileKey, &status))) {
|
||||
switch (status) {
|
||||
case CacheIndex::DOES_NOT_EXIST:
|
||||
LOG((" entry doesn't exist according information from the index, truncating"));
|
||||
// Doesn't apply to memory-only entries, Load() is called only once for them
|
||||
// and never again for their session lifetime.
|
||||
if (!aTruncate && mUseDisk) {
|
||||
LOG((" entry doesn't exist according information from the index, truncating"));
|
||||
reportMiss = true;
|
||||
aTruncate = true;
|
||||
}
|
||||
aTruncate = true;
|
||||
break;
|
||||
case CacheIndex::EXISTS:
|
||||
case CacheIndex::DO_NOT_KNOW:
|
||||
if (!mUseDisk) {
|
||||
LOG((" entry open as memory-only, but there is (status=%d) a file, dooming it", status));
|
||||
LOG((" entry open as memory-only, but there is a file, status=%d, dooming it", status));
|
||||
CacheFileIOManager::DoomFileByKey(fileKey, nullptr);
|
||||
}
|
||||
break;
|
||||
@ -376,6 +415,7 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
|
||||
// mLoadStart will be used to calculate telemetry of life-time of this entry.
|
||||
// Low resulution is then enough.
|
||||
mLoadStart = TimeStamp::NowLoRes();
|
||||
mPinningKnown = true;
|
||||
} else {
|
||||
mLoadStart = TimeStamp::Now();
|
||||
}
|
||||
@ -395,6 +435,7 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
|
||||
!mUseDisk,
|
||||
mSkipSizeCheck,
|
||||
aPriority,
|
||||
mPinned,
|
||||
directLoad ? nullptr : this);
|
||||
}
|
||||
|
||||
@ -432,9 +473,10 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
|
||||
}
|
||||
|
||||
// OnFileReady, that is the only code that can transit from LOADING
|
||||
// to any follow-on state, can only be invoked ones on an entry,
|
||||
// thus no need to lock. Until this moment there is no consumer that
|
||||
// could manipulate the entry state.
|
||||
// to any follow-on state and can only be invoked ones on an entry.
|
||||
// Until this moment there is no consumer that could manipulate
|
||||
// the entry state.
|
||||
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
|
||||
MOZ_ASSERT(mState == LOADING);
|
||||
@ -445,6 +487,10 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
|
||||
|
||||
mFileStatus = aResult;
|
||||
|
||||
mPinned = mFile->IsPinned();;
|
||||
mPinningKnown = true;
|
||||
LOG((" pinning=%d", mPinned));
|
||||
|
||||
if (mState == READY) {
|
||||
mHasData = true;
|
||||
|
||||
@ -456,6 +502,7 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
|
||||
}
|
||||
|
||||
InvokeCallbacks();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -483,6 +530,13 @@ already_AddRefed<CacheEntryHandle> CacheEntry::ReopenTruncated(bool aMemoryOnly,
|
||||
RefPtr<CacheEntryHandle> handle;
|
||||
RefPtr<CacheEntry> newEntry;
|
||||
{
|
||||
if (mPinned) {
|
||||
MOZ_ASSERT(mUseDisk);
|
||||
// We want to pin even no-store entries (the case we recreate a disk entry as
|
||||
// a memory-only entry.)
|
||||
aMemoryOnly = false;
|
||||
}
|
||||
|
||||
mozilla::MutexAutoUnlock unlock(mLock);
|
||||
|
||||
// The following call dooms this entry (calls DoomAlreadyRemoved on us)
|
||||
@ -490,6 +544,7 @@ already_AddRefed<CacheEntryHandle> CacheEntry::ReopenTruncated(bool aMemoryOnly,
|
||||
GetStorageID(), GetURI(), GetEnhanceID(),
|
||||
mUseDisk && !aMemoryOnly,
|
||||
mSkipSizeCheck,
|
||||
mPinned,
|
||||
true, // always create
|
||||
true, // truncate existing (this one)
|
||||
getter_AddRefs(handle));
|
||||
@ -577,6 +632,8 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly)
|
||||
{
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
|
||||
RefPtr<CacheEntryHandle> recreatedHandle;
|
||||
|
||||
uint32_t i = 0;
|
||||
while (i < mCallbacks.Length()) {
|
||||
if (mPreventCallbacks) {
|
||||
@ -589,6 +646,18 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool recreate;
|
||||
if (mCallbacks[i].DeferDoom(&recreate)) {
|
||||
mCallbacks.RemoveElementAt(i);
|
||||
if (!recreate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG((" defer doom marker callback hit positive, recreating"));
|
||||
recreatedHandle = ReopenTruncated(!mUseDisk, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mCallbacks[i].mReadOnly != aReadOnly) {
|
||||
// Callback is not r/w or r/o, go to another one in line
|
||||
++i;
|
||||
@ -625,6 +694,12 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly)
|
||||
}
|
||||
}
|
||||
|
||||
if (recreatedHandle) {
|
||||
// Must be released outside of the lock, enters InvokeCallback on the new entry
|
||||
mozilla::MutexAutoUnlock unlock(mLock);
|
||||
recreatedHandle = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -991,6 +1066,13 @@ NS_IMETHODIMP CacheEntry::GetIsForcedValid(bool *aIsForcedValid)
|
||||
{
|
||||
NS_ENSURE_ARG(aIsForcedValid);
|
||||
|
||||
MOZ_ASSERT(mState > LOADING);
|
||||
|
||||
if (mPinned) {
|
||||
*aIsForcedValid = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString key;
|
||||
|
||||
nsresult rv = HashingKeyWithStorage(key);
|
||||
@ -1442,6 +1524,28 @@ void CacheEntry::SetRegistered(bool aRegistered)
|
||||
}
|
||||
}
|
||||
|
||||
bool CacheEntry::DeferOrBypassRemovalOnPinStatus(bool aPinned)
|
||||
{
|
||||
LOG(("CacheEntry::DeferOrBypassRemovalOnPinStatus [this=%p]", this));
|
||||
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
|
||||
if (mPinningKnown) {
|
||||
LOG((" pinned=%d, caller=%d", mPinned, aPinned));
|
||||
// Bypass when the pin status of this entry doesn't match the pin status
|
||||
// caller wants to remove
|
||||
return mPinned != aPinned;
|
||||
}
|
||||
|
||||
LOG((" pinning unknown, caller=%d", aPinned));
|
||||
// Oterwise, remember to doom after the status is determined for any
|
||||
// callback opening the entry after this point...
|
||||
Callback c(this, aPinned);
|
||||
RememberCallback(c);
|
||||
// ...and always bypass
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheEntry::Purge(uint32_t aWhat)
|
||||
{
|
||||
LOG(("CacheEntry::Purge [this=%p, what=%d]", this, aWhat));
|
||||
@ -1523,6 +1627,10 @@ void CacheEntry::DoomAlreadyRemoved()
|
||||
|
||||
mIsDoomed = true;
|
||||
|
||||
// Pretend pinning is know. This entry is now doomed for good, so don't
|
||||
// bother with defering doom because of unknown pinning state any more.
|
||||
mPinningKnown = true;
|
||||
|
||||
// This schedules dooming of the file, dooming is ensured to happen
|
||||
// sooner than demand to open the same file made after this point
|
||||
// so that we don't get this file for any newer opened entry(s).
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
CacheEntry(const nsACString& aStorageID, nsIURI* aURI, const nsACString& aEnhanceID,
|
||||
bool aUseDisk, bool aSkipSizeCheck);
|
||||
bool aUseDisk, bool aSkipSizeCheck, bool aPin);
|
||||
|
||||
void AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags);
|
||||
|
||||
@ -92,6 +92,7 @@ public:
|
||||
PURGE_WHOLE,
|
||||
};
|
||||
|
||||
bool DeferOrBypassRemovalOnPinStatus(bool aPinned);
|
||||
bool Purge(uint32_t aWhat);
|
||||
void PurgeAndDoom();
|
||||
void DoomAlreadyRemoved();
|
||||
@ -136,6 +137,9 @@ private:
|
||||
Callback(CacheEntry* aEntry,
|
||||
nsICacheEntryOpenCallback *aCallback,
|
||||
bool aReadOnly, bool aCheckOnAnyThread, bool aSecret);
|
||||
// Special constructor for Callback objects added to the chain
|
||||
// just to ensure proper defer dooming (recreation) of this entry.
|
||||
Callback(CacheEntry* aEntry, bool aDoomWhenFoundInPinStatus);
|
||||
Callback(Callback const &aThat);
|
||||
~Callback();
|
||||
|
||||
@ -143,6 +147,10 @@ private:
|
||||
// mainly during recreation.
|
||||
void ExchangeEntry(CacheEntry* aEntry);
|
||||
|
||||
// Returns true when an entry is about to be "defer" doomed and this is
|
||||
// a "defer" callback.
|
||||
bool DeferDoom(bool *aDoom) const;
|
||||
|
||||
// We are raising reference count here to take into account the pending
|
||||
// callback (that virtually holds a ref to this entry before it gets
|
||||
// it's pointer).
|
||||
@ -156,6 +164,13 @@ private:
|
||||
bool mNotWanted : 1;
|
||||
bool mSecret : 1;
|
||||
|
||||
// These are set only for the defer-doomer Callback instance inserted
|
||||
// to the callback chain. When any of these is set and also any of
|
||||
// the corressponding flags on the entry is set, this callback will
|
||||
// indicate (via DeferDoom()) the entry have to be recreated/doomed.
|
||||
bool mDoomWhenFoundPinned : 1;
|
||||
bool mDoomWhenFoundNonPinned : 1;
|
||||
|
||||
nsresult OnCheckThread(bool *aOnCheckThread) const;
|
||||
nsresult OnAvailThread(bool *aOnAvailThread) const;
|
||||
};
|
||||
@ -274,14 +289,9 @@ private:
|
||||
nsCString mStorageID;
|
||||
|
||||
// Whether it's allowed to persist the data to disk
|
||||
bool const mUseDisk;
|
||||
|
||||
bool const mUseDisk : 1;
|
||||
// Whether it should skip max size check.
|
||||
bool const mSkipSizeCheck;
|
||||
|
||||
// Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
|
||||
// Left as a standalone flag to not bother with locking (there is no need).
|
||||
bool mIsDoomed;
|
||||
bool const mSkipSizeCheck : 1;
|
||||
|
||||
// Following flags are all synchronized with the cache entry lock.
|
||||
|
||||
@ -296,6 +306,15 @@ private:
|
||||
// false: after load and a new file, or dropped to back to false when a writer
|
||||
// fails to open an output stream.
|
||||
bool mHasData : 1;
|
||||
// The indication of pinning this entry was open with
|
||||
bool mPinned : 1;
|
||||
// Whether the pinning state of the entry is known (equals to the actual state
|
||||
// of the cache file)
|
||||
bool mPinningKnown : 1;
|
||||
|
||||
// Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
|
||||
// Left as a standalone flag to not bother with locking (there is no need).
|
||||
bool mIsDoomed;
|
||||
|
||||
static char const * StateString(uint32_t aState);
|
||||
|
||||
|
@ -102,7 +102,7 @@ protected:
|
||||
nsCOMPtr<CacheFileChunkListener> mCallback;
|
||||
nsresult mRV;
|
||||
uint32_t mChunkIdx;
|
||||
RefPtr<CacheFileChunk> mChunk;
|
||||
RefPtr<CacheFileChunk> mChunk;
|
||||
};
|
||||
|
||||
|
||||
@ -185,6 +185,7 @@ CacheFile::CacheFile()
|
||||
, mMemoryOnly(false)
|
||||
, mSkipSizeCheck(false)
|
||||
, mOpenAsMemoryOnly(false)
|
||||
, mPinned(false)
|
||||
, mPriority(false)
|
||||
, mDataAccessed(false)
|
||||
, mDataIsDirty(false)
|
||||
@ -215,17 +216,21 @@ CacheFile::Init(const nsACString &aKey,
|
||||
bool aMemoryOnly,
|
||||
bool aSkipSizeCheck,
|
||||
bool aPriority,
|
||||
bool aPinned,
|
||||
CacheFileListener *aCallback)
|
||||
{
|
||||
MOZ_ASSERT(!mListener);
|
||||
MOZ_ASSERT(!mHandle);
|
||||
|
||||
MOZ_ASSERT(!(aMemoryOnly && aPinned));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
mKey = aKey;
|
||||
mOpenAsMemoryOnly = mMemoryOnly = aMemoryOnly;
|
||||
mSkipSizeCheck = aSkipSizeCheck;
|
||||
mPriority = aPriority;
|
||||
mPinned = aPinned;
|
||||
|
||||
// Some consumers (at least nsHTTPCompressConv) assume that Read() can read
|
||||
// such amount of data that was announced by Available().
|
||||
@ -244,7 +249,7 @@ CacheFile::Init(const nsACString &aKey,
|
||||
if (mMemoryOnly) {
|
||||
MOZ_ASSERT(!aCallback);
|
||||
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mKey);
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, false, mKey);
|
||||
mReady = true;
|
||||
mDataSize = mMetadata->Offset();
|
||||
return NS_OK;
|
||||
@ -256,7 +261,7 @@ CacheFile::Init(const nsACString &aKey,
|
||||
flags = CacheFileIOManager::CREATE_NEW;
|
||||
|
||||
// make sure we can use this entry immediately
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mKey);
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mPinned, mKey);
|
||||
mReady = true;
|
||||
mDataSize = mMetadata->Offset();
|
||||
} else {
|
||||
@ -267,6 +272,10 @@ CacheFile::Init(const nsACString &aKey,
|
||||
flags |= CacheFileIOManager::PRIORITY;
|
||||
}
|
||||
|
||||
if (mPinned) {
|
||||
flags |= CacheFileIOManager::PINNED;
|
||||
}
|
||||
|
||||
mOpeningFile = true;
|
||||
mListener = aCallback;
|
||||
rv = CacheFileIOManager::OpenFile(mKey, flags, this);
|
||||
@ -274,6 +283,12 @@ CacheFile::Init(const nsACString &aKey,
|
||||
mListener = nullptr;
|
||||
mOpeningFile = false;
|
||||
|
||||
if (mPinned) {
|
||||
LOG(("CacheFile::Init() - CacheFileIOManager::OpenFile() failed "
|
||||
"but we want to pin, fail the file opening. [this=%p]", this));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (aCreateNew) {
|
||||
NS_WARNING("Forcing memory-only entry since OpenFile failed");
|
||||
LOG(("CacheFile::Init() - CacheFileIOManager::OpenFile() failed "
|
||||
@ -289,7 +304,7 @@ CacheFile::Init(const nsACString &aKey,
|
||||
"initializing entry as memory-only. [this=%p]", this));
|
||||
|
||||
mMemoryOnly = true;
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mKey);
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mPinned, mKey);
|
||||
mReady = true;
|
||||
mDataSize = mMetadata->Offset();
|
||||
|
||||
@ -482,7 +497,8 @@ CacheFile::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
autoDoom.mAlreadyDoomed = true;
|
||||
return NS_OK;
|
||||
}
|
||||
else if (NS_FAILED(aResult)) {
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
if (mMetadata) {
|
||||
// This entry was initialized as createNew, just switch to memory-only
|
||||
// mode.
|
||||
@ -494,7 +510,8 @@ CacheFile::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
mMemoryOnly = true;
|
||||
return NS_OK;
|
||||
}
|
||||
else if (aResult == NS_ERROR_FILE_INVALID_PATH) {
|
||||
|
||||
if (aResult == NS_ERROR_FILE_INVALID_PATH) {
|
||||
// CacheFileIOManager doesn't have mCacheDirectory, switch to
|
||||
// memory-only mode.
|
||||
NS_WARNING("Forcing memory-only entry since CacheFileIOManager doesn't "
|
||||
@ -504,22 +521,20 @@ CacheFile::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
this));
|
||||
|
||||
mMemoryOnly = true;
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mKey);
|
||||
mMetadata = new CacheFileMetadata(mOpenAsMemoryOnly, mPinned, mKey);
|
||||
mReady = true;
|
||||
mDataSize = mMetadata->Offset();
|
||||
|
||||
isNew = true;
|
||||
retval = NS_OK;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// CacheFileIOManager::OpenFile() failed for another reason.
|
||||
isNew = false;
|
||||
retval = aResult;
|
||||
}
|
||||
|
||||
mListener.swap(listener);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mHandle = aHandle;
|
||||
if (NS_FAILED(mStatus)) {
|
||||
CacheFileIOManager::DoomFile(mHandle, nullptr);
|
||||
@ -583,6 +598,7 @@ CacheFile::OnMetadataRead(nsresult aResult)
|
||||
|
||||
bool isNew = false;
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
mPinned = mMetadata->Pinned();
|
||||
mReady = true;
|
||||
mDataSize = mMetadata->Offset();
|
||||
if (mDataSize == 0 && mMetadata->ElementsSize() == 0) {
|
||||
@ -1970,7 +1986,8 @@ CacheFile::InitIndexEntry()
|
||||
rv = CacheFileIOManager::InitIndexEntry(mHandle,
|
||||
mMetadata->OriginAttributes().mAppId,
|
||||
mMetadata->IsAnonymous(),
|
||||
mMetadata->OriginAttributes().mInBrowser);
|
||||
mMetadata->OriginAttributes().mInBrowser,
|
||||
mPinned);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t expTime;
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
bool aMemoryOnly,
|
||||
bool aSkipSizeCheck,
|
||||
bool aPriority,
|
||||
bool aPinned,
|
||||
CacheFileListener *aCallback);
|
||||
|
||||
NS_IMETHOD OnChunkRead(nsresult aResult, CacheFileChunk *aChunk) override;
|
||||
@ -103,6 +104,7 @@ public:
|
||||
bool DataSize(int64_t* aSize);
|
||||
void Key(nsACString& aKey) { aKey = mKey; }
|
||||
bool IsDoomed();
|
||||
bool IsPinned() const { return mPinned; }
|
||||
bool IsWriteInProgress();
|
||||
|
||||
// Memory reporting
|
||||
@ -196,6 +198,7 @@ private:
|
||||
bool mMemoryOnly;
|
||||
bool mSkipSizeCheck;
|
||||
bool mOpenAsMemoryOnly;
|
||||
bool mPinned;
|
||||
bool mPriority;
|
||||
bool mDataAccessed;
|
||||
bool mDataIsDirty;
|
||||
@ -206,8 +209,8 @@ private:
|
||||
int64_t mDataSize;
|
||||
nsCString mKey;
|
||||
|
||||
RefPtr<CacheFileHandle> mHandle;
|
||||
RefPtr<CacheFileMetadata> mMetadata;
|
||||
RefPtr<CacheFileHandle> mHandle;
|
||||
RefPtr<CacheFileMetadata> mMetadata;
|
||||
nsCOMPtr<CacheFileListener> mListener;
|
||||
nsCOMPtr<CacheFileIOListener> mDoomAfterOpenListener;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
|
||||
protected:
|
||||
nsCOMPtr<CacheFileChunkListener> mCallback;
|
||||
RefPtr<CacheFileChunk> mChunk;
|
||||
RefPtr<CacheFileChunk> mChunk;
|
||||
};
|
||||
|
||||
bool
|
||||
|
@ -150,7 +150,7 @@ private:
|
||||
uint32_t mRWBufSize;
|
||||
CacheHash::Hash16_t mReadHash;
|
||||
|
||||
RefPtr<CacheFile> mFile; // is null if chunk is cached to
|
||||
RefPtr<CacheFile> mFile; // is null if chunk is cached to
|
||||
// prevent reference cycles
|
||||
nsCOMPtr<CacheFileChunkListener> mListener;
|
||||
nsTArray<ChunkListenerItem *> mUpdateListeners;
|
||||
|
@ -81,32 +81,49 @@ CacheFileContextEvictor::ContextsCount()
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo)
|
||||
CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo,
|
||||
bool aPinned)
|
||||
{
|
||||
LOG(("CacheFileContextEvictor::AddContext() [this=%p, loadContextInfo=%p]",
|
||||
this, aLoadContextInfo));
|
||||
LOG(("CacheFileContextEvictor::AddContext() [this=%p, loadContextInfo=%p, pinned=%d]",
|
||||
this, aLoadContextInfo, aPinned));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
|
||||
|
||||
CacheFileContextEvictorEntry *entry = nullptr;
|
||||
for (uint32_t i = 0; i < mEntries.Length(); ++i) {
|
||||
if (mEntries[i]->mInfo->Equals(aLoadContextInfo)) {
|
||||
entry = mEntries[i];
|
||||
break;
|
||||
if (aLoadContextInfo) {
|
||||
for (uint32_t i = 0; i < mEntries.Length(); ++i) {
|
||||
if (mEntries[i]->mInfo &&
|
||||
mEntries[i]->mInfo->Equals(aLoadContextInfo) &&
|
||||
mEntries[i]->mPinned == aPinned) {
|
||||
entry = mEntries[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not providing load context info means we want to delete everything,
|
||||
// so let's not bother with any currently running context cleanups
|
||||
// for the same pinning state.
|
||||
for (uint32_t i = mEntries.Length(); i > 0;) {
|
||||
--i;
|
||||
if (mEntries[i]->mInfo && mEntries[i]->mPinned == aPinned) {
|
||||
RemoveEvictInfoFromDisk(mEntries[i]->mInfo, mEntries[i]->mPinned);
|
||||
mEntries.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
entry = new CacheFileContextEvictorEntry();
|
||||
entry->mInfo = aLoadContextInfo;
|
||||
entry->mPinned = aPinned;
|
||||
mEntries.AppendElement(entry);
|
||||
}
|
||||
|
||||
entry->mTimeStamp = PR_Now() / PR_USEC_PER_MSEC;
|
||||
|
||||
PersistEvictionInfoToDisk(aLoadContextInfo);
|
||||
PersistEvictionInfoToDisk(aLoadContextInfo, aPinned);
|
||||
|
||||
if (mIndexIsUpToDate) {
|
||||
// Already existing context could be added again, in this case the iterator
|
||||
@ -180,58 +197,62 @@ CacheFileContextEvictor::CacheIndexStateChanged()
|
||||
|
||||
nsresult
|
||||
CacheFileContextEvictor::WasEvicted(const nsACString &aKey, nsIFile *aFile,
|
||||
bool *_retval)
|
||||
bool *aEvictedAsPinned, bool *aEvictedAsNonPinned)
|
||||
{
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() [key=%s]",
|
||||
PromiseFlatCString(aKey).get()));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
*aEvictedAsPinned = false;
|
||||
*aEvictedAsNonPinned = false;
|
||||
|
||||
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
|
||||
|
||||
nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(aKey);
|
||||
MOZ_ASSERT(info);
|
||||
if (!info) {
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() - Cannot parse key!"));
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CacheFileContextEvictorEntry *entry = nullptr;
|
||||
for (uint32_t i = 0; i < mEntries.Length(); ++i) {
|
||||
if (info->Equals(mEntries[i]->mInfo)) {
|
||||
entry = mEntries[i];
|
||||
break;
|
||||
CacheFileContextEvictorEntry *entry = mEntries[i];
|
||||
|
||||
if (entry->mInfo && !info->Equals(entry->mInfo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PRTime lastModifiedTime;
|
||||
rv = aFile->GetLastModifiedTime(&lastModifiedTime);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() - Cannot get last modified time"
|
||||
", returning false."));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (lastModifiedTime > entry->mTimeStamp) {
|
||||
// File has been modified since context eviction.
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() - evicted [pinning=%d, "
|
||||
"mTimeStamp=%lld, lastModifiedTime=%lld]",
|
||||
entry->mPinned, entry->mTimeStamp, lastModifiedTime));
|
||||
|
||||
if (entry->mPinned) {
|
||||
*aEvictedAsPinned = true;
|
||||
} else {
|
||||
*aEvictedAsNonPinned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() - Didn't find equal context, "
|
||||
"returning false."));
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRTime lastModifiedTime;
|
||||
rv = aFile->GetLastModifiedTime(&lastModifiedTime);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() - Cannot get last modified time"
|
||||
", returning false."));
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*_retval = !(lastModifiedTime > entry->mTimeStamp);
|
||||
LOG(("CacheFileContextEvictor::WasEvicted() - returning %s. [mTimeStamp=%lld,"
|
||||
" lastModifiedTime=%lld]", *_retval ? "true" : "false",
|
||||
mEntries[0]->mTimeStamp, lastModifiedTime));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheFileContextEvictor::PersistEvictionInfoToDisk(
|
||||
nsILoadContextInfo *aLoadContextInfo)
|
||||
nsILoadContextInfo *aLoadContextInfo, bool aPinned)
|
||||
{
|
||||
LOG(("CacheFileContextEvictor::PersistEvictionInfoToDisk() [this=%p, "
|
||||
"loadContextInfo=%p]", this, aLoadContextInfo));
|
||||
@ -241,7 +262,7 @@ CacheFileContextEvictor::PersistEvictionInfoToDisk(
|
||||
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = GetContextFile(aLoadContextInfo, getter_AddRefs(file));
|
||||
rv = GetContextFile(aLoadContextInfo, aPinned, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -268,7 +289,7 @@ CacheFileContextEvictor::PersistEvictionInfoToDisk(
|
||||
|
||||
nsresult
|
||||
CacheFileContextEvictor::RemoveEvictInfoFromDisk(
|
||||
nsILoadContextInfo *aLoadContextInfo)
|
||||
nsILoadContextInfo *aLoadContextInfo, bool aPinned)
|
||||
{
|
||||
LOG(("CacheFileContextEvictor::RemoveEvictInfoFromDisk() [this=%p, "
|
||||
"loadContextInfo=%p]", this, aLoadContextInfo));
|
||||
@ -278,7 +299,7 @@ CacheFileContextEvictor::RemoveEvictInfoFromDisk(
|
||||
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = GetContextFile(aLoadContextInfo, getter_AddRefs(file));
|
||||
rv = GetContextFile(aLoadContextInfo, aPinned, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -363,16 +384,26 @@ CacheFileContextEvictor::LoadEvictInfoFromDisk()
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(decoded);
|
||||
|
||||
if (!info) {
|
||||
LOG(("CacheFileContextEvictor::LoadEvictInfoFromDisk() - Cannot parse "
|
||||
"context key, removing file. [contextKey=%s, file=%s]",
|
||||
decoded.get(), leaf.get()));
|
||||
file->Remove(false);
|
||||
continue;
|
||||
bool pinned = decoded[0] == '\t';
|
||||
if (pinned) {
|
||||
decoded = Substring(decoded, 1);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadContextInfo> info;
|
||||
if (!NS_LITERAL_CSTRING("*").Equals(decoded)) {
|
||||
// "*" is indication of 'delete all', info left null will pass
|
||||
// to CacheFileContextEvictor::AddContext and clear all the cache data.
|
||||
info = CacheFileUtils::ParseKey(decoded);
|
||||
if (!info) {
|
||||
LOG(("CacheFileContextEvictor::LoadEvictInfoFromDisk() - Cannot parse "
|
||||
"context key, removing file. [contextKey=%s, file=%s]",
|
||||
decoded.get(), leaf.get()));
|
||||
file->Remove(false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PRTime lastModifiedTime;
|
||||
rv = file->GetLastModifiedTime(&lastModifiedTime);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -381,6 +412,7 @@ CacheFileContextEvictor::LoadEvictInfoFromDisk()
|
||||
|
||||
CacheFileContextEvictorEntry *entry = new CacheFileContextEvictorEntry();
|
||||
entry->mInfo = info;
|
||||
entry->mPinned = pinned;
|
||||
entry->mTimeStamp = lastModifiedTime;
|
||||
mEntries.AppendElement(entry);
|
||||
}
|
||||
@ -390,6 +422,7 @@ CacheFileContextEvictor::LoadEvictInfoFromDisk()
|
||||
|
||||
nsresult
|
||||
CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo,
|
||||
bool aPinned,
|
||||
nsIFile **_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
@ -398,7 +431,16 @@ CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo,
|
||||
leafName.AssignLiteral(CONTEXT_EVICTION_PREFIX);
|
||||
|
||||
nsAutoCString keyPrefix;
|
||||
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, keyPrefix);
|
||||
if (aPinned) {
|
||||
// Mark pinned context files with a tab char at the start.
|
||||
// Tab is chosen because it can never be used as a context key tag.
|
||||
keyPrefix.Append('\t');
|
||||
}
|
||||
if (aLoadContextInfo) {
|
||||
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, keyPrefix);
|
||||
} else {
|
||||
keyPrefix.Append('*');
|
||||
}
|
||||
|
||||
nsAutoCString data64;
|
||||
rv = Base64Encode(keyPrefix, data64);
|
||||
@ -530,7 +572,7 @@ CacheFileContextEvictor::EvictEntries()
|
||||
LOG(("CacheFileContextEvictor::EvictEntries() - No more entries left in "
|
||||
"iterator. [iterator=%p, info=%p]", mEntries[0]->mIterator.get(),
|
||||
mEntries[0]->mInfo.get()));
|
||||
RemoveEvictInfoFromDisk(mEntries[0]->mInfo);
|
||||
RemoveEvictInfoFromDisk(mEntries[0]->mInfo, mEntries[0]->mPinned);
|
||||
mEntries.RemoveElementAt(0);
|
||||
continue;
|
||||
} else if (NS_FAILED(rv)) {
|
||||
@ -557,6 +599,20 @@ CacheFileContextEvictor::EvictEntries()
|
||||
continue;
|
||||
}
|
||||
|
||||
CacheIndex::EntryStatus status;
|
||||
bool pinned;
|
||||
rv = CacheIndex::HasEntry(hash, &status, &pinned);
|
||||
// This must never fail, since eviction (this code) happens only when the index
|
||||
// is up-to-date and thus the informatin is known.
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
if (pinned != mEntries[0]->mPinned) {
|
||||
LOG(("CacheFileContextEvictor::EvictEntries() - Skipping entry since pinning "
|
||||
"doesn't match [evicting pinned=%d, entry pinned=%d]",
|
||||
mEntries[0]->mPinned, pinned));
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoCString leafName;
|
||||
CacheFileIOManager::HashToStr(&hash, leafName);
|
||||
|
||||
|
@ -20,6 +20,7 @@ class CacheIndexIterator;
|
||||
struct CacheFileContextEvictorEntry
|
||||
{
|
||||
nsCOMPtr<nsILoadContextInfo> mInfo;
|
||||
bool mPinned;
|
||||
PRTime mTimeStamp; // in milliseconds
|
||||
RefPtr<CacheIndexIterator> mIterator;
|
||||
};
|
||||
@ -40,7 +41,7 @@ public:
|
||||
// Returns number of contexts that are being evicted.
|
||||
uint32_t ContextsCount();
|
||||
// Start evicting given context.
|
||||
nsresult AddContext(nsILoadContextInfo *aLoadContextInfo);
|
||||
nsresult AddContext(nsILoadContextInfo *aLoadContextInfo, bool aPinned);
|
||||
// CacheFileIOManager calls this method when CacheIndex's state changes. We
|
||||
// check whether the index is up to date and start or stop evicting according
|
||||
// to index's state.
|
||||
@ -50,21 +51,22 @@ public:
|
||||
// info to the given key and the last modified time of the entry file is
|
||||
// earlier than the time stamp of the time when the context was added to the
|
||||
// evictor.
|
||||
nsresult WasEvicted(const nsACString &aKey, nsIFile *aFile, bool *_retval);
|
||||
nsresult WasEvicted(const nsACString &aKey, nsIFile *aFile,
|
||||
bool *aEvictedAsPinned, bool *aEvictedAsNonPinned);
|
||||
|
||||
private:
|
||||
// Writes information about eviction of the given context to the disk. This is
|
||||
// done for every context added to the evictor to be able to recover eviction
|
||||
// after a shutdown or crash. When the context file is found after startup, we
|
||||
// restore mTimeStamp from the last modified time of the file.
|
||||
nsresult PersistEvictionInfoToDisk(nsILoadContextInfo *aLoadContextInfo);
|
||||
nsresult PersistEvictionInfoToDisk(nsILoadContextInfo *aLoadContextInfo, bool aPinned);
|
||||
// Once we are done with eviction for the given context, the eviction info is
|
||||
// removed from the disk.
|
||||
nsresult RemoveEvictInfoFromDisk(nsILoadContextInfo *aLoadContextInfo);
|
||||
nsresult RemoveEvictInfoFromDisk(nsILoadContextInfo *aLoadContextInfo, bool aPinned);
|
||||
// Tries to load all contexts from the disk. This method is called just once
|
||||
// after startup.
|
||||
nsresult LoadEvictInfoFromDisk();
|
||||
nsresult GetContextFile(nsILoadContextInfo *aLoadContextInfo,
|
||||
nsresult GetContextFile(nsILoadContextInfo *aLoadContextInfo, bool aPinned,
|
||||
nsIFile **_retval);
|
||||
|
||||
void CreateIterators();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user