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

This commit is contained in:
Wes Kocher 2015-07-02 17:31:11 -07:00
commit f44218465a
73 changed files with 1320 additions and 746 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "722028715a56a03f327e2e70f2c32dcb6d819d4c",
"git_revision": "50b6104ed03f87f1207695f861ba475bd79aaf71",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "547f049d7e7510b628b5b1074f73b204ab6627df",
"revision": "7f044c57386bfd12a5c2d52bcfccde76e11d6b68",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="50b6104ed03f87f1207695f861ba475bd79aaf71"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -18,8 +18,6 @@ import mozinfo
__all__ = [
"dumpLeakLog",
"processLeakLog",
'systemMemory',
'environment',
'dumpScreen',
"setAutomationLog",
]
@ -282,136 +280,6 @@ def processLeakLog(leakLogFile, options):
processSingleLeakFile(thisFile, processType, leakThreshold,
processType in ignoreMissingLeaks)
def systemMemory():
"""
Returns total system memory in kilobytes.
Works only on unix-like platforms where `free` is in the path.
"""
return int(os.popen("free").readlines()[1].split()[1])
def environment(xrePath, env=None, crashreporter=True, debugger=False, dmdPath=None, lsanPath=None):
"""populate OS environment variables for mochitest"""
env = os.environ.copy() if env is None else env
assert os.path.isabs(xrePath)
if mozinfo.isMac:
ldLibraryPath = os.path.join(os.path.dirname(xrePath), "MacOS")
else:
ldLibraryPath = xrePath
envVar = None
dmdLibrary = None
preloadEnvVar = None
if 'toolkit' in mozinfo.info and mozinfo.info['toolkit'] == "gonk":
# Skip all of this, it's only valid for the host.
pass
elif mozinfo.isUnix:
envVar = "LD_LIBRARY_PATH"
env['MOZILLA_FIVE_HOME'] = xrePath
dmdLibrary = "libdmd.so"
preloadEnvVar = "LD_PRELOAD"
elif mozinfo.isMac:
envVar = "DYLD_LIBRARY_PATH"
dmdLibrary = "libdmd.dylib"
preloadEnvVar = "DYLD_INSERT_LIBRARIES"
elif mozinfo.isWin:
envVar = "PATH"
dmdLibrary = "dmd.dll"
preloadEnvVar = "MOZ_REPLACE_MALLOC_LIB"
if envVar:
envValue = ((env.get(envVar), str(ldLibraryPath))
if mozinfo.isWin
else (ldLibraryPath, dmdPath, env.get(envVar)))
env[envVar] = os.path.pathsep.join([path for path in envValue if path])
if dmdPath and dmdLibrary and preloadEnvVar:
env[preloadEnvVar] = os.path.join(dmdPath, dmdLibrary)
# crashreporter
env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
if crashreporter and not debugger:
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
env['MOZ_CRASHREPORTER'] = '1'
else:
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
# Crash on non-local network connections by default.
# MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily
# enable non-local connections for the purposes of local testing. Don't
# override the user's choice here. See bug 1049688.
env.setdefault('MOZ_DISABLE_NONLOCAL_CONNECTIONS', '1')
# Set WebRTC logging in case it is not set yet
env.setdefault('NSPR_LOG_MODULES', 'signaling:3,mtransport:4,datachannel:4,jsep:4,MediaPipelineFactory:4')
env.setdefault('R_LOG_LEVEL', '6')
env.setdefault('R_LOG_DESTINATION', 'stderr')
env.setdefault('R_LOG_VERBOSE', '1')
# ASan specific environment stuff
asan = bool(mozinfo.info.get("asan"))
if asan and (mozinfo.isLinux or mozinfo.isMac):
try:
# Symbolizer support
llvmsym = os.path.join(xrePath, "llvm-symbolizer")
if os.path.isfile(llvmsym):
env["ASAN_SYMBOLIZER_PATH"] = llvmsym
log.info("INFO | runtests.py | ASan using symbolizer at %s" % llvmsym)
else:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Failed to find ASan symbolizer at %s" % llvmsym)
totalMemory = systemMemory()
# Only 4 GB RAM or less available? Use custom ASan options to reduce
# the amount of resources required to do the tests. Standard options
# will otherwise lead to OOM conditions on the current test slaves.
message = "INFO | runtests.py | ASan running in %s configuration"
asanOptions = []
if totalMemory <= 1024 * 1024 * 4:
message = message % 'low-memory'
asanOptions = ['quarantine_size=50331648', 'malloc_context_size=5']
else:
message = message % 'default memory'
if lsanPath:
log.info("LSan enabled.")
asanOptions.append('detect_leaks=1')
lsanOptions = ["exitcode=0"]
suppressionsFile = os.path.join(lsanPath, 'lsan_suppressions.txt')
if os.path.exists(suppressionsFile):
log.info("LSan using suppression file " + suppressionsFile)
lsanOptions.append("suppressions=" + suppressionsFile)
else:
log.info("WARNING | runtests.py | LSan suppressions file does not exist! " + suppressionsFile)
env["LSAN_OPTIONS"] = ':'.join(lsanOptions)
# Run shutdown GCs and CCs to avoid spurious leaks.
env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1'
if len(asanOptions):
env['ASAN_OPTIONS'] = ':'.join(asanOptions)
except OSError,err:
log.info("Failed determine available memory, disabling ASan low-memory configuration: %s" % err.strerror)
except:
log.info("Failed determine available memory, disabling ASan low-memory configuration")
else:
log.info(message)
tsan = bool(mozinfo.info.get("tsan"))
if tsan and mozinfo.isLinux:
# Symbolizer support.
llvmsym = os.path.join(xrePath, "llvm-symbolizer")
if os.path.isfile(llvmsym):
env["TSAN_OPTIONS"] = "external_symbolizer_path=%s" % llvmsym
log.info("INFO | runtests.py | TSan using symbolizer at %s" % llvmsym)
else:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Failed to find TSan symbolizer at %s" % llvmsym)
return env
def dumpScreen(utilityPath):
"""dumps a screenshot of the entire screen to a directory specified by
the MOZ_UPLOAD_DIR environment variable"""

View File

@ -46,6 +46,7 @@
#include "mozilla/EventStates.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Preferences.h"
#ifdef LoadImage
// Undefine LoadImage to prevent naming conflict with Windows.
@ -930,15 +931,27 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
}
// get document wide referrer policy
mozilla::net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", false);
// if referrer attributes are enabled in preferences, load img referrer attribute
nsresult rv;
if (referrerAttributeEnabled) {
mozilla::net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
// if the image does not provide a referrer attribute, ignore this
if (imgReferrerPolicy != mozilla::net::RP_Unset) {
referrerPolicy = imgReferrerPolicy;
}
}
// Not blocked. Do the load.
nsRefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
nsresult rv;
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
aDocument->NodePrincipal(),
aDocument->GetDocumentURI(),
aDocument->GetReferrerPolicy(),
referrerPolicy,
this, loadFlags,
content->LocalName(),
getter_AddRefs(req),
@ -1566,3 +1579,11 @@ nsImageLoadingContent::ImageObserver::~ImageObserver()
MOZ_COUNT_DTOR(ImageObserver);
NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);
}
// Only HTMLInputElement.h overrides this for <img> tags
// all other subclasses use this one, i.e. ignore referrer attributes
mozilla::net::ReferrerPolicy
nsImageLoadingContent::GetImageReferrerPolicy()
{
return mozilla::net::RP_Unset;
};

View File

@ -24,6 +24,7 @@
#include "nsAutoPtr.h"
#include "nsIContentPolicy.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/net/ReferrerPolicy.h"
class nsIURI;
class nsIDocument;
@ -198,6 +199,8 @@ protected:
*/
virtual mozilla::CORSMode GetCORSMode();
virtual mozilla::net::ReferrerPolicy GetImageReferrerPolicy();
// Subclasses are *required* to call BindToTree/UnbindFromTree.
void BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent, bool aCompileEventHandlers);

View File

@ -0,0 +1,212 @@
var BASE_URL = 'example.com/tests/dom/base/test/img_referrer_testserver.sjs';
function createTestUrl(aPolicy, aAction, aName) {
return 'http://' + BASE_URL + '?' +
'action=' + aAction + '&' +
'policy=' + aPolicy + '&' +
'name=' + aName;
}
function createTestPage(aHead, aImgPolicy, aName) {
var _createTestUrl = createTestUrl.bind(null, aImgPolicy, 'test', aName);
return '<!DOCTYPE HTML>\n\
<html>'+
aHead +
'<body>\n\
<img src="' + _createTestUrl('img') + '" referrer="' + aImgPolicy + '" id="image"></img>\n\
<script>' +
// LOAD EVENT (of the test)
// fires when the img resource for the page is loaded
'window.addEventListener("load", function() {\n\
parent.postMessage("childLoadComplete", "http://mochi.test:8888");\n\
}.bind(window), false);' +
'</script>\n\
</body>\n\
</html>';
}
// Creates the following test cases for the specified referrer
// policy combination:
// <img> with referrer
function createTest(aPolicy, aImgPolicy, aName) {
var headString = '<head>';
if (aPolicy) {
headString += '<meta name="referrer" content="' + aPolicy + '">';
}
headString += '<script></script>';
return createTestPage(headString, aImgPolicy, aName);
}
// testing regular load img with referrer policy
// speculative parser should not kick in here
function createTest2(aImgPolicy, name) {
return createTestPage('', aImgPolicy, name);
}
function createTest3(aImgPolicy1, aImgPolicy2, aImgPolicy3, aName) {
return '<!DOCTYPE HTML>\n\
<html>\n\
<body>\n\
<img src="' + createTestUrl(aImgPolicy1, 'test', aName + aImgPolicy1) + '" referrer="' + aImgPolicy1 + '" id="image"></img>\n\
<img src="' + createTestUrl(aImgPolicy2, 'test', aName + aImgPolicy2) + '" referrer="' + aImgPolicy2 + '" id="image"></img>\n\
<img src="' + createTestUrl(aImgPolicy3, 'test', aName + aImgPolicy3) + '" referrer="' + aImgPolicy3 + '" id="image"></img>\n\
<script>\n\
var _numLoads = 0;' +
// LOAD EVENT (of the test)
// fires when the img resource for the page is loaded
'window.addEventListener("load", function() {\n\
parent.postMessage("childLoadComplete", "http://mochi.test:8888");\n\
}.bind(window), false);' +
'</script>\n\
</body>\n\
</html>';
}
function createTestPage2(aHead, aPolicy, aName) {
return '<!DOCTYPE HTML>\n\
<html>'+
aHead +
'<body>\n\
<img src="' + createTestUrl(aPolicy, "test", aName) + '" id="image"></img>\n\
<script>' +
// LOAD EVENT (of the test)
// fires when the img resource for the page is loaded
'window.addEventListener("load", function() {\n\
parent.postMessage("childLoadComplete", "http://mochi.test:8888");\n\
}.bind(window), false);' +
'</script>\n\
</body>\n\
</html>';
}
function createTest4(aPolicy, aName) {
var headString = '<head>';
headString += '<meta name="referrer" content="' + aPolicy + '">';
headString += '<script></script>';
return createTestPage2(headString, aPolicy, aName);
}
function createTest5(aPolicy, aName) {
var headString = '<head>';
headString += '<meta name="referrer" content="' + aPolicy + '">';
return createTestPage2(headString, aPolicy, aName);
}
function handleRequest(request, response) {
var sharedKey = 'img_referrer_testserver.sjs';
var params = request.queryString.split('&');
var action = params[0].split('=')[1];
response.setHeader('Cache-Control', 'no-cache', false);
response.setHeader('Content-Type', 'text/html; charset=utf-8', false);
if (action === 'resetState') {
var state = getSharedState(sharedKey);
state = {};
setSharedState(sharedKey, JSON.stringify(state));
response.write("");
return;
}
if (action === 'test') {
// ?action=test&policy=origin&name=name
var policy = params[1].split('=')[1];
var name = params[2].split('=')[1];
var result = getSharedState(sharedKey);
if (result === '') {
result = {};
} else {
result = JSON.parse(result);
}
if (!result["tests"]) {
result["tests"] = {};
}
var referrerLevel = "none";
var test = {}
if (request.hasHeader('Referer')) {
let referrer = request.getHeader('Referer');
if (referrer.indexOf("img_referrer_testserver") > 0) {
referrerLevel = "full";
} else if (referrer == "http://mochi.test:8888") {
referrerLevel = "origin";
}
test.referrer = request.getHeader('Referer');
} else {
test.referrer = '';
}
test.policy = referrerLevel;
test.expected = policy;
result["tests"][name] = test;
setSharedState(sharedKey, JSON.stringify(result));
return;
}
if (action === 'get-test-results') {
// ?action=get-result
response.write(getSharedState(sharedKey));
return;
}
if (action === 'generate-img-policy-test') {
// ?action=generate-img-policy-test&imgPolicy=b64-encoded-string&name=name&policy=b64-encoded-string
var imgPolicy = unescape(params[1].split('=')[1]);
var name = unescape(params[2].split('=')[1]);
var metaPolicy = '';
if (params[3]) {
metaPolicy = params[3].split('=')[1];
}
response.write(createTest(metaPolicy, imgPolicy, name));
return;
}
if (action === 'generate-img-policy-test2') {
// ?action=generate-img-policy-test2&imgPolicy=b64-encoded-string&name=name
var imgPolicy = unescape(params[1].split('=')[1]);
var name = unescape(params[2].split('=')[1]);
response.write(createTest2(imgPolicy, name));
return;
}
if (action === 'generate-img-policy-test3') {
// ?action=generate-img-policy-test3&imgPolicy1=b64-encoded-string&imgPolicy2=b64-encoded-string&imgPolicy3=b64-encoded-string&name=name
var imgPolicy1 = unescape(params[1].split('=')[1]);
var imgPolicy2 = unescape(params[2].split('=')[1]);
var imgPolicy3 = unescape(params[3].split('=')[1]);
var name = unescape(params[4].split('=')[1]);
response.write(createTest3(imgPolicy1, imgPolicy2, imgPolicy3, name));
return;
}
if (action === 'generate-img-policy-test4') {
// ?action=generate-img-policy-test4&imgPolicy=b64-encoded-string&name=name
var policy = unescape(params[1].split('=')[1]);
var name = unescape(params[2].split('=')[1]);
response.write(createTest4(policy, name));
return;
}
if (action === 'generate-img-policy-test5') {
// ?action=generate-img-policy-test5&policy=b64-encoded-string&name=name
var policy = unescape(params[1].split('=')[1]);
var name = unescape(params[2].split('=')[1]);
response.write(createTest5(policy, name));
return;
}
response.write("I don't know action "+action);
return;
}

View File

@ -236,6 +236,7 @@ support-files =
file_nonascii_blob_url.html
referrerHelper.js
test_performance_user_timing.js
img_referrer_testserver.sjs
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@ -661,6 +662,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
support-files = referrerHelper.js
[test_bug1165501.html]
support-files = referrerHelper.js
[test_img_referrer.html]
[test_caretPositionFromPoint.html]
[test_classList.html]
# This test fails on the Mac for some reason

View File

@ -0,0 +1,171 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test img policy attribute for Bug 1166910</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<!--
Testing that img referrer attribute is honoured correctly
* Speculative parser loads (generate-img-policy-test)
* regular loads (generate-img-policy-test2)
* loading a single image multiple times with different policies (generate-img-policy-test3)
* testing setAttribute and .referrer (generate-setAttribute-test)
* regression tests that meta referrer is still working even if attribute referrers are enabled
https://bugzilla.mozilla.org/show_bug.cgi?id=1166910
-->
<script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
var advance = function() { tests.next(); };
var mTestResult;
/**
* Listen for notifications from the child.
* These are sent in case of error, or when the loads we await have completed.
*/
window.addEventListener("message", function(event) {
if (event.data == "childLoadComplete") {
// all loads happen, continue the test.
advance();
}
else if (event.data.contains("childLoadComplete")) {
mTestResult = event.data.split(",")[1];
advance();
}
});
/**
* helper to perform an XHR.
*/
function doXHR(aUrl, onSuccess, onFail) {
var xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.onload = function () {
onSuccess(xhr);
};
xhr.onerror = function () {
onFail(xhr);
};
xhr.open('GET', aUrl, true);
xhr.send(null);
}
/**
* Grabs the results via XHR and passes to checker.
*/
function checkIndividualResults(aTestname, aExpectedImg, aName) {
doXHR('/tests/dom/base/test/img_referrer_testserver.sjs?action=get-test-results',
function(xhr) {
var results = xhr.response;
info(JSON.stringify(xhr.response));
if (aName === 'setAttribute') {
is(mTestResult, aExpectedImg, aTestname + ' --- ' + mTestResult);
} else {
for (i in aName) {
ok(aName[i] in results.tests, aName[i] + " tests have to be performed.");
is(results.tests[aName[i]].policy, aExpectedImg[i], aTestname + ' --- ' + results.tests[aName[i]].policy + ' (' + results.tests[aName[i]].referrer + ')');
}
}
advance();
},
function(xhr) {
ok(false, "Can't get results from the counter server.");
SimpleTest.finish();
});
}
function resetState() {
doXHR('/tests/dom/base/test/img_referrer_testserver.sjs?action=resetState',
advance,
function(xhr) {
ok(false, "error in reset state");
SimpleTest.finish();
});
}
/**
* testing if img referrer attribute is honoured (1165501)
*/
var tests = (function() {
// enable referrer attribute
yield SpecialPowers.pushPrefEnv({"set": [['network.http.enablePerElementReferrer', true]]}, advance);
var iframe = document.getElementById("testframe");
var sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test";
// setting img unsafe-url and meta origin - unsafe-url shall prevail (should use speculative load)
yield resetState();
var name = 'unsaf-url-with-meta-in-origin';
yield iframe.src = sjs + "&imgPolicy=" + escape('unsafe-url') + "&name=" + name + "&policy=" + escape('origin');
yield checkIndividualResults("unsafe-url (img) with origin in meta", ["full"], [name]);
// setting img no-referrer and meta default - no-referrer shall prevail (should use speculative load)
yield resetState();
name = 'no-referrer-with-meta-in-origin';
yield iframe.src = sjs + "&imgPolicy=" + escape('no-referrer')+ "&name=" + name + "&policy=" + escape('origin');
yield checkIndividualResults("no-referrer (img) with default in meta", ["none"], [name]);
// test referrer policy in regular load
yield resetState();
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test2";
name = 'regular-load-unsafe-url';
yield iframe.src = sjs + "&imgPolicy=" + escape('unsafe-url') + "&name=" + name;
yield checkIndividualResults("unsafe-url in img", ["full"], [name]);
// test referrer policy in regular load with multiple images
var policies = ['unsafe-url', 'origin', 'no-referrer'];
var expected = ["full", "origin", "none"];
yield resetState();
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test3";
name = 'multiple-images-'+policies[0]+'-'+policies[1]+'-'+policies[2];
yield iframe.src = sjs + "&imgPolicy1=" + escape(policies[0]) + "&imgPolicy2=" + escape(policies[1]) + "&imgPolicy3=" + escape(policies[2]) + "&name=" + name;
yield checkIndividualResults(policies[0]+", "+policies[1]+" and "+policies[2]+" in img", expected, [name+policies[0], name+policies[1], name+policies[2]]);
policies = ['origin', 'no-referrer', 'unsafe-url'];
expected = ["origin", "none", "full"];
yield resetState();
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test3";
name = 'multiple-images-'+policies[0]+'-'+policies[1]+'-'+policies[2];
yield iframe.src = sjs + "&imgPolicy1=" + escape(policies[0]) + "&imgPolicy2=" + escape(policies[1]) + "&imgPolicy3=" + escape(policies[2]) + "&name=" + name;
yield checkIndividualResults(policies[0]+", "+policies[1]+" and "+policies[2]+" in img", expected, [name+policies[0], name+policies[1], name+policies[2]]);
policies = ['no-referrer', 'origin', 'unsafe-url'];
expected = ["none", "origin", "full"];
yield resetState();
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test3";
name = 'multiple-images-'+policies[0]+'-'+policies[1]+'-'+policies[2];
yield iframe.src = sjs + "&imgPolicy1=" + escape(policies[0]) + "&imgPolicy2=" + escape(policies[1]) + "&imgPolicy3=" + escape(policies[2]) + "&name=" + name;
yield checkIndividualResults(policies[0]+", "+policies[1]+" and "+policies[2]+" in img", expected, [name+policies[0], name+policies[1], name+policies[2]]);
// regression tests that meta referrer is still working even if attribute referrers are enabled
yield resetState();
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test4";
name = 'regular-load-no-referrer-meta';
yield iframe.src = sjs + "&policy=" + escape('no-referrer') + "&name=" + name;
yield checkIndividualResults("no-referrer in meta (no img referrer policy), speculative load", ["none"], [name]);
yield resetState();
sjs = "/tests/dom/base/test/img_referrer_testserver.sjs?action=generate-img-policy-test5";
name = 'regular-load-no-referrer-meta';
yield iframe.src = sjs + "&policy=" + escape('no-referrer') + "&name=" + name;
yield checkIndividualResults("no-referrer in meta (no img referrer policy), regular load", ["none"], [name]);
// complete. Be sure to yield so we don't call this twice.
yield SimpleTest.finish();
})();
</script>
</head>
<body onload="tests.next();">
<iframe id="testframe"></iframe>
</body>
</html>

View File

@ -204,9 +204,23 @@ CacheStorage::CreateOnWorker(Namespace aNamespace, nsIGlobalObject* aGlobal,
const PrincipalInfo& principalInfo = aWorkerPrivate->GetPrincipalInfo();
// We have a number of cases where we want to skip the https scheme
// validation:
//
// 1) Any worker when dom.caches.testing.enabled pref is true.
// 2) Any worker when dom.serviceWorkers.testing.enabled pref is true. This
// is mainly because most sites using SWs will expect Cache to work if
// SWs are enabled.
// 3) If the window that created this worker has the devtools SW testing
// option enabled. Same reasoning as (2).
// 4) If the worker itself is a ServiceWorker, then we always skip the
// origin checks. The ServiceWorker has its own trusted origin checks
// that are better than ours. In addition, we don't have information
// about the window any more, so we can't do our own checks.
bool testingEnabled = aWorkerPrivate->DOMCachesTestingEnabled() ||
aWorkerPrivate->ServiceWorkersTestingEnabled() ||
aWorkerPrivate->ServiceWorkersTestingInWindow();
aWorkerPrivate->ServiceWorkersTestingInWindow() ||
aWorkerPrivate->IsServiceWorker();
if (!IsTrusted(principalInfo, testingEnabled)) {
NS_WARNING("CacheStorage not supported on untrusted origins.");

View File

@ -1823,9 +1823,6 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
GLenum format, GLenum type,
mozilla::dom::Element& elt)
{
if (type == LOCAL_GL_HALF_FLOAT_OES)
type = LOCAL_GL_HALF_FLOAT;
if (!ValidateTexImageFormatAndType(format, type,
WebGLTexImageFunc::TexImage,
WebGLTexDimensions::Tex2D))

View File

@ -1078,6 +1078,10 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type,
WebGLTexImageFunc func,
WebGLTexDimensions dims)
{
if (type == LOCAL_GL_HALF_FLOAT_OES) {
type = LOCAL_GL_HALF_FLOAT;
}
if (IsCompressedFunc(func) || IsCopyFunc(func)) {
MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
return true;

View File

@ -3708,18 +3708,8 @@ EventStateManager::IsHandlingUserInput()
}
TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
TimeDuration elapsed = TimeStamp::Now() - sHandlingInputStart;
bool inTime = timeout <= TimeDuration(0) || elapsed <= timeout;
if (!inTime) {
#ifdef DEBUG
printf("EventStateManager::IsHandlingUserInput() has timed out "
"(timeout: %f, elapsed: %f)\n",
timeout.ToMilliseconds(), elapsed.ToMilliseconds());
#endif
return false;
}
return true;
return timeout <= TimeDuration(0) ||
(TimeStamp::Now() - sHandlingInputStart) <= timeout;
}
static void

View File

@ -189,6 +189,20 @@ public:
{
SetHTMLAttr(nsGkAtoms::border, aBorder, aError);
}
void SetReferrer(const nsAString& aReferrer, ErrorResult& aError)
{
SetHTMLAttr(nsGkAtoms::referrer, aReferrer, aError);
}
void GetReferrer(nsAString& aReferrer)
{
GetEnumAttr(nsGkAtoms::referrer, nullptr, aReferrer);
}
mozilla::net::ReferrerPolicy
GetImageReferrerPolicy()
{
return GetReferrerPolicy();
}
int32_t X();
int32_t Y();

View File

@ -106,6 +106,8 @@
#include "mozilla/dom/HTMLBodyElement.h"
#include "imgIContainer.h"
#include "mozilla/net/ReferrerPolicy.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -995,6 +997,10 @@ nsGenericHTMLElement::ParseAttribute(int32_t aNamespaceID,
return aResult.ParseIntValue(aValue);
}
if (aAttribute == nsGkAtoms::referrer) {
return ParseReferrerAttribute(aValue, aResult);
}
if (aAttribute == nsGkAtoms::name) {
// Store name as an atom. name="" means that the element has no name,
// not that it has an emptystring as the name.
@ -1262,6 +1268,19 @@ nsGenericHTMLElement::ParseImageAttribute(nsIAtom* aAttribute,
return false;
}
bool
nsGenericHTMLElement::ParseReferrerAttribute(const nsAString& aString,
nsAttrValue& aResult)
{
static const nsAttrValue::EnumTable kReferrerTable[] = {
{ "no-referrer", net::RP_No_Referrer },
{ "origin", net::RP_Origin },
{ "unsafe-url", net::RP_Unsafe_URL },
{ 0 }
};
return aResult.ParseEnumValue(aString, kReferrerTable, false);
}
bool
nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
nsAttrValue& aResult)

View File

@ -233,6 +233,17 @@ public:
mScrollgrab = aValue;
}
mozilla::net::ReferrerPolicy
GetReferrerPolicy()
{
nsAutoString aPolicyString;
GetEnumAttr(nsGkAtoms::referrer, nullptr, aPolicyString);
if (aPolicyString.IsEmpty()) {
return mozilla::net::RP_Unset;
}
return mozilla::net::ReferrerPolicyFromString(aPolicyString);
}
/**
* Determine whether an attribute is an event (onclick, etc.)
* @param aName the attribute
@ -711,6 +722,10 @@ public:
static bool ParseImageAttribute(nsIAtom* aAttribute,
const nsAString& aString,
nsAttrValue& aResult);
static bool ParseReferrerAttribute(const nsAString& aString,
nsAttrValue& aResult);
/**
* Convert a frameborder string to value (yes/no/1/0)
*

View File

@ -54,6 +54,10 @@ public:
// Returns true if the decoder is shut down.
virtual bool IsShutdown() const = 0;
// A special version of the above for the ogg decoder that is allowed to be
// called cross-thread.
virtual bool IsOggDecoderShutdown() { return false; }
virtual bool OnStateMachineTaskQueue() const = 0;
virtual bool OnDecodeTaskQueue() const = 0;

View File

@ -335,6 +335,8 @@ bool MediaDecoder::IsInfinite()
MediaDecoder::MediaDecoder() :
mWatchManager(this, AbstractThread::MainThread()),
mBuffered(AbstractThread::MainThread(), TimeIntervals(), "MediaDecoder::mBuffered (Mirror)"),
mStateMachineIsShutdown(AbstractThread::MainThread(), true,
"MediaDecoder::mStateMachineIsShutdown (Mirror)"),
mNextFrameStatus(AbstractThread::MainThread(),
MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
"MediaDecoder::mNextFrameStatus (Mirror)"),
@ -393,6 +395,9 @@ MediaDecoder::MediaDecoder() :
// mDuration
mWatchManager.Watch(mStateMachineDuration, &MediaDecoder::DurationChanged);
// mStateMachineIsShutdown
mWatchManager.Watch(mStateMachineIsShutdown, &MediaDecoder::ShutdownBitChanged);
// readyState
mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateReadyState);
mWatchManager.Watch(mNextFrameStatus, &MediaDecoder::UpdateReadyState);
@ -851,7 +856,7 @@ double MediaDecoder::ComputePlaybackRate(bool* aReliable)
int64_t length = mResource ? mResource->GetLength() : -1;
if (!IsNaN(mDuration) && !mozilla::IsInfinite<double>(mDuration) && length >= 0) {
*aReliable = true;
return length * mDuration;
return length / mDuration;
}
return mPlaybackStatistics->GetRateAtLastStop(aReliable);
}
@ -1254,11 +1259,13 @@ MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
if (mDecoderStateMachine) {
mStateMachineDuration.Connect(mDecoderStateMachine->CanonicalDuration());
mBuffered.Connect(mDecoderStateMachine->CanonicalBuffered());
mStateMachineIsShutdown.Connect(mDecoderStateMachine->CanonicalIsShutdown());
mNextFrameStatus.Connect(mDecoderStateMachine->CanonicalNextFrameStatus());
mCurrentPosition.Connect(mDecoderStateMachine->CanonicalCurrentPosition());
} else {
mStateMachineDuration.DisconnectIfConnected();
mBuffered.DisconnectIfConnected();
mStateMachineIsShutdown.DisconnectIfConnected();
mNextFrameStatus.DisconnectIfConnected();
mCurrentPosition.DisconnectIfConnected();
}
@ -1336,8 +1343,9 @@ MediaDecoder::NotifyWaitingForResourcesStatusChanged()
}
bool MediaDecoder::IsShutdown() const {
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(GetStateMachine(), true);
return GetStateMachine()->IsShutdown();
return mStateMachineIsShutdown;
}
// Drop reference to state machine. Only called during shutdown dance.

View File

@ -895,6 +895,12 @@ protected:
// Buffered range, mirrored from the reader.
Mirror<media::TimeIntervals> mBuffered;
// Whether the state machine is shut down.
Mirror<bool> mStateMachineIsShutdown;
// Used by the ogg decoder to watch mStateMachineIsShutdown.
virtual void ShutdownBitChanged() {}
// NextFrameStatus, mirrored from the state machine.
Mirror<MediaDecoderOwner::NextFrameStatus> mNextFrameStatus;

View File

@ -76,7 +76,6 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder,
, mThrottleDuration(TimeDuration::FromMilliseconds(500))
, mLastThrottledNotify(TimeStamp::Now() - mThrottleDuration)
, mIgnoreAudioOutputFormat(false)
, mStartTime(-1)
, mHitAudioDecodeError(false)
, mShutdown(false)
, mTaskQueueIsBorrowed(!!aBorrowedTaskQueue)
@ -148,24 +147,33 @@ nsresult MediaDecoderReader::ResetDecode()
return NS_OK;
}
VideoData* MediaDecoderReader::DecodeToFirstVideoData()
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MediaDecoderReader::DecodeToFirstVideoData()
{
bool eof = false;
while (!eof && VideoQueue().GetSize() == 0) {
{
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
return nullptr;
}
MOZ_ASSERT(OnTaskQueue());
typedef MediaDecoderReader::VideoDataPromise PromiseType;
nsRefPtr<PromiseType::Private> p = new PromiseType::Private(__func__);
nsRefPtr<MediaDecoderReader> self = this;
InvokeUntil([self] () -> bool {
MOZ_ASSERT(self->OnTaskQueue());
NS_ENSURE_TRUE(!self->mShutdown, false);
bool skip = false;
if (!self->DecodeVideoFrame(skip, 0)) {
self->VideoQueue().Finish();
return !!self->VideoQueue().PeekFront();
}
bool keyframeSkip = false;
eof = !DecodeVideoFrame(keyframeSkip, 0);
}
if (eof) {
VideoQueue().Finish();
}
VideoData* d = nullptr;
return (d = VideoQueue().PeekFront()) ? d : nullptr;
return true;
}, [self] () -> bool {
MOZ_ASSERT(self->OnTaskQueue());
return self->VideoQueue().GetSize();
})->Then(TaskQueue(), __func__, [self, p] () {
p->Resolve(self->VideoQueue().PeekFront(), __func__);
}, [p] () {
// We don't have a way to differentiate EOS, error, and shutdown here. :-(
p->Reject(END_OF_STREAM, __func__);
});
return p.forget();
}
void
@ -228,7 +236,7 @@ media::TimeIntervals
MediaDecoderReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
AutoPinned<MediaResource> stream(mDecoder->GetResource());
if (!mDuration.Ref().isSome()) {

View File

@ -288,8 +288,7 @@ public:
return mDecoder;
}
// TODO: DEPRECATED. This uses synchronous decoding.
VideoData* DecodeToFirstVideoData();
nsRefPtr<VideoDataPromise> DecodeToFirstVideoData();
MediaInfo GetMediaInfo() { return mInfo; }
@ -304,8 +303,8 @@ public:
NS_NewRunnableFunction([self, aStartTime] () -> void
{
MOZ_ASSERT(self->OnTaskQueue());
MOZ_ASSERT(self->mStartTime == -1);
self->mStartTime = aStartTime;
MOZ_ASSERT(!self->HaveStartTime());
self->mStartTime.emplace(aStartTime);
self->UpdateBuffered();
});
TaskQueue()->Dispatch(r.forget());
@ -407,7 +406,9 @@ protected:
// readers to return the correct value of GetBuffered. We should refactor
// things such that all GetBuffered calls go through the MDSM, which would
// offset the range accordingly.
int64_t mStartTime;
Maybe<int64_t> mStartTime;
bool HaveStartTime() { MOZ_ASSERT(OnTaskQueue()); return mStartTime.isSome(); }
int64_t StartTime() { MOZ_ASSERT(HaveStartTime()); return mStartTime.ref(); }
// This is a quick-and-dirty way for DecodeAudioData implementations to
// communicate the presence of a decoding error to RequestAudioData. We should

View File

@ -200,6 +200,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
"MediaDecoderStateMachine::mNextPlayState (Mirror)"),
mLogicallySeeking(mTaskQueue, false,
"MediaDecoderStateMachine::mLogicallySeeking (Mirror)"),
mIsShutdown(mTaskQueue, false,
"MediaDecoderStateMachine::mIsShutdown (Canonical)"),
mNextFrameStatus(mTaskQueue, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
"MediaDecoderStateMachine::mNextFrameStatus (Canonical)"),
mFragmentEndTime(-1),
@ -1377,6 +1379,8 @@ void MediaDecoderStateMachine::SetState(State aState)
mState = aState;
mIsShutdown = mState == DECODER_STATE_ERROR || mState == DECODER_STATE_SHUTDOWN;
// Clear state-scoped state.
mSentPlaybackEndedEvent = false;
}
@ -2466,6 +2470,7 @@ MediaDecoderStateMachine::FinishShutdown()
mLogicalPlaybackRate.DisconnectIfConnected();
mPreservesPitch.DisconnectIfConnected();
mDuration.DisconnectAll();
mIsShutdown.DisconnectAll();
mNextFrameStatus.DisconnectAll();
mCurrentPosition.DisconnectAll();
@ -3269,8 +3274,8 @@ void MediaDecoderStateMachine::PreservesPitchChanged()
bool MediaDecoderStateMachine::IsShutdown()
{
return mState == DECODER_STATE_ERROR ||
mState == DECODER_STATE_SHUTDOWN;
MOZ_ASSERT(OnTaskQueue());
return mIsShutdown;
}
void MediaDecoderStateMachine::QueueMetadata(int64_t aPublishTime,

View File

@ -982,6 +982,12 @@ protected:
mNextPlayState == MediaDecoder::PLAY_STATE_PLAYING;
}
// Whether we're currently in or transitioning to shutdown state.
Canonical<bool> mIsShutdown;
public:
AbstractCanonical<bool>* CanonicalIsShutdown() { return &mIsShutdown; }
protected:
// The status of our next frame. Mirrored on the main thread and used to
// compute ready state.
Canonical<NextFrameStatus> mNextFrameStatus;

View File

@ -1404,8 +1404,8 @@ MediaFormatReader::GetBuffered()
int64_t startTime;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals());
startTime = mStartTime;
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
startTime = StartTime();
}
// Ensure we have up to date buffered time range.
if (HasVideo()) {

View File

@ -701,6 +701,9 @@ public:
}
};
// A generic promise type that does the trick for simple use cases.
typedef MediaPromise<bool, nsresult, /* IsExclusive = */ false> GenericPromise;
/*
* Class to encapsulate a promise for a particular role. Use this as the member
* variable for a class whose method returns a promise.

View File

@ -13,6 +13,7 @@
#include "nsIThread.h"
#include "nsSize.h"
#include "nsRect.h"
#include "MediaPromise.h"
#if !(defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)) || \
defined(MOZ_ASAN)
@ -281,6 +282,34 @@ CreateMediaDecodeTaskQueue();
already_AddRefed<FlushableMediaTaskQueue>
CreateFlushableMediaDecodeTaskQueue();
// Iteratively invokes aWork until aCondition returns true, or aWork returns false.
// Use this rather than a while loop to avoid bogarting the task queue.
template<class Work, class Condition>
nsRefPtr<GenericPromise> InvokeUntil(Work aWork, Condition aCondition) {
nsRefPtr<GenericPromise::Private> p = new GenericPromise::Private(__func__);
if (aCondition()) {
p->Resolve(true, __func__);
}
struct Helper {
static void Iteration(nsRefPtr<GenericPromise::Private> aPromise, Work aWork, Condition aCondition) {
if (!aWork()) {
aPromise->Reject(NS_ERROR_FAILURE, __func__);
} else if (aCondition()) {
aPromise->Resolve(true, __func__);
} else {
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction([aPromise, aWork, aCondition] () { Iteration(aPromise, aWork, aCondition); });
AbstractThread::GetCurrent()->Dispatch(r.forget());
}
}
};
Helper::Iteration(p, aWork, aCondition);
return p.forget();
}
} // end namespace mozilla
#endif

View File

@ -116,6 +116,8 @@ nsresult AndroidMediaReader::ResetDecode()
if (mLastVideoFrame) {
mLastVideoFrame = nullptr;
}
mSeekRequest.DisconnectIfExists();
mSeekPromise.RejectIfExists(NS_OK, __func__);
return MediaDecoderReader::ResetDecode();
}
@ -323,6 +325,7 @@ AndroidMediaReader::Seek(int64_t aTarget, int64_t aEndTime)
{
MOZ_ASSERT(OnTaskQueue());
nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
if (mHasAudio && mHasVideo) {
// The decoder seeks/demuxes audio and video streams separately. So if
// we seek both audio and video to aTarget, the audio stream can typically
@ -333,13 +336,23 @@ AndroidMediaReader::Seek(int64_t aTarget, int64_t aEndTime)
// seek the audio stream to match the video stream's time. Otherwise, the
// audio and video streams won't be in sync after the seek.
mVideoSeekTimeUs = aTarget;
const VideoData* v = DecodeToFirstVideoData();
mAudioSeekTimeUs = v ? v->mTime : aTarget;
nsRefPtr<AndroidMediaReader> self = this;
mSeekRequest.Begin(DecodeToFirstVideoData()->Then(TaskQueue(), __func__, [self] (VideoData* v) {
self->mSeekRequest.Complete();
self->mAudioSeekTimeUs = v->mTime;
self->mSeekPromise.Resolve(self->mAudioSeekTimeUs, __func__);
}, [self, aTarget] () {
self->mSeekRequest.Complete();
self->mAudioSeekTimeUs = aTarget;
self->mSeekPromise.Resolve(aTarget, __func__);
}));
} else {
mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget;
mSeekPromise.Resolve(aTarget, __func__);
}
return SeekPromise::CreateAndResolve(mAudioSeekTimeUs, __func__);
return p;
}
AndroidMediaReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer) :

View File

@ -36,6 +36,8 @@ class AndroidMediaReader : public MediaDecoderReader
int64_t mVideoSeekTimeUs;
int64_t mAudioSeekTimeUs;
nsRefPtr<VideoData> mLastVideoFrame;
MediaPromiseHolder<MediaDecoderReader::SeekPromise> mSeekPromise;
MediaPromiseRequestHolder<MediaDecoderReader::VideoDataPromise> mSeekRequest;
public:
AndroidMediaReader(AbstractMediaDecoder* aDecoder,
const nsACString& aContentType);

View File

@ -1079,7 +1079,7 @@ MP4Reader::GetBuffered()
return buffered;
}
UpdateIndex();
NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
AutoPinned<MediaResource> resource(mDecoder->GetResource());
nsTArray<MediaByteRange> ranges;
@ -1090,8 +1090,8 @@ MP4Reader::GetBuffered()
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
for (size_t i = 0; i < timeRanges.Length(); i++) {
buffered += media::TimeInterval(
media::TimeUnit::FromMicroseconds(timeRanges[i].start - mStartTime),
media::TimeUnit::FromMicroseconds(timeRanges[i].end - mStartTime));
media::TimeUnit::FromMicroseconds(timeRanges[i].start - StartTime()),
media::TimeUnit::FromMicroseconds(timeRanges[i].end - StartTime()));
}
}

View File

@ -722,7 +722,8 @@ CreateReaderForType(const nsACString& aType, AbstractMediaDecoder* aDecoder,
already_AddRefed<SourceBufferDecoder>
MediaSourceReader::CreateSubDecoder(const nsACString& aType, int64_t aTimestampOffset)
{
if (IsShutdown()) {
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder->IsShutdown()) {
return nullptr;
}
@ -837,13 +838,9 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aIgnored /* Used only for ogg whi
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
MOZ_DIAGNOSTIC_ASSERT(mAudioPromise.IsEmpty());
MOZ_DIAGNOSTIC_ASSERT(mVideoPromise.IsEmpty());
MOZ_ASSERT(!mShutdown);
nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
if (IsShutdown()) {
mSeekPromise.Reject(NS_ERROR_FAILURE, __func__);
return p;
}
// Store pending seek target in case the track buffers don't contain
// the desired time and we delay doing the seek.
mOriginalSeekTime = aTime;

View File

@ -124,12 +124,6 @@ public:
virtual void BreakCycles() override;
bool IsShutdown()
{
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
return mDecoder->IsShutdown();
}
// Return true if all of the active tracks contain data for the specified time.
bool TrackBuffersContainTime(int64_t aTime);

View File

@ -13,6 +13,11 @@ namespace mozilla {
class OggDecoder : public MediaDecoder
{
public:
OggDecoder()
: mShutdownBitMonitor("mShutdownBitMonitor")
, mShutdownBit(false)
{}
virtual MediaDecoder* Clone() {
if (!IsOggEnabled()) {
return nullptr;
@ -20,6 +25,26 @@ public:
return new OggDecoder();
}
virtual MediaDecoderStateMachine* CreateStateMachine();
// For yucky legacy reasons, the ogg decoder needs to do a cross-thread read
// to check for shutdown while it hogs its own task queue. We don't want to
// protect the general state with a lock, so we make a special copy and a
// special-purpose lock. This method may be called on any thread.
bool IsOggDecoderShutdown() override
{
MonitorAutoLock lock(mShutdownBitMonitor);
return mShutdownBit;
}
protected:
void ShutdownBitChanged() override
{
MonitorAutoLock lock(mShutdownBitMonitor);
mShutdownBit = mStateMachineIsShutdown;
}
Monitor mShutdownBitMonitor;
bool mShutdownBit;
};
} // namespace mozilla

View File

@ -474,7 +474,7 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
MediaResource* resource = mDecoder->GetResource();
if (mInfo.mMetadataDuration.isNothing() && !mDecoder->IsShutdown() &&
if (mInfo.mMetadataDuration.isNothing() && !mDecoder->IsOggDecoderShutdown() &&
resource->GetLength() >= 0 && mDecoder->IsMediaSeekable())
{
// We didn't get a duration from the index or a Content-Duration header.
@ -1358,11 +1358,8 @@ nsresult OggReader::SeekInBufferedRange(int64_t aTarget,
do {
bool skip = false;
eof = !DecodeVideoFrame(skip, 0);
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
return NS_ERROR_FAILURE;
}
if (mDecoder->IsOggDecoderShutdown()) {
return NS_ERROR_FAILURE;
}
} while (!eof &&
mVideoQueue.GetSize() == 0);
@ -1439,6 +1436,7 @@ OggReader::Seek(int64_t aTarget, int64_t aEndTime)
nsresult OggReader::SeekInternal(int64_t aTarget, int64_t aEndTime)
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(HaveStartTime(), NS_ERROR_FAILURE);
if (mIsChained)
return NS_ERROR_FAILURE;
LOG(LogLevel::Debug, ("%p About to seek to %lld", mDecoder, aTarget));
@ -1447,10 +1445,10 @@ nsresult OggReader::SeekInternal(int64_t aTarget, int64_t aEndTime)
NS_ENSURE_TRUE(resource != nullptr, NS_ERROR_FAILURE);
int64_t adjustedTarget = aTarget;
if (HasAudio() && mOpusState){
adjustedTarget = std::max(mStartTime, aTarget - SEEK_OPUS_PREROLL);
adjustedTarget = std::max(StartTime(), aTarget - SEEK_OPUS_PREROLL);
}
if (adjustedTarget == mStartTime) {
if (adjustedTarget == StartTime()) {
// We've seeked to the media start. Just seek to the offset of the first
// content page.
res = resource->Seek(nsISeekableStream::NS_SEEK_SET, 0);
@ -1473,18 +1471,18 @@ nsresult OggReader::SeekInternal(int64_t aTarget, int64_t aEndTime)
NS_ENSURE_SUCCESS(res,res);
// Figure out if the seek target lies in a buffered range.
SeekRange r = SelectSeekRange(ranges, aTarget, mStartTime, aEndTime, true);
SeekRange r = SelectSeekRange(ranges, aTarget, StartTime(), aEndTime, true);
if (!r.IsNull()) {
// We know the buffered range in which the seek target lies, do a
// bisection search in that buffered range.
res = SeekInBufferedRange(aTarget, adjustedTarget, mStartTime, aEndTime, ranges, r);
res = SeekInBufferedRange(aTarget, adjustedTarget, StartTime(), aEndTime, ranges, r);
NS_ENSURE_SUCCESS(res,res);
} else {
// The target doesn't lie in a buffered range. Perform a bisection
// search over the whole media, using the known buffered ranges to
// reduce the search space.
res = SeekInUnbuffered(aTarget, mStartTime, aEndTime, ranges);
res = SeekInUnbuffered(aTarget, StartTime(), aEndTime, ranges);
NS_ENSURE_SUCCESS(res,res);
}
}
@ -1509,8 +1507,7 @@ nsresult OggReader::SeekInternal(int64_t aTarget, int64_t aEndTime)
// forwards until we find a keyframe.
bool skip = true;
while (DecodeVideoFrame(skip, 0) && skip) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
if (mDecoder->IsOggDecoderShutdown()) {
return NS_ERROR_FAILURE;
}
}
@ -1853,7 +1850,7 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
media::TimeIntervals OggReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
{
mozilla::ReentrantMonitorAutoEnter mon(mMonitor);
if (mIsChained) {
@ -1892,7 +1889,7 @@ media::TimeIntervals OggReader::GetBuffered()
// we special-case (startOffset == 0) so that the first
// buffered range always appears to be buffered from the media start
// time, rather than from the end-time of the first page.
int64_t startTime = (startOffset == 0) ? mStartTime : -1;
int64_t startTime = (startOffset == 0) ? StartTime() : -1;
// Find the start time of the range. Read pages until we find one with a
// granulepos which we can convert into a timestamp to use as the time of
@ -1959,8 +1956,8 @@ media::TimeIntervals OggReader::GetBuffered()
int64_t endTime = RangeEndTime(startOffset, endOffset, true);
if (endTime > startTime) {
buffered += media::TimeInterval(
media::TimeUnit::FromMicroseconds(startTime - mStartTime),
media::TimeUnit::FromMicroseconds(endTime - mStartTime));
media::TimeUnit::FromMicroseconds(startTime - StartTime()),
media::TimeUnit::FromMicroseconds(endTime - StartTime()));
}
}
}
@ -1980,14 +1977,14 @@ VideoData* OggReader::FindStartTime(int64_t& aOutStartTime)
VideoData* videoData = nullptr;
if (HasVideo()) {
videoData = DecodeToFirstVideoData();
videoData = SyncDecodeToFirstVideoData();
if (videoData) {
videoStartTime = videoData->mTime;
LOG(LogLevel::Debug, ("OggReader::FindStartTime() video=%lld", videoStartTime));
}
}
if (HasAudio()) {
AudioData* audioData = DecodeToFirstAudioData();
AudioData* audioData = SyncDecodeToFirstAudioData();
if (audioData) {
audioStartTime = audioData->mTime;
LOG(LogLevel::Debug, ("OggReader::FindStartTime() audio=%lld", audioStartTime));
@ -2002,15 +1999,12 @@ VideoData* OggReader::FindStartTime(int64_t& aOutStartTime)
return videoData;
}
AudioData* OggReader::DecodeToFirstAudioData()
AudioData* OggReader::SyncDecodeToFirstAudioData()
{
bool eof = false;
while (!eof && AudioQueue().GetSize() == 0) {
{
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
return nullptr;
}
if (mDecoder->IsOggDecoderShutdown()) {
return nullptr;
}
eof = !DecodeAudioData();
}
@ -2021,6 +2015,23 @@ AudioData* OggReader::DecodeToFirstAudioData()
return (d = AudioQueue().PeekFront()) ? d : nullptr;
}
VideoData* OggReader::SyncDecodeToFirstVideoData()
{
bool eof = false;
while (!eof && VideoQueue().GetSize() == 0) {
if (mDecoder->IsOggDecoderShutdown()) {
return nullptr;
}
bool keyframeSkip = false;
eof = !DecodeVideoFrame(keyframeSkip, 0);
}
if (eof) {
VideoQueue().Finish();
}
VideoData* d = nullptr;
return (d = VideoQueue().PeekFront()) ? d : nullptr;
}
OggCodecStore::OggCodecStore()
: mMonitor("CodecStore")
{

View File

@ -17,6 +17,7 @@
#include "OggCodecState.h"
#include "VideoUtils.h"
#include "mozilla/Monitor.h"
#include "OggDecoder.h"
namespace mozilla {
@ -81,7 +82,8 @@ private:
// we started playback at the current position. Returns the first video
// frame, if we have video.
VideoData* FindStartTime(int64_t& aOutStartTime);
AudioData* DecodeToFirstAudioData();
AudioData* SyncDecodeToFirstAudioData();
VideoData* SyncDecodeToFirstVideoData();
// This monitor should be taken when reading or writing to mIsChained.
ReentrantMonitor mMonitor;

View File

@ -527,6 +527,7 @@ MediaOmxReader::Seek(int64_t aTarget, int64_t aEndTime)
{
MOZ_ASSERT(OnTaskQueue());
EnsureActive();
nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
if (container && container->GetImageContainer()) {
@ -543,13 +544,23 @@ MediaOmxReader::Seek(int64_t aTarget, int64_t aEndTime)
// seek the audio stream to match the video stream's time. Otherwise, the
// audio and video streams won't be in sync after the seek.
mVideoSeekTimeUs = aTarget;
const VideoData* v = DecodeToFirstVideoData();
mAudioSeekTimeUs = v ? v->mTime : aTarget;
nsRefPtr<MediaOmxReader> self = this;
mSeekRequest.Begin(DecodeToFirstVideoData()->Then(TaskQueue(), __func__, [self] (VideoData* v) {
self->mSeekRequest.Complete();
self->mAudioSeekTimeUs = v->mTime;
self->mSeekPromise.Resolve(self->mAudioSeekTimeUs, __func__);
}, [self, aTarget] () {
self->mSeekRequest.Complete();
self->mAudioSeekTimeUs = aTarget;
self->mSeekPromise.Resolve(aTarget, __func__);
}));
} else {
mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget;
mSeekPromise.Resolve(aTarget, __func__);
}
return SeekPromise::CreateAndResolve(mAudioSeekTimeUs, __func__);
return p;
}
void MediaOmxReader::SetIdle() {

View File

@ -46,6 +46,9 @@ class MediaOmxReader : public MediaOmxCommonReader
bool mIsShutdown;
MediaPromiseHolder<MediaDecoderReader::MetadataPromise> mMetadataPromise;
MediaPromiseRequestHolder<MediaResourcePromise> mMediaResourceRequest;
MediaPromiseHolder<MediaDecoderReader::SeekPromise> mSeekPromise;
MediaPromiseRequestHolder<MediaDecoderReader::VideoDataPromise> mSeekRequest;
protected:
android::sp<android::OmxDecoder> mOmxDecoder;
android::sp<android::MediaExtractor> mExtractor;
@ -73,6 +76,13 @@ protected:
virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
public:
virtual nsresult ResetDecode()
{
mSeekRequest.DisconnectIfExists();
mSeekPromise.RejectIfExists(NS_OK, __func__);
return MediaDecoderReader::ResetDecode();
}
virtual bool DecodeAudioData();
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold);

View File

@ -230,16 +230,6 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip,
nsRefPtr<MediaDecoderReader::SeekPromise>
RawReader::Seek(int64_t aTime, int64_t aEndTime)
{
nsresult res = SeekInternal(aTime);
if (NS_FAILED(res)) {
return SeekPromise::CreateAndReject(res, __func__);
} else {
return SeekPromise::CreateAndResolve(aTime, __func__);
}
}
nsresult RawReader::SeekInternal(int64_t aTime)
{
MOZ_ASSERT(OnTaskQueue());
@ -248,39 +238,40 @@ nsresult RawReader::SeekInternal(int64_t aTime)
uint32_t frame = mCurrentFrame;
if (aTime >= UINT_MAX)
return NS_ERROR_FAILURE;
return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
mCurrentFrame = aTime * mFrameRate / USECS_PER_S;
CheckedUint32 offset = CheckedUint32(mCurrentFrame) * mFrameSize;
offset += sizeof(RawVideoHeader);
NS_ENSURE_TRUE(offset.isValid(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(offset.isValid(), SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__));
nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, offset.value());
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, SeekPromise::CreateAndReject(rv, __func__));
mVideoQueue.Reset();
while(mVideoQueue.GetSize() == 0) {
bool keyframeSkip = false;
if (!DecodeVideoFrame(keyframeSkip, 0)) {
mCurrentFrame = frame;
return NS_ERROR_FAILURE;
nsRefPtr<SeekPromise::Private> p = new SeekPromise::Private(__func__);
nsRefPtr<RawReader> self = this;
InvokeUntil([self] () {
MOZ_ASSERT(self->OnTaskQueue());
NS_ENSURE_TRUE(!self->mShutdown, false);
bool skip = false;
return self->DecodeVideoFrame(skip, 0);
}, [self, aTime] () {
MOZ_ASSERT(self->OnTaskQueue());
return self->mVideoQueue.Peek() &&
self->mVideoQueue.Peek()->GetEndTime() >= aTime;
})->Then(TaskQueue(), __func__, [self, p, aTime] () {
while (self->mVideoQueue.GetSize() >= 2) {
nsRefPtr<VideoData> releaseMe = self->mVideoQueue.PopFront();
}
p->Resolve(aTime, __func__);
}, [self, p, frame] {
self->mCurrentFrame = frame;
self->mVideoQueue.Reset();
p->Reject(NS_ERROR_FAILURE, __func__);
});
{
ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor());
if (mDecoder->IsShutdown()) {
mCurrentFrame = frame;
return NS_ERROR_FAILURE;
}
}
if (mVideoQueue.PeekFront() && mVideoQueue.PeekFront()->GetEndTime() < aTime) {
nsRefPtr<VideoData> releaseMe = mVideoQueue.PopFront();
}
}
return NS_OK;
return p.forget();
}
media::TimeIntervals RawReader::GetBuffered()

View File

@ -49,8 +49,6 @@ public:
private:
bool ReadFromResource(MediaResource *aResource, uint8_t *aBuf, uint32_t aLength);
nsresult SeekInternal(int64_t aTime);
RawVideoHeader mMetadata;
uint32_t mCurrentFrame;
double mFrameRate;

View File

@ -735,6 +735,7 @@ WebMReader::Seek(int64_t aTarget, int64_t aEndTime)
nsresult WebMReader::SeekInternal(int64_t aTarget)
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(HaveStartTime(), NS_ERROR_FAILURE);
if (mVideoDecoder) {
nsresult rv = mVideoDecoder->Flush();
NS_ENSURE_SUCCESS(rv, rv);
@ -749,7 +750,7 @@ nsresult WebMReader::SeekInternal(int64_t aTarget)
uint64_t target = aTarget * NS_PER_USEC;
if (mSeekPreroll) {
target = std::max(uint64_t(mStartTime * NS_PER_USEC),
target = std::max(uint64_t(StartTime() * NS_PER_USEC),
target - mSeekPreroll);
}
int r = nestegg_track_seek(mContext, trackToSeek, target);
@ -777,7 +778,7 @@ nsresult WebMReader::SeekInternal(int64_t aTarget)
media::TimeIntervals WebMReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
AutoPinned<MediaResource> resource(mDecoder->GetResource());
media::TimeIntervals buffered;
@ -804,7 +805,7 @@ media::TimeIntervals WebMReader::GetBuffered()
ranges[index].mEnd,
&start, &end);
if (rv) {
int64_t startOffset = mStartTime * NS_PER_USEC;
int64_t startOffset = StartTime() * NS_PER_USEC;
NS_ASSERTION(startOffset >= 0 && uint64_t(startOffset) <= start,
"startOffset negative or larger than start time");
if (!(startOffset >= 0 && uint64_t(startOffset) <= start)) {

View File

@ -30,6 +30,8 @@ interface HTMLImageElement : HTMLElement {
[SetterThrows]
attribute DOMString useMap;
[SetterThrows]
attribute DOMString referrer;
[SetterThrows]
attribute boolean isMap;
[SetterThrows]
attribute unsigned long width;

View File

@ -11,11 +11,6 @@
const Ci = Components.interfaces;
var mainWindow;
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
prefBranch.setIntPref("browser.startup.page", 0);
prefBranch.setCharPref("browser.startup.homepage_override.mstone", "ignore");
var contentPage = "http://mochi.test:8888/chrome/dom/workers/test/empty.html";
function testOnWindow(aIsPrivate, aCallback) {
@ -59,7 +54,7 @@ function doTests() {
testOnWindow(true, function(aWin) {
wP = aWin;
ok(!("serviceWorker" in wP.content.navigator), "ServiceWorkers are not available for private windows");
SimpleTest.finish();
runTest();
});
});
}
@ -74,9 +69,6 @@ function runTest() {
wN.close();
wP.close();
prefBranch.clearUserPref("browser.startup.page")
prefBranch.clearUserPref("browser.startup.homepage_override.mstone");
SimpleTest.finish();
return;
}
@ -86,7 +78,11 @@ function runTest() {
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.serviceWorkers.enabled", true]]}, runTest);
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.enabled", true],
["browser.startup.page", 0],
["browser.startup.homepage_override.mstone", "ignore"],
]}, runTest);
</script>
</body>

View File

@ -11,11 +11,6 @@
const Ci = Components.interfaces;
var mainWindow;
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
prefBranch.setIntPref("browser.startup.page", 0);
prefBranch.setCharPref("browser.startup.homepage_override.mstone", "ignore");
var contentPage = "http://mochi.test:8888/chrome/dom/workers/test/empty.html";
function testOnWindow(aIsPrivate, aCallback) {
@ -69,7 +64,7 @@ function doTests() {
var sharedWorker3 = new wP.content.SharedWorker('sharedWorker_privateBrowsing.js');
sharedWorker3.port.onmessage = function(event) {
is(event.data, 2, "Only 2 sharedworker expected in the private window");
SimpleTest.finish();
runTest();
}
}
}
@ -87,9 +82,6 @@ function runTest() {
wN.close();
wP.close();
prefBranch.clearUserPref("browser.startup.page")
prefBranch.clearUserPref("browser.startup.homepage_override.mstone");
SimpleTest.finish();
return;
}
@ -99,7 +91,11 @@ function runTest() {
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.workers.sharedWorkers.enabled", true]]}, runTest);
SpecialPowers.pushPrefEnv({"set": [
["dom.workers.sharedWorkers.enabled", true],
["browser.startup.page", 0],
["browser.startup.homepage_override.mstone", "ignore"],
]}, runTest);
</script>
</body>

View File

@ -333,30 +333,39 @@ DrawTargetD2D1::CopySurface(SourceSurface *aSurface,
return;
}
if (mFormat == SurfaceFormat::A8) {
RefPtr<ID2D1Bitmap> bitmap;
image->QueryInterface((ID2D1Bitmap**)byRef(bitmap));
mDC->PushAxisAlignedClip(D2D1::RectF(aDestination.x, aDestination.y,
aDestination.x + aSourceRect.width,
aDestination.y + aSourceRect.height),
D2D1_ANTIALIAS_MODE_ALIASED);
mDC->Clear();
mDC->PopAxisAlignedClip();
RefPtr<ID2D1Bitmap> bitmap;
image->QueryInterface((ID2D1Bitmap**)byRef(bitmap));
if (bitmap && mFormat == SurfaceFormat::A8) {
RefPtr<ID2D1SolidColorBrush> brush;
mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
D2D1::BrushProperties(), byRef(brush));
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
return;
}
Rect srcRect(Float(aSourceRect.x), Float(aSourceRect.y),
Float(aSourceRect.width), Float(aSourceRect.height));
Rect dstRect(Float(aDestination.x), Float(aDestination.y),
Float(aSourceRect.width), Float(aSourceRect.height));
if (bitmap) {
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
mDC->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f,
D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
D2DRect(srcRect));
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
return;
}
mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)),
D2D1::RectF(Float(aSourceRect.x), Float(aSourceRect.y),
Float(aSourceRect.XMost()), Float(aSourceRect.YMost())),
D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
D2DRect(srcRect), D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
}
void

View File

@ -393,10 +393,6 @@ ClientTiledPaintedLayer::RenderLayer()
LayerManager::DrawPaintedLayerCallback callback =
ClientManager()->GetPaintedLayerCallback();
void *data = ClientManager()->GetPaintedLayerCallbackData();
if (!callback) {
ClientManager()->SetTransactionIncomplete();
return;
}
if (!mContentClient) {
mContentClient = new TiledContentClient(this, ClientManager());
@ -442,6 +438,11 @@ ClientTiledPaintedLayer::RenderLayer()
return;
}
if (!callback) {
ClientManager()->SetTransactionIncomplete();
return;
}
if (!ClientManager()->IsRepeatTransaction()) {
// Only paint the mask layers on the first transaction.
RenderMaskLayers(this);

View File

@ -2026,6 +2026,10 @@ gfxWindowsPlatform::InitD3D11Devices()
mD3D11ContentDevice->SetExceptionMode(0);
nsRefPtr<ID3D10Multithread> multi;
mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
multi->SetMultithreadProtected(TRUE);
Factory::SetDirect3D11Device(mD3D11ContentDevice);
}

View File

@ -670,6 +670,9 @@ ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
nsISupports* aCX, ReferrerPolicy referrerPolicy)
{
// If the entry's Referrer Policy doesn't match, we can't use this request.
// XXX: this will return false if an image has different referrer attributes,
// i.e. we currently don't use the cached image but reload the image with
// the new referrer policy bug 1174921
if (referrerPolicy != request->GetReferrerPolicy()) {
return false;
}

View File

@ -3200,9 +3200,8 @@ CSS_PROP_TEXT(
text_combine_upright,
TextCombineUpright,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_VALUE_PARSER_FUNCTION |
CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS,
"layout.css.vertical-text.enabled",
CSS_PROPERTY_VALUE_PARSER_FUNCTION,
"layout.css.text-combine-upright.enabled",
0,
kTextCombineUprightKTable,
offsetof(nsStyleText, mTextCombineUpright),

View File

@ -2836,7 +2836,8 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_RepaintFrame);
for (uint8_t index = 0; index < 3; ++index)
if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) {
NS_UpdateHint(transformHint, kUpdateOverflowAndRepaintHint);
NS_UpdateHint(transformHint, NS_CombineHint(nsChangeHint_UpdateTransformLayer,
nsChangeHint_UpdatePostTransformOverflow));
break;
}

View File

@ -4715,16 +4715,6 @@ if (SpecialPowers.getBoolPref("layout.css.vertical-text.enabled")) {
other_values: [ "upright", "sideways-right" ],
invalid_values: [ "none", "3em", "sideways", "sideways-left" ] /* sideways, sideways-left not yet supported */
},
"text-combine-upright": {
domProp: "textCombineUpright",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "all", "digits", "digits 2", "digits 3", "digits 4", "digits 3" ],
invalid_values: [ "auto", "all 2", "none all", "digits -3", "digits 0",
"digits 12", "none 3", "digits 3.1415", "digits3", "digits 1",
"digits 3 all", "digits foo", "digits all", "digits 3.0" ]
},
"border-block-end": {
domProp: "borderBlockEnd",
inherited: false,
@ -5288,6 +5278,19 @@ if (SpecialPowers.getBoolPref("layout.css.vertical-text.enabled")) {
});
}
if (SpecialPowers.getBoolPref("layout.css.text-combine-upright.enabled")) {
gCSSProperties["text-combine-upright"] = {
domProp: "textCombineUpright",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "all", "digits", "digits 2", "digits 3", "digits 4", "digits 3" ],
invalid_values: [ "auto", "all 2", "none all", "digits -3", "digits 0",
"digits 12", "none 3", "digits 3.1415", "digits3", "digits 1",
"digits 3 all", "digits foo", "digits all", "digits 3.0" ]
};
}
if (SpecialPowers.getBoolPref("layout.css.masking.enabled")) {
gCSSProperties["mask-type"] = {
domProp: "maskType",

View File

@ -68,7 +68,8 @@ function step() {
// ----
var gProps = {
"layout.css.vertical-text.enabled": ["text-combine-upright", "text-orientation", "writing-mode"],
"layout.css.vertical-text.enabled": ["text-orientation", "writing-mode"],
"layout.css.text-combine-upright.enabled": ["text-combine-upright"],
"layout.css.image-orientation.enabled": ["image-orientation"],
"layout.css.mix-blend-mode.enabled": ["mix-blend-mode"],
"layout.css.isolation.enabled": [ "isolation"],

View File

@ -23,7 +23,6 @@ sys.path.insert(0, SCRIPT_DIRECTORY)
from automationutils import (
dumpScreen,
environment,
printstatus,
processLeakLog
)
@ -33,6 +32,7 @@ import mozinfo
import mozprocess
import mozprofile
import mozrunner
from mozrunner.utils import test_environment
here = os.path.abspath(os.path.dirname(__file__))
@ -273,7 +273,8 @@ class RefTest(object):
return profile
def environment(self, **kwargs):
return environment(**kwargs)
kwargs['log'] = log
return test_environment(**kwargs)
def buildBrowserEnv(self, options, profileDir):
browserEnv = self.environment(xrePath = options.xrePath, debugger=options.debugger)

View File

@ -1274,6 +1274,9 @@ pref("network.http.referer.XOriginPolicy", 0);
// By default this is enabled for compatibility (see bug 141641)
pref("network.http.sendSecureXSiteReferrer", true);
// Controls whether referrer attributes in <a>, <img>, <area>, and <iframe> are honoured
pref("network.http.enablePerElementReferrer", false);
// Maximum number of consecutive redirects before aborting.
pref("network.http.redirection-limit", 20);
@ -2249,6 +2252,9 @@ pref("layout.css.background-blend-mode.enabled", true);
// Is support for CSS vertical text enabled?
pref("layout.css.vertical-text.enabled", true);
// Is support for CSS text-combine-upright (tate-chu-yoko) enabled?
pref("layout.css.text-combine-upright.enabled", false);
// Is support for object-fit and object-position enabled?
pref("layout.css.object-fit-and-position.enabled", true);

View File

@ -25,7 +25,10 @@ enum ReferrerPolicy {
RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
/* spec tokens: always unsafe-url */
RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL
RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL,
/* referrer policy is not set */
RP_Unset = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE
};
inline ReferrerPolicy

View File

@ -989,6 +989,7 @@ public final class AttributeName
public static final AttributeName READONLY = new AttributeName(ALL_NO_NS, SAME_LOCAL("readonly"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG | CASE_FOLDED | BOOLEAN);
public static final AttributeName SELECTED = new AttributeName(ALL_NO_NS, SAME_LOCAL("selected"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG | CASE_FOLDED | BOOLEAN);
public static final AttributeName ROWLINES = new AttributeName(ALL_NO_NS, SAME_LOCAL("rowlines"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName REFERRER = new AttributeName(ALL_NO_NS, SAME_LOCAL("referrer"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName SEAMLESS = new AttributeName(ALL_NO_NS, SAME_LOCAL("seamless"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName ROWALIGN = new AttributeName(ALL_NO_NS, SAME_LOCAL("rowalign"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName STRETCHY = new AttributeName(ALL_NO_NS, SAME_LOCAL("stretchy"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
@ -1571,6 +1572,7 @@ public final class AttributeName
READONLY,
SELECTED,
ROWLINES,
REFERRER,
SEAMLESS,
ROWALIGN,
STRETCHY,
@ -2154,6 +2156,7 @@ public final class AttributeName
291557706,
291665349,
291804100,
291862420,
292138018,
292166446,
292418738,

View File

@ -348,6 +348,7 @@ HTML5_ATOM(tabindex, "tabindex")
HTML5_ATOM(readonly, "readonly")
HTML5_ATOM(selected, "selected")
HTML5_ATOM(rowlines, "rowlines")
HTML5_ATOM(referrer, "referrer")
HTML5_ATOM(seamless, "seamless")
HTML5_ATOM(rowalign, "rowalign")
HTML5_ATOM(stretchy, "stretchy")

File diff suppressed because one or more lines are too long

View File

@ -364,6 +364,7 @@ class nsHtml5AttributeName
static nsHtml5AttributeName* ATTR_READONLY;
static nsHtml5AttributeName* ATTR_SELECTED;
static nsHtml5AttributeName* ATTR_ROWLINES;
static nsHtml5AttributeName* ATTR_REFERRER;
static nsHtml5AttributeName* ATTR_SEAMLESS;
static nsHtml5AttributeName* ATTR_ROWALIGN;
static nsHtml5AttributeName* ATTR_STRETCHY;

View File

@ -28,10 +28,10 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
aExecutor->SetSpeculationBase(mUrl);
break;
case eSpeculativeLoadMetaReferrer:
aExecutor->SetSpeculationReferrerPolicy(mMetaReferrerPolicy);
aExecutor->SetSpeculationReferrerPolicy(mReferrerPolicy);
break;
case eSpeculativeLoadImage:
aExecutor->PreloadImage(mUrl, mCrossOrigin, mSrcset, mSizes);
aExecutor->PreloadImage(mUrl, mCrossOrigin, mSrcset, mSizes, mReferrerPolicy);
break;
case eSpeculativeLoadOpenPicture:
aExecutor->PreloadOpenPicture();

View File

@ -45,12 +45,13 @@ class nsHtml5SpeculativeLoad {
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!");
mOpCode = eSpeculativeLoadMetaReferrer;
mMetaReferrerPolicy.Assign(
mReferrerPolicy.Assign(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
}
inline void InitImage(const nsAString& aUrl,
const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy,
const nsAString& aSrcset,
const nsAString& aSizes)
{
@ -59,6 +60,8 @@ class nsHtml5SpeculativeLoad {
mOpCode = eSpeculativeLoadImage;
mUrl.Assign(aUrl);
mCrossOrigin.Assign(aCrossOrigin);
mReferrerPolicy.Assign(
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
mSrcset.Assign(aSrcset);
mSizes.Assign(aSizes);
}
@ -179,7 +182,7 @@ class nsHtml5SpeculativeLoad {
private:
eHtml5SpeculativeLoad mOpCode;
nsString mUrl;
nsString mMetaReferrerPolicy;
nsString mReferrerPolicy;
/**
* If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
* then this is the value of the "charset" attribute. For

View File

@ -125,11 +125,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
nsString* crossOrigin =
aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
nsString* referrerPolicy =
aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRER);
nsString* sizes =
aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
mSpeculativeLoadQueue.AppendElement()->
InitImage(url ? *url : NullString(),
crossOrigin ? *crossOrigin : NullString(),
referrerPolicy ? *referrerPolicy : NullString(),
srcset ? *srcset : NullString(),
sizes ? *sizes : NullString());
} else if (nsHtml5Atoms::source == aName) {
@ -202,6 +205,7 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
if (url) {
mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
NullString(),
NullString(),
NullString());
}
@ -238,6 +242,7 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
if (url) {
mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
NullString(),
NullString(),
NullString());
}

View File

@ -943,13 +943,25 @@ void
nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
const nsAString& aCrossOrigin,
const nsAString& aSrcset,
const nsAString& aSizes)
const nsAString& aSizes,
const nsAString& aImageReferrerPolicy)
{
nsCOMPtr<nsIURI> baseURI = BaseURIForPreload();
nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset,
aSizes);
if (uri && ShouldPreloadURI(uri)) {
mDocument->MaybePreLoadImage(uri, aCrossOrigin, mSpeculationReferrerPolicy);
// use document wide referrer policy
mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy;
// if enabled in preferences, use the referrer attribute from the image, if provided
bool referrerAttributeEnabled = Preferences::GetBool("network.http.enablePerElementReferrer", false);
if (referrerAttributeEnabled) {
mozilla::net::ReferrerPolicy imageReferrerPolicy = mozilla::net::ReferrerPolicyFromString(aImageReferrerPolicy);
if (imageReferrerPolicy != mozilla::net::RP_Unset) {
referrerPolicy = imageReferrerPolicy;
}
}
mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy);
}
}

View File

@ -256,7 +256,8 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder,
void PreloadImage(const nsAString& aURL,
const nsAString& aCrossOrigin,
const nsAString& aSrcset,
const nsAString& aSizes);
const nsAString& aSizes,
const nsAString& aImageReferrerPolicy);
void PreloadOpenPicture();

View File

@ -35,7 +35,6 @@ import zipfile
import bisection
from automationutils import (
environment,
processLeakLog,
dumpScreen,
printstatus,
@ -59,6 +58,7 @@ from mozprofile.permissions import ServerLocations
from urllib import quote_plus as encodeURIComponent
from mozlog.structured.formatters import TbplFormatter
from mozlog.structured import commandline
from mozrunner.utils import test_environment
here = os.path.abspath(os.path.dirname(__file__))
@ -359,7 +359,7 @@ class MochitestServer(object):
"Run the Mochitest server, returning the process ID of the server."
# get testing environment
env = environment(xrePath=self._xrePath)
env = test_environment(xrePath=self._xrePath, log=self._log)
env["XPCOM_DEBUG_BREAK"] = "warn"
env["LD_LIBRARY_PATH"] = self._xrePath
@ -1064,7 +1064,7 @@ class SSLTunnel:
ssltunnel)
exit(1)
env = environment(xrePath=self.xrePath)
env = test_environment(xrePath=self.xrePath, log=self.log)
env["LD_LIBRARY_PATH"] = self.xrePath
self.process = mozprocess.ProcessHandler([ssltunnel, self.configFile],
env=env)
@ -1234,9 +1234,6 @@ class Mochitest(MochitestUtilsMixin):
def __init__(self, logger_options):
super(Mochitest, self).__init__(logger_options)
# environment function for browserEnv
self.environment = environment
# Max time in seconds to wait for server startup before tests will fail -- if
# this seems big, it's mostly for debug machines where cold startup
# (particularly after a build) takes forever.
@ -1254,6 +1251,10 @@ class Mochitest(MochitestUtilsMixin):
self.expectedError = {}
self.result = {}
def environment(self, **kwargs):
kwargs['log'] = self.log
return test_environment(**kwargs)
def extraPrefs(self, extraPrefs):
"""interpolate extra preferences from option strings"""

View File

@ -94,3 +94,152 @@ def uses_marionette(func):
return ret
return _
def _raw_log():
import logging
return logging.getLogger(__name__)
def test_environment(xrePath, env=None, crashreporter=True, debugger=False,
dmdPath=None, lsanPath=None, log=None):
"""
populate OS environment variables for mochitest and reftests.
Originally comes from automationutils.py. Don't use that for new code.
"""
env = os.environ.copy() if env is None else env
log = log or _raw_log()
assert os.path.isabs(xrePath)
if mozinfo.isMac:
ldLibraryPath = os.path.join(os.path.dirname(xrePath), "MacOS")
else:
ldLibraryPath = xrePath
envVar = None
dmdLibrary = None
preloadEnvVar = None
if 'toolkit' in mozinfo.info and mozinfo.info['toolkit'] == "gonk":
# Skip all of this, it's only valid for the host.
pass
elif mozinfo.isUnix:
envVar = "LD_LIBRARY_PATH"
env['MOZILLA_FIVE_HOME'] = xrePath
dmdLibrary = "libdmd.so"
preloadEnvVar = "LD_PRELOAD"
elif mozinfo.isMac:
envVar = "DYLD_LIBRARY_PATH"
dmdLibrary = "libdmd.dylib"
preloadEnvVar = "DYLD_INSERT_LIBRARIES"
elif mozinfo.isWin:
envVar = "PATH"
dmdLibrary = "dmd.dll"
preloadEnvVar = "MOZ_REPLACE_MALLOC_LIB"
if envVar:
envValue = ((env.get(envVar), str(ldLibraryPath))
if mozinfo.isWin
else (ldLibraryPath, dmdPath, env.get(envVar)))
env[envVar] = os.path.pathsep.join([path for path in envValue if path])
if dmdPath and dmdLibrary and preloadEnvVar:
env[preloadEnvVar] = os.path.join(dmdPath, dmdLibrary)
# crashreporter
env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
if crashreporter and not debugger:
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
env['MOZ_CRASHREPORTER'] = '1'
else:
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
# Crash on non-local network connections by default.
# MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily
# enable non-local connections for the purposes of local testing. Don't
# override the user's choice here. See bug 1049688.
env.setdefault('MOZ_DISABLE_NONLOCAL_CONNECTIONS', '1')
# Set WebRTC logging in case it is not set yet
env.setdefault(
'NSPR_LOG_MODULES',
'signaling:3,mtransport:4,datachannel:4,jsep:4,MediaPipelineFactory:4'
)
env.setdefault('R_LOG_LEVEL', '6')
env.setdefault('R_LOG_DESTINATION', 'stderr')
env.setdefault('R_LOG_VERBOSE', '1')
# ASan specific environment stuff
asan = bool(mozinfo.info.get("asan"))
if asan and (mozinfo.isLinux or mozinfo.isMac):
try:
# Symbolizer support
llvmsym = os.path.join(xrePath, "llvm-symbolizer")
if os.path.isfile(llvmsym):
env["ASAN_SYMBOLIZER_PATH"] = llvmsym
log.info("INFO | runtests.py | ASan using symbolizer at %s"
% llvmsym)
else:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Failed to find"
" ASan symbolizer at %s" % llvmsym)
# Returns total system memory in kilobytes.
# Works only on unix-like platforms where `free` is in the path.
totalMemory = int(os.popen("free").readlines()[1].split()[1])
# Only 4 GB RAM or less available? Use custom ASan options to reduce
# the amount of resources required to do the tests. Standard options
# will otherwise lead to OOM conditions on the current test slaves.
message = "INFO | runtests.py | ASan running in %s configuration"
asanOptions = []
if totalMemory <= 1024 * 1024 * 4:
message = message % 'low-memory'
asanOptions = [
'quarantine_size=50331648', 'malloc_context_size=5']
else:
message = message % 'default memory'
if lsanPath:
log.info("LSan enabled.")
asanOptions.append('detect_leaks=1')
lsanOptions = ["exitcode=0"]
suppressionsFile = os.path.join(
lsanPath, 'lsan_suppressions.txt')
if os.path.exists(suppressionsFile):
log.info("LSan using suppression file " + suppressionsFile)
lsanOptions.append("suppressions=" + suppressionsFile)
else:
log.info("WARNING | runtests.py | LSan suppressions file"
" does not exist! " + suppressionsFile)
env["LSAN_OPTIONS"] = ':'.join(lsanOptions)
# Run shutdown GCs and CCs to avoid spurious leaks.
env['MOZ_CC_RUN_DURING_SHUTDOWN'] = '1'
if len(asanOptions):
env['ASAN_OPTIONS'] = ':'.join(asanOptions)
except OSError, err:
log.info("Failed determine available memory, disabling ASan"
" low-memory configuration: %s" % err.strerror)
except:
log.info("Failed determine available memory, disabling ASan"
" low-memory configuration")
else:
log.info(message)
tsan = bool(mozinfo.info.get("tsan"))
if tsan and mozinfo.isLinux:
# Symbolizer support.
llvmsym = os.path.join(xrePath, "llvm-symbolizer")
if os.path.isfile(llvmsym):
env["TSAN_OPTIONS"] = "external_symbolizer_path=%s" % llvmsym
log.info("INFO | runtests.py | TSan using symbolizer at %s"
% llvmsym)
else:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Failed to find TSan"
" symbolizer at %s" % llvmsym)
return env

View File

@ -68,30 +68,6 @@ function takeWindowSnapshot(win, ctx) {
ctx.drawWindow(win.ownerGlobal, 0, 0, PAGE_WIDTH, PAGE_HEIGHT, "rgb(255,255,255)", flags);
}
function takeWidgetSnapshot(win, canvas, ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawWidgetAsOnScreen(win.ownerGlobal);
}
function testWidgetSnapshot(win, canvas, ctx) {
try {
takeWidgetSnapshot(win, canvas, ctx);
if (verifyVideoRendering(ctx)) {
reportSnapshotResult(SNAPSHOT_VIDEO_OK);
} else {
reportSnapshotResult(SNAPSHOT_VIDEO_FAIL);
}
if (verifyLayersRendering(ctx)) {
reportSnapshotResult(SNAPSHOT_LAYERS_OK);
} else {
reportSnapshotResult(SNAPSHOT_LAYERS_FAIL);
}
} catch (e) {
reportSnapshotResult(SNAPSHOT_ERROR);
}
}
function setTimeout(aMs, aCallback) {
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
@ -149,15 +125,6 @@ let listener = {
utils: null,
canvas: null,
// State flow:
// onload -> WM_PAINT -> MozAfterPaint -> ready
// WM_PAINT -> onload -> MozAfterPaint -> ready
//
// We always wait for the low-level paint message because this is what tells
// us whether or not the OS has actually started drawing.
windowLoaded: false, // onload event has fired.
windowReady: false, // widget has received an OS-level paint request.
scheduleTest: function(win) {
this.win = win;
this.win.onload = this.onWindowLoaded.bind(this);
@ -177,64 +144,7 @@ let listener = {
// Perform the compositor backbuffer test, which currently we use for
// actually deciding whether to enable hardware media decoding.
if (!testCompositor(this.win, this.ctx)) {
this.endTest();
return;
}
// Wait to perform the OS snapshot test. Since this waits for a series of
// events to occur, we set a timeout in case nothing happens.
setTimeout(OS_SNAPSHOT_TIMEOUT_SEC * 1000, (() => {
if (this.win) {
reportSnapshotResult(SNAPSHOT_TIMEOUT);
this.endTest();
}
}));
this.windowLoaded = true;
if (this.windowReady) {
this.waitForPaintsFlushed();
}
},
// Watch for the first OS-level paint message to the window.
observe: function(aSubject, aTopic, aData) {
if (aSubject != this.win || aTopic != "widget-first-paint") {
return;
}
this.windowReady = true;
if (this.windowLoaded) {
this.waitForPaintsFlushed();
}
},
// Wait for all layout-induced paints to flush.
waitForPaintsFlushed: function() {
// If the test ended prematurely due to a timeout, just ignore the event.
if (!this.win) {
return;
}
if (this.utils.isMozAfterPaintPending) {
let paintListener = (() => {
if (this.utils && this.utils.isMozAfterPaintPending) {
return;
}
this.win.removeEventListener("MozAfterPaint", paintListener);
if (this.utils) {
// Painting is finished, we will fail the above
// isMozAfterPaintPending test now.
this.waitForPaintsFlushed();
}
});
this.win.addEventListener("MozAfterPaint", paintListener);
return;
}
testWidgetSnapshot(this.win, this.canvas, this.ctx);
testCompositor(this.win, this.ctx);
this.endTest();
},
@ -303,6 +213,10 @@ SanityTest.prototype = {
"Test Page",
"width=" + PAGE_WIDTH + ",height=" + PAGE_HEIGHT + ",chrome,titlebar=0,scrollbars=0",
null);
// There's no clean way to have an invisible window and ensure it's always painted.
// Instead, move the window far offscreen so it doesn't show up during launch.
sanityTest.moveTo(100000000,1000000000);
listener.scheduleTest(sanityTest);
},
};