mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team, a=merge
This commit is contained in:
commit
f44218465a
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"""
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
212
dom/base/test/img_referrer_testserver.sjs
Normal file
212
dom/base/test/img_referrer_testserver.sjs
Normal 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;
|
||||
}
|
@ -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
|
||||
|
171
dom/base/test/test_img_referrer.html
Normal file
171
dom/base/test/test_img_referrer.html
Normal 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>
|
||||
|
16
dom/cache/CacheStorage.cpp
vendored
16
dom/cache/CacheStorage.cpp
vendored
@ -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.");
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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) :
|
||||
|
@ -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);
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -30,6 +30,8 @@ interface HTMLImageElement : HTMLElement {
|
||||
[SetterThrows]
|
||||
attribute DOMString useMap;
|
||||
[SetterThrows]
|
||||
attribute DOMString referrer;
|
||||
[SetterThrows]
|
||||
attribute boolean isMap;
|
||||
[SetterThrows]
|
||||
attribute unsigned long width;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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"],
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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"""
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user