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

--HG--
extra : commitid : JfOXHrexxbp
This commit is contained in:
Wes Kocher 2015-10-29 17:18:38 -07:00
commit def31b952c
153 changed files with 2987 additions and 957 deletions

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)
:
;;
*)

View File

@ -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;

View File

@ -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");

View File

@ -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,

View File

@ -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"
}

View File

@ -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

View 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>

View File

@ -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 */

View File

@ -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");

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -1600,7 +1600,8 @@ MediaDecoderOwner*
MediaDecoder::GetOwner()
{
MOZ_ASSERT(NS_IsMainThread());
return mOwner;
// mOwner is valid until shutdown.
return !mShuttingDown ? mOwner : nullptr;
}
void

View File

@ -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:

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */
/**

View File

@ -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());
}

View File

@ -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]

View File

@ -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>

View File

@ -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'
];
/**

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -50,6 +50,10 @@ dictionary MediaTrackConstraintSet {
long long browserWindow;
boolean scrollWithPage;
ConstrainDOMString deviceId;
ConstrainLong viewportOffsetX;
ConstrainLong viewportOffsetY;
ConstrainLong viewportWidth;
ConstrainLong viewportHeight;
};
dictionary MediaTrackConstraints : MediaTrackConstraintSet {

View File

@ -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;
};

View File

@ -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,
};

View File

@ -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()

View File

@ -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, &params);
} 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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -6,7 +6,7 @@
//
// These should not run with --no-asmjs.
if (!isAsmJSCompilationAvailable())
if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
quit(0);
//////////////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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.

View File

@ -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)
{

View File

@ -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);

View File

@ -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.

View File

@ -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();

View File

@ -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

View 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);
}

View 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 */

View File

@ -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,

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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();

View File

@ -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
};

View File

@ -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',

View File

@ -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 */

View File

@ -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()

View File

@ -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,

View File

@ -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() &&

View File

@ -430,7 +430,7 @@ public:
NS_DECL_QUERYFRAME_TARGET(nsIFrame)
nsPresContext* PresContext() const {
return StyleContext()->RuleNode()->PresContext();
return StyleContext()->PresContext();
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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']

View File

@ -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));

View File

@ -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

View File

@ -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:
*/

View File

@ -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;
};
/**

View File

@ -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);

View File

@ -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).

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -44,7 +44,7 @@ public:
protected:
nsCOMPtr<CacheFileChunkListener> mCallback;
RefPtr<CacheFileChunk> mChunk;
RefPtr<CacheFileChunk> mChunk;
};
bool

View File

@ -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;

View File

@ -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);

View File

@ -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