mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
1fcc543445
@ -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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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"/>
|
||||
@ -117,7 +117,7 @@
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
|
||||
<project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
|
||||
<project name="platform/system/media" path="system/media" revision="188b3e51e0a2ce1e16dc8067edef7be3d2365ad9"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
|
||||
<project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
|
||||
|
@ -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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="47f48a42502b1c694db2b162011a67a2ff888c5d"/>
|
||||
|
@ -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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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": "938375d0abafd92d78b3913db1735e49f46a6598",
|
||||
"git_revision": "553e4e281d11500bea702918841f011bfb5405f7",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "2c98eea0fc57337386cb7c527503b0950c117167",
|
||||
"revision": "0f653f6e0c527eee11b3d0e21f41509976c1daed",
|
||||
"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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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="47f48a42502b1c694db2b162011a67a2ff888c5d"/>
|
||||
|
@ -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="938375d0abafd92d78b3913db1735e49f46a6598"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
|
||||
<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"/>
|
||||
|
@ -128,6 +128,7 @@
|
||||
#ifndef MOZ_FOLD_LIBS
|
||||
@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
|
||||
#endif
|
||||
@BINPATH@/@DLL_PREFIX@lgpllibs@DLL_SUFFIX@
|
||||
@RESPATH@/blocklist.xml
|
||||
@RESPATH@/ua-update.json
|
||||
#ifdef XP_UNIX
|
||||
|
@ -94,6 +94,34 @@ Sanitizer.prototype = {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
let cookiesIndex = itemsToClear.indexOf("cookies");
|
||||
if (cookiesIndex != -1) {
|
||||
itemsToClear.splice(cookiesIndex, 1);
|
||||
let item = this.items.cookies;
|
||||
item.range = this.range;
|
||||
let ok = item.clear(() => {
|
||||
try {
|
||||
if (!itemsToClear.length) {
|
||||
// we're done
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
let clearedPromise = this.sanitize(itemsToClear);
|
||||
clearedPromise.then(deferred.resolve, deferred.reject);
|
||||
} catch(e) {
|
||||
let error = "Sanitizer threw after clearing cookies: " + e;
|
||||
Cu.reportError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
});
|
||||
// When cancelled, reject immediately
|
||||
if (!ok) {
|
||||
deferred.reject("Sanitizer canceled clearing cookies");
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
TelemetryStopwatch.start("FX_SANITIZE_TOTAL");
|
||||
|
||||
// Cache the range of times to clear
|
||||
@ -177,7 +205,7 @@ Sanitizer.prototype = {
|
||||
},
|
||||
|
||||
cookies: {
|
||||
clear: function ()
|
||||
clear: function (aCallback)
|
||||
{
|
||||
TelemetryStopwatch.start("FX_SANITIZE_COOKIES");
|
||||
TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2");
|
||||
@ -209,6 +237,16 @@ Sanitizer.prototype = {
|
||||
|
||||
// Clear plugin data.
|
||||
TelemetryStopwatch.start("FX_SANITIZE_PLUGINS");
|
||||
this.clearPluginCookies().then(
|
||||
function() {
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS");
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_COOKIES");
|
||||
aCallback();
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
clearPluginCookies: function() {
|
||||
const phInterface = Ci.nsIPluginHost;
|
||||
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
||||
let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
|
||||
@ -217,29 +255,35 @@ Sanitizer.prototype = {
|
||||
// that this.range[1] is actually now, so we compute age range based
|
||||
// on the lower bound. If this.range results in a negative age, do
|
||||
// nothing.
|
||||
let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000)
|
||||
: -1;
|
||||
let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000) : -1;
|
||||
if (!this.range || age >= 0) {
|
||||
let tags = ph.getPluginTags();
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
try {
|
||||
ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, age);
|
||||
} catch (e) {
|
||||
// If the plugin doesn't support clearing by age, clear everything.
|
||||
if (e.result == Components.results.
|
||||
NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
|
||||
try {
|
||||
ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, -1);
|
||||
} catch (e) {
|
||||
// Ignore errors from the plugin
|
||||
}
|
||||
function iterate(tag) {
|
||||
let promise = new Promise(resolve => {
|
||||
try {
|
||||
let onClear = function(rv) {
|
||||
// If the plugin doesn't support clearing by age, clear everything.
|
||||
if (rv == Components.results. NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
|
||||
ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, -1, function() {
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, age, onClear);
|
||||
} catch (ex) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
let promises = [];
|
||||
for (let tag of tags) {
|
||||
promises.push(iterate(tag));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS");
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_COOKIES");
|
||||
},
|
||||
|
||||
get canClear()
|
||||
|
@ -84,7 +84,7 @@ add_task(function* () {
|
||||
// Clear 20 seconds ago
|
||||
let now_uSec = Date.now() * 1000;
|
||||
sanitizer.range = [now_uSec - 20*1000000, now_uSec];
|
||||
sanitizer.sanitize();
|
||||
yield sanitizer.sanitize();
|
||||
|
||||
ok(stored(["bar.com","qux.com"]), "Data stored for sites");
|
||||
ok(!stored(["foo.com"]), "Data cleared for foo.com");
|
||||
@ -92,7 +92,7 @@ add_task(function* () {
|
||||
|
||||
// Clear everything
|
||||
sanitizer.range = null;
|
||||
sanitizer.sanitize();
|
||||
yield sanitizer.sanitize();
|
||||
|
||||
ok(!stored(null), "All data cleared");
|
||||
|
||||
@ -117,7 +117,7 @@ add_task(function* () {
|
||||
// clearing all data regardless of age.
|
||||
let now_uSec = Date.now() * 1000;
|
||||
sanitizer.range = [now_uSec - 20*1000000, now_uSec];
|
||||
sanitizer.sanitize();
|
||||
yield sanitizer.sanitize();
|
||||
|
||||
ok(!stored(null), "All data cleared");
|
||||
|
||||
|
@ -151,6 +151,7 @@
|
||||
@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
|
||||
#endif
|
||||
#endif
|
||||
@BINPATH@/@DLL_PREFIX@lgpllibs@DLL_SUFFIX@
|
||||
@RESPATH@/browser/blocklist.xml
|
||||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
|
@ -629,10 +629,36 @@ EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
|
||||
endif
|
||||
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
|
||||
|
||||
# $(call CHECK_SYMBOLS,lib,PREFIX,dep_name,test)
|
||||
# Checks that the given `lib` doesn't contain dependency on symbols with a
|
||||
# version starting with `PREFIX`_ and matching the `test`. `dep_name` is only
|
||||
# used for the error message.
|
||||
# `test` is an awk expression using the information in the variable `v` which
|
||||
# contains a list of version items ([major, minor, ...]).
|
||||
define CHECK_SYMBOLS
|
||||
@$(TOOLCHAIN_PREFIX)readelf -sW $(1) | \
|
||||
awk '$$8 ~ /@$(2)_/ { \
|
||||
split($$8,a,"@"); \
|
||||
split(a[2],b,"_"); \
|
||||
split(b[2],v,"."); \
|
||||
if ($(4)) { \
|
||||
if (!found) { \
|
||||
print "TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these $(3) symbols to be used:" \
|
||||
} \
|
||||
print " ",$$8; \
|
||||
found=1 \
|
||||
} \
|
||||
} \
|
||||
END { \
|
||||
if (found) { \
|
||||
exit(1) \
|
||||
} \
|
||||
}'
|
||||
endef
|
||||
|
||||
ifneq (,$(MOZ_LIBSTDCXX_TARGET_VERSION)$(MOZ_LIBSTDCXX_HOST_VERSION))
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
CHECK_STDCXX = @$(TOOLCHAIN_PREFIX)objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(1[1-9]\|[2-9][0-9]\)' > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these libstdc++ symbols to be used:' && $(TOOLCHAIN_PREFIX)objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(1[1-9]\|[2-9][0-9]\)' && exit 1 || true
|
||||
endif
|
||||
CHECK_STDCXX = $(call CHECK_SYMBOLS,$(1),GLIBCXX,libstdc++,v[1] > 3 || (v[1] == 3 && v[2] == 4 && v[3] > 10))
|
||||
CHECK_GLIBC = $(call CHECK_SYMBOLS,$(1),GLIBC,libc,v[1] > 2 || (v[1] == 2 && v[2] > 7))
|
||||
endif
|
||||
|
||||
ifeq (,$(filter $(OS_TARGET),WINNT Darwin))
|
||||
@ -648,6 +674,7 @@ CHECK_MOZGLUE_ORDER = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep NEEDED | awk '{
|
||||
endif
|
||||
|
||||
define CHECK_BINARY
|
||||
$(call CHECK_GLIBC,$(1))
|
||||
$(call CHECK_STDCXX,$(1))
|
||||
$(call CHECK_TEXTREL,$(1))
|
||||
$(call LOCAL_CHECKS,$(1))
|
||||
|
14
config/external/lgpllibs/moz.build
vendored
Normal file
14
config/external/lgpllibs/moz.build
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# The lgpllibs library stores symbols from third-party LGPL licensed libraries,
|
||||
# such as libav and libsoundtouch. It fulfills the requirement of dynamically
|
||||
# linking these symbols into gecko.
|
||||
#
|
||||
# Any library added here should also be reflected in the about:license page.
|
||||
|
||||
SharedLibrary('lgpllibs')
|
||||
SHARED_LIBRARY_NAME = 'lgpllibs'
|
1
config/external/moz.build
vendored
1
config/external/moz.build
vendored
@ -7,6 +7,7 @@
|
||||
external_dirs = []
|
||||
|
||||
DIRS += [
|
||||
'lgpllibs',
|
||||
'sqlite',
|
||||
]
|
||||
if not CONFIG['MOZ_NATIVE_JPEG']:
|
||||
|
@ -1257,6 +1257,7 @@ X11/Xos.h
|
||||
X11/Xutil.h
|
||||
zmouse.h
|
||||
soundtouch/SoundTouch.h
|
||||
soundtouch/SoundTouchFactory.h
|
||||
#if MOZ_NATIVE_PNG==1
|
||||
png.h
|
||||
#endif
|
||||
|
@ -106,6 +106,7 @@ static RedirEntry kRedirMap[] = {
|
||||
{
|
||||
"serviceworkers", "chrome://global/content/aboutServiceWorkers.xhtml",
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||
nsIAboutModule::ALLOW_SCRIPT
|
||||
},
|
||||
// about:srcdoc is unresolvable by specification. It is included here
|
||||
|
@ -3196,7 +3196,10 @@ nsDOMWindowUtils::ExitFullscreen()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
|
||||
nsIDocument::ExitFullscreen(nullptr, /* async */ false);
|
||||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
NS_ENSURE_STATE(doc);
|
||||
|
||||
nsIDocument::ExitFullscreen(doc, /* async */ false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,9 @@ nsImageLoadingContent::nsImageLoadingContent()
|
||||
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
|
||||
mLoadingEnabled = false;
|
||||
}
|
||||
|
||||
bool isInconsistent;
|
||||
mMostRecentRequestChange = TimeStamp::ProcessCreation(isInconsistent);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1235,6 +1238,22 @@ nsImageLoadingContent::FireEvent(const nsAString& aEventType)
|
||||
nsRefPtr<imgRequestProxy>&
|
||||
nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
|
||||
{
|
||||
nsImageFrame* frame = do_QueryFrame(GetOurPrimaryFrame());
|
||||
if (frame) {
|
||||
// Detect JavaScript-based animations created by changing the |src|
|
||||
// attribute on a timer.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration threshold =
|
||||
TimeDuration::FromMilliseconds(
|
||||
gfxPrefs::ImageInferSrcAnimationThresholdMS());
|
||||
|
||||
// If the length of time between request changes is less than the threshold,
|
||||
// then force sync decoding to eliminate flicker from the animation.
|
||||
frame->SetForceSyncDecoding(now - mMostRecentRequestChange < threshold);
|
||||
|
||||
mMostRecentRequestChange = now;
|
||||
}
|
||||
|
||||
// If we don't have a usable current request, get rid of any half-baked
|
||||
// request that might be sitting there and make this one current.
|
||||
if (!HaveSize(mCurrentRequest))
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "imgIOnloadBlocker.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsIRequest.h"
|
||||
@ -397,6 +398,8 @@ private:
|
||||
*/
|
||||
mozilla::EventStates mForcedImageState;
|
||||
|
||||
mozilla::TimeStamp mMostRecentRequestChange;
|
||||
|
||||
int16_t mImageBlockingStatus;
|
||||
bool mLoadingEnabled : 1;
|
||||
|
||||
|
@ -501,7 +501,11 @@ nsPerformance::Navigation()
|
||||
DOMHighResTimeStamp
|
||||
nsPerformance::Now() const
|
||||
{
|
||||
return GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
|
||||
double nowTimeMs = GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
|
||||
// Round down to the nearest 0.005ms (5us), because if the timer is too
|
||||
// accurate people can do nasty timing attacks with it.
|
||||
const double maxResolutionMs = 0.005;
|
||||
return floor(nowTimeMs / maxResolutionMs) * maxResolutionMs;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -90,6 +90,10 @@ function make_json()
|
||||
function parent_test(finish)
|
||||
{
|
||||
function f(check_func) {
|
||||
// Make sure this doesn't crash.
|
||||
let array = new Uint32Array(10);
|
||||
content.crypto.getRandomValues(array);
|
||||
|
||||
let result = check_func(10);
|
||||
ok(result == 20, "calling function in parent worked");
|
||||
return result;
|
||||
|
@ -34,9 +34,17 @@ function runTest() {
|
||||
event = ifr.contentDocument.createEvent("Events");
|
||||
event.initEvent("foo", true, true);
|
||||
xhr.dispatchEvent(event);
|
||||
is(eventCount, 1,
|
||||
"Shouldn't have handled an event because the context has changed");
|
||||
SimpleTest.finish();
|
||||
is(eventCount, 2,
|
||||
"Should have handled the event because open()/close() keep the active document");
|
||||
ifr.onload = function() {
|
||||
event = ifr.contentDocument.createEvent("Events");
|
||||
event.initEvent("foo", true, true);
|
||||
xhr.dispatchEvent(event);
|
||||
is(eventCount, 2,
|
||||
"Shouldn't have handled an event because the context has changed");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
ifr.contentWindow.location = "about:blank";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -91,14 +91,13 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
nsGlobalWindow* win =
|
||||
aIsJSImplementedWebIDL ? nullptr : xpc::WindowGlobalOrNull(realCallback);
|
||||
if (win) {
|
||||
// Make sure that if this is a window it's the current inner, since the
|
||||
// nsIScriptContext and hence JSContext are associated with the outer
|
||||
// window. Which means that if someone holds on to a function from a
|
||||
// now-unloaded document we'd have the new document as the script entry
|
||||
// point...
|
||||
// Make sure that if this is a window it has an active document, since
|
||||
// the nsIScriptContext and hence JSContext are associated with the
|
||||
// outer window. Which means that if someone holds on to a function
|
||||
// from a now-unloaded document we'd have the new document as the
|
||||
// script entry point...
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
nsPIDOMWindow* outer = win->GetOuterWindow();
|
||||
if (!outer || win != outer->GetCurrentInnerWindow()) {
|
||||
if (!win->HasActiveDocument()) {
|
||||
// Just bail out from here
|
||||
return;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ skip-if = debug == false
|
||||
[test_bug1041646.html]
|
||||
[test_bug1123875.html]
|
||||
[test_barewordGetsWindow.html]
|
||||
[test_callback_across_document_open.html]
|
||||
[test_callback_default_thisval.html]
|
||||
[test_cloneAndImportNode.html]
|
||||
[test_defineProperty.html]
|
||||
|
21
dom/bindings/test/test_callback_across_document_open.html
Normal file
21
dom/bindings/test/test_callback_across_document_open.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test for callback invocation for a callback that comes from a
|
||||
no-longer-current window that still has an active document.</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<iframe srcdoc='<script>function f() { parent.callCount++; }</script>'></iframe>
|
||||
<script>
|
||||
var callCount = 0;
|
||||
var t = async_test("A test of callback invocation in a no-longer-current window with a still-active document");
|
||||
window.addEventListener("load", t.step_func_done(function() {
|
||||
var d = document.createElement("div");
|
||||
d.addEventListener("xyz", frames[0].f);
|
||||
frames[0].document.open();
|
||||
frames[0].document.write("All gone");
|
||||
frames[0].document.close();
|
||||
d.dispatchEvent(new Event("xyz"));
|
||||
assert_equals(callCount, 1, "Callback should have been called");
|
||||
}));
|
||||
</script>
|
@ -1195,8 +1195,41 @@ DataStoreService::CheckPermission(nsIPrincipal* aPrincipal)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only support DataStore API for certified apps for now.
|
||||
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
// Certified apps are always allowed.
|
||||
if (status == nsIPrincipal::APP_STATUS_CERTIFIED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (status != nsIPrincipal::APP_STATUS_PRIVILEGED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Privileged apps are allowed if they are the homescreen.
|
||||
nsAdoptingString homescreen =
|
||||
Preferences::GetString("dom.mozApps.homescreenURL");
|
||||
if (!homescreen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t appId;
|
||||
nsresult rv = aPrincipal->GetAppId(&appId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService =
|
||||
do_GetService("@mozilla.org/AppsService;1");
|
||||
if (NS_WARN_IF(!appsService)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString manifestURL;
|
||||
rv = appsService->GetManifestURLByLocalId(appId, manifestURL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return manifestURL.Equals(homescreen);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -111,7 +111,10 @@ function tests() {
|
||||
// Release.
|
||||
sendMouseEvent("mouseup", label);
|
||||
yield undefined;
|
||||
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
|
||||
var focusOnMouse = (navigator.platform.indexOf("Mac") != 0);
|
||||
compareSnapshots_(focusOnMouse ? normalFocusedButtonCanvas : normalButtonCanvas,
|
||||
currentSnapshot, true, "Releasing the mouse over the label should have unpressed" +
|
||||
(focusOnMouse ? " (and focused)" : "") + " the button.");
|
||||
// Press the label and remove it.
|
||||
sendMouseEvent("mousemove", label);
|
||||
sendMouseEvent("mousedown", label);
|
||||
|
@ -127,7 +127,10 @@ function tests() {
|
||||
// Release.
|
||||
sendMouseEvent("mouseup", label);
|
||||
yield undefined;
|
||||
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
|
||||
var focusOnMouse = (navigator.platform.indexOf("Mac") != 0);
|
||||
compareSnapshots_(focusOnMouse ? normalFocusedButtonCanvas : normalButtonCanvas,
|
||||
currentSnapshot, true, "Releasing the mouse over the label should have unpressed" +
|
||||
(focusOnMouse ? " (and focused)" : "") + " the button.");
|
||||
// Press the label and remove it.
|
||||
sendMouseEvent("mousemove", label);
|
||||
sendMouseEvent("mousedown", label);
|
||||
|
@ -169,8 +169,14 @@ HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
// be selected only when focused via a key or when the navigation
|
||||
// flag is used and we want to select the text on label clicks as
|
||||
// well.
|
||||
// If the label has been clicked by the user, we also want to
|
||||
// pass FLAG_BYMOUSE so that we get correct focus ring behavior,
|
||||
// but we don't want to pass FLAG_BYMOUSE if this click event was
|
||||
// caused by the user pressing an accesskey.
|
||||
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content);
|
||||
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS);
|
||||
bool byMouse = (mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD);
|
||||
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS |
|
||||
(byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0));
|
||||
}
|
||||
}
|
||||
// Dispatch a new click event to |content|
|
||||
|
@ -72,11 +72,29 @@ const ACTION_FUNCS = [
|
||||
}
|
||||
];
|
||||
|
||||
const DISABLE_LIST = [
|
||||
// Bug 1180574
|
||||
{ openWinFunc: "openNewWindow",
|
||||
actionFunc: "navigate",
|
||||
platform: "Linux i686" }
|
||||
];
|
||||
|
||||
function* testGenerator() {
|
||||
for (var openWinFunc of OPEN_WINDOW_FUNCS) {
|
||||
for (var actionFunc of ACTION_FUNCS) {
|
||||
info(`Testing ${openWinFunc.name}, ${actionFunc.name}`);
|
||||
yield { openWinFunc: openWinFunc, actionFunc: actionFunc };
|
||||
var skipTest = false;
|
||||
for (var disabledItem of DISABLE_LIST) {
|
||||
if (openWinFunc.name == disabledItem.openWinFunc &&
|
||||
actionFunc.name == disabledItem.actionFunc &&
|
||||
navigator.platform == disabledItem.platform) {
|
||||
skipTest = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!skipTest) {
|
||||
info(`Testing ${openWinFunc.name}, ${actionFunc.name}`);
|
||||
yield { openWinFunc: openWinFunc, actionFunc: actionFunc };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -732,7 +732,7 @@ parent:
|
||||
|
||||
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
|
||||
|
||||
sync GetRandomValues(uint32_t length)
|
||||
prio(urgent) sync GetRandomValues(uint32_t length)
|
||||
returns (uint8_t[] randomValues);
|
||||
|
||||
async GetSystemMemory(uint64_t getterId);
|
||||
|
@ -11,112 +11,82 @@
|
||||
*
|
||||
* BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
|
||||
*/
|
||||
/*globals content, sendAsyncMessage, addMessageListener, Components*/
|
||||
/*globals Task, ManifestObtainer, ManifestFinder, content, sendAsyncMessage, addMessageListener, Components*/
|
||||
'use strict';
|
||||
const {
|
||||
utils: Cu,
|
||||
classes: Cc,
|
||||
interfaces: Ci
|
||||
} = Components;
|
||||
const {
|
||||
ManifestProcessor
|
||||
} = Cu.import('resource://gre/modules/WebManifest.jsm', {});
|
||||
const {
|
||||
Task: {
|
||||
spawn, async
|
||||
}
|
||||
} = Components.utils.import('resource://gre/modules/Task.jsm', {});
|
||||
Cu.import('resource://gre/modules/ManifestObtainer.jsm');
|
||||
Cu.import('resource://gre/modules/ManifestFinder.jsm');
|
||||
Cu.import('resource://gre/modules/Task.jsm');
|
||||
|
||||
addMessageListener('DOM:ManifestObtainer:Obtain', async(function* (aMsg) {
|
||||
const response = {
|
||||
msgId: aMsg.data.msgId,
|
||||
success: true,
|
||||
result: undefined
|
||||
};
|
||||
try {
|
||||
response.result = yield fetchManifest();
|
||||
} catch (err) {
|
||||
response.success = false;
|
||||
response.result = cloneError(err);
|
||||
}
|
||||
sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
|
||||
}));
|
||||
const finder = new ManifestFinder();
|
||||
|
||||
function cloneError(aError) {
|
||||
const clone = {
|
||||
'fileName': String(aError.fileName),
|
||||
'lineNumber': String(aError.lineNumber),
|
||||
'columnNumber': String(aError.columnNumber),
|
||||
'stack': String(aError.stack),
|
||||
'message': String(aError.message),
|
||||
'name': String(aError.name)
|
||||
};
|
||||
return clone;
|
||||
}
|
||||
const MessageHandler = {
|
||||
registerListeners() {
|
||||
addMessageListener(
|
||||
'DOM:WebManifest:hasManifestLink',
|
||||
this.hasManifestLink.bind(this)
|
||||
);
|
||||
addMessageListener(
|
||||
'DOM:ManifestObtainer:Obtain',
|
||||
this.obtainManifest.bind(this)
|
||||
);
|
||||
},
|
||||
|
||||
function fetchManifest() {
|
||||
return spawn(function* () {
|
||||
if (!content || content.top !== content) {
|
||||
let msg = 'Content window must be a top-level browsing context.';
|
||||
throw new Error(msg);
|
||||
/**
|
||||
* Check if the content document includes a link to a web manifest.
|
||||
* @param {Object} aMsg The IPC message.
|
||||
*/
|
||||
hasManifestLink: Task.async(function* ({data: {id}}) {
|
||||
const response = this.makeMsgResponse(id);
|
||||
response.result = yield finder.hasManifestLink(content);
|
||||
response.success = true;
|
||||
sendAsyncMessage('DOM:WebManifest:hasManifestLink', response);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Obtains a web manifest from content by using the ManifestObtainer
|
||||
* and messages back the result.
|
||||
* @param {Object} aMsg The IPC message.
|
||||
*/
|
||||
obtainManifest: Task.async(function* ({data: {id}}) {
|
||||
const obtainer = new ManifestObtainer();
|
||||
const response = this.makeMsgResponse(id);
|
||||
try {
|
||||
response.result = yield obtainer.obtainManifest(content);
|
||||
response.success = true;
|
||||
} catch (err) {
|
||||
response.result = this.serializeError(err);
|
||||
}
|
||||
const elem = content.document.querySelector('link[rel~="manifest"]');
|
||||
if (!elem || !elem.getAttribute('href')) {
|
||||
let msg = 'No manifest to fetch.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
// Throws on malformed URLs
|
||||
const manifestURL = new content.URL(elem.href, elem.baseURI);
|
||||
if (!canLoadManifest(elem)) {
|
||||
let msg = `Content Security Policy: The page's settings blocked the `;
|
||||
msg += `loading of a resource at ${elem.href}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
const reqInit = {
|
||||
mode: 'cors'
|
||||
sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
|
||||
}),
|
||||
|
||||
makeMsgResponse(aId) {
|
||||
return {
|
||||
id: aId,
|
||||
success: false,
|
||||
result: undefined
|
||||
};
|
||||
if (elem.crossOrigin === 'use-credentials') {
|
||||
reqInit.credentials = 'include';
|
||||
}
|
||||
const req = new content.Request(manifestURL, reqInit);
|
||||
req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST);
|
||||
const response = yield content.fetch(req);
|
||||
const manifest = yield processResponse(response, content);
|
||||
return manifest;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
function canLoadManifest(aElem) {
|
||||
const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
|
||||
.getService(Ci.nsIContentPolicy);
|
||||
const mimeType = aElem.type || 'application/manifest+json';
|
||||
const elemURI = BrowserUtils.makeURI(
|
||||
aElem.href, aElem.ownerDocument.characterSet
|
||||
);
|
||||
const shouldLoad = contentPolicy.shouldLoad(
|
||||
Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
|
||||
aElem.ownerDocument.documentURIObject,
|
||||
aElem, mimeType, null
|
||||
);
|
||||
return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
|
||||
}
|
||||
|
||||
function processResponse(aResp, aContentWindow) {
|
||||
return spawn(function* () {
|
||||
const badStatus = aResp.status < 200 || aResp.status >= 300;
|
||||
if (aResp.type === 'error' || badStatus) {
|
||||
let msg =
|
||||
`Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
const text = yield aResp.text();
|
||||
const args = {
|
||||
jsonText: text,
|
||||
manifestURL: aResp.url,
|
||||
docURL: aContentWindow.location.href
|
||||
/**
|
||||
* Utility function to Serializes an JS Error, so it can be transferred over
|
||||
* the message channel.
|
||||
* FIX ME: https://bugzilla.mozilla.org/show_bug.cgi?id=1172586
|
||||
* @param {Error} aError The error to serialize.
|
||||
* @return {Object} The serialized object.
|
||||
*/
|
||||
serializeError(aError) {
|
||||
const clone = {
|
||||
'fileName': aError.fileName,
|
||||
'lineNumber': aError.lineNumber,
|
||||
'columnNumber': aError.columnNumber,
|
||||
'stack': aError.stack,
|
||||
'message': aError.message,
|
||||
'name': aError.name
|
||||
};
|
||||
const processor = new ManifestProcessor();
|
||||
const manifest = processor.process(args);
|
||||
return Cu.cloneInto(manifest, content);
|
||||
});
|
||||
}
|
||||
return clone;
|
||||
},
|
||||
};
|
||||
MessageHandler.registerListeners();
|
||||
|
58
dom/manifest/ManifestFinder.jsm
Normal file
58
dom/manifest/ManifestFinder.jsm
Normal file
@ -0,0 +1,58 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
/* globals Components, Task, PromiseMessage */
|
||||
'use strict';
|
||||
const {
|
||||
utils: Cu
|
||||
} = Components;
|
||||
Cu.import('resource://gre/modules/PromiseMessage.jsm');
|
||||
Cu.import('resource://gre/modules/Task.jsm');
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function ManifestFinder() {}
|
||||
|
||||
/**
|
||||
* checks if a browser window's document has a conforming
|
||||
* manifest link relationship.
|
||||
* @param aWindowOrBrowser the XUL browser or window to check.
|
||||
* @return {Promise}
|
||||
*/
|
||||
ManifestFinder.prototype.hasManifestLink = Task.async(
|
||||
function* (aWindowOrBrowser) {
|
||||
const msgKey = 'DOM:WebManifest:hasManifestLink';
|
||||
if (!(aWindowOrBrowser && (aWindowOrBrowser.namespaceURI || aWindowOrBrowser.location))) {
|
||||
throw new TypeError('Invalid input.');
|
||||
}
|
||||
if (isXULBrowser(aWindowOrBrowser)) {
|
||||
const mm = aWindowOrBrowser.messageManager;
|
||||
const reply = yield PromiseMessage.send(mm, msgKey);
|
||||
return reply.data.result;
|
||||
}
|
||||
return checkForManifest(aWindowOrBrowser);
|
||||
}
|
||||
);
|
||||
|
||||
function isXULBrowser(aBrowser) {
|
||||
const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
|
||||
return (aBrowser.namespaceURI && aBrowser.namespaceURI === XUL);
|
||||
}
|
||||
|
||||
function checkForManifest(aWindow) {
|
||||
// Only top-level browsing contexts are valid.
|
||||
if (!aWindow || aWindow.top !== aWindow) {
|
||||
return false;
|
||||
}
|
||||
const elem = aWindow.document.querySelector('link[rel~="manifest"]');
|
||||
// Only if we have an element and a non-empty href attribute.
|
||||
if (!elem || !elem.getAttribute('href')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ // jshint ignore:line
|
||||
'ManifestFinder'
|
||||
];
|
@ -1,92 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* ManifestObtainer is an implementation of:
|
||||
* http://w3c.github.io/manifest/#obtaining
|
||||
*
|
||||
* Exposes public method `.obtainManifest(browserWindow)`, which returns
|
||||
* a promise. If successful, you get back a manifest (string).
|
||||
*
|
||||
* For e10s compat, this JSM relies on the following to do
|
||||
* the nessesary IPC:
|
||||
* dom/ipc/manifestMessages.js
|
||||
*
|
||||
* whose internal URL is:
|
||||
* 'chrome://global/content/manifestMessages.js'
|
||||
*
|
||||
* Which is injected into every browser instance via browser.js.
|
||||
*
|
||||
* BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
|
||||
* exported ManifestObtainer
|
||||
*/
|
||||
'use strict';
|
||||
const MSG_KEY = 'DOM:ManifestObtainer:Obtain';
|
||||
let messageCounter = 0;
|
||||
// FIXME: Ideally, we would store a reference to the
|
||||
// message manager in a weakmap instead of needing a
|
||||
// browserMap. However, trying to store a messageManager
|
||||
// results in a TypeError because of:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=888600
|
||||
const browsersMap = new WeakMap();
|
||||
|
||||
function ManifestObtainer() {}
|
||||
|
||||
ManifestObtainer.prototype = {
|
||||
obtainManifest(aBrowserWindow) {
|
||||
if (!aBrowserWindow) {
|
||||
const err = new TypeError('Invalid input. Expected xul browser.');
|
||||
return Promise.reject(err);
|
||||
}
|
||||
const mm = aBrowserWindow.messageManager;
|
||||
const onMessage = function(aMsg) {
|
||||
const msgId = aMsg.data.msgId;
|
||||
const {
|
||||
resolve, reject
|
||||
} = browsersMap.get(aBrowserWindow).get(msgId);
|
||||
browsersMap.get(aBrowserWindow).delete(msgId);
|
||||
// If we we've processed all messages,
|
||||
// stop listening.
|
||||
if (!browsersMap.get(aBrowserWindow).size) {
|
||||
browsersMap.delete(aBrowserWindow);
|
||||
mm.removeMessageListener(MSG_KEY, onMessage);
|
||||
}
|
||||
if (aMsg.data.success) {
|
||||
return resolve(aMsg.data.result);
|
||||
}
|
||||
reject(toError(aMsg.data.result));
|
||||
};
|
||||
// If we are not already listening for messages
|
||||
// start listening.
|
||||
if (!browsersMap.has(aBrowserWindow)) {
|
||||
browsersMap.set(aBrowserWindow, new Map());
|
||||
mm.addMessageListener(MSG_KEY, onMessage);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const msgId = messageCounter++;
|
||||
browsersMap.get(aBrowserWindow).set(msgId, {
|
||||
resolve: resolve,
|
||||
reject: reject
|
||||
});
|
||||
mm.sendAsyncMessage(MSG_KEY, {
|
||||
msgId: msgId
|
||||
});
|
||||
});
|
||||
|
||||
function toError(aErrorClone) {
|
||||
let error;
|
||||
switch (aErrorClone.name) {
|
||||
case 'TypeError':
|
||||
error = new TypeError();
|
||||
break;
|
||||
default:
|
||||
error = new Error();
|
||||
}
|
||||
Object.getOwnPropertyNames(aErrorClone)
|
||||
.forEach(name => error[name] = aErrorClone[name]);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
};
|
||||
this.ManifestObtainer = ManifestObtainer; // jshint ignore:line
|
||||
this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line
|
170
dom/manifest/ManifestObtainer.jsm
Normal file
170
dom/manifest/ManifestObtainer.jsm
Normal file
@ -0,0 +1,170 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/*
|
||||
* ManifestObtainer is an implementation of:
|
||||
* http://w3c.github.io/manifest/#obtaining
|
||||
*
|
||||
* Exposes public method `.obtainManifest(Window)`, which returns
|
||||
* a promise. If successful, you get back a manifest object.
|
||||
*
|
||||
* Import it with URL:
|
||||
* 'chrome://global/content/manifestMessages.js'
|
||||
*
|
||||
* e10s IPC messaage from this components are handled by:
|
||||
* dom/ipc/manifestMessages.js
|
||||
*
|
||||
* Which is injected into every browser instance via browser.js.
|
||||
*
|
||||
* exported ManifestObtainer
|
||||
*/
|
||||
/*globals Components, Task, PromiseMessage, XPCOMUtils, ManifestProcessor, BrowserUtils*/
|
||||
'use strict';
|
||||
const {
|
||||
utils: Cu,
|
||||
classes: Cc,
|
||||
interfaces: Ci
|
||||
} = Components;
|
||||
Cu.import('resource://gre/modules/Task.jsm');
|
||||
Cu.import('resource://gre/modules/PromiseMessage.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/ManifestProcessor.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUtils', // jshint ignore:line
|
||||
'resource://gre/modules/BrowserUtils.jsm');
|
||||
|
||||
const processor = new ManifestProcessor();
|
||||
|
||||
/**
|
||||
* Asynchronously processes the result of response after having fetched
|
||||
* a manifest.
|
||||
* @param {Response} aResp Response from fetch().
|
||||
* @param {Window} aContentWindow The content window.
|
||||
* @return {Promise<Object>} The processed manifest.
|
||||
*/
|
||||
const processResponse = Task.async(function* (aResp, aContentWindow) {
|
||||
const badStatus = aResp.status < 200 || aResp.status >= 300;
|
||||
if (aResp.type === 'error' || badStatus) {
|
||||
const msg =
|
||||
`Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
const text = yield aResp.text();
|
||||
const args = {
|
||||
jsonText: text,
|
||||
manifestURL: aResp.url,
|
||||
docURL: aContentWindow.location.href
|
||||
};
|
||||
const manifest = processor.process(args);
|
||||
return manifest;
|
||||
});
|
||||
|
||||
/**
|
||||
* Asynchronously fetches a web manifest.
|
||||
* @param {Window} a The content Window from where to extract the manifest.
|
||||
* @return {Promise<Object>}
|
||||
*/
|
||||
const fetchManifest = Task.async(function* (aWindow) {
|
||||
if (!aWindow || aWindow.top !== aWindow) {
|
||||
let msg = 'Window must be a top-level browsing context.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
const elem = aWindow.document.querySelector('link[rel~="manifest"]');
|
||||
if (!elem || !elem.getAttribute('href')) {
|
||||
let msg = `No manifest to fetch at ${aWindow.location}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
// Throws on malformed URLs
|
||||
const manifestURL = new aWindow.URL(elem.href, elem.baseURI);
|
||||
if (!canLoadManifest(elem)) {
|
||||
let msg = `Content Security Policy: The page's settings blocked the `;
|
||||
msg += `loading of a resource at ${elem.href}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
const reqInit = {
|
||||
mode: 'cors'
|
||||
};
|
||||
if (elem.crossOrigin === 'use-credentials') {
|
||||
reqInit.credentials = 'include';
|
||||
}
|
||||
const req = new aWindow.Request(manifestURL, reqInit);
|
||||
req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST);
|
||||
const response = yield aWindow.fetch(req);
|
||||
const manifest = yield processResponse(response, aWindow);
|
||||
return manifest;
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks against security manager if we can load the web manifest.
|
||||
* @param {HTMLLinkElement} aElem The HTML element to security check.
|
||||
* @return {Boolean} True if it can, false if it can't.
|
||||
*/
|
||||
function canLoadManifest(aElem) {
|
||||
const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
|
||||
.getService(Ci.nsIContentPolicy);
|
||||
const mimeType = aElem.type || 'application/manifest+json';
|
||||
const elemURI = BrowserUtils.makeURI(
|
||||
aElem.href, aElem.ownerDocument.characterSet
|
||||
);
|
||||
const shouldLoad = contentPolicy.shouldLoad(
|
||||
Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
|
||||
aElem.ownerDocument.documentURIObject,
|
||||
aElem, mimeType, null
|
||||
);
|
||||
return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManifestObtainer
|
||||
* @constructor
|
||||
*/
|
||||
function ManifestObtainer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Public interface for obtaining a web manifest.
|
||||
* @param {XULWindow or DOMWindow} aWindow The Window from which to fetch
|
||||
* the manifest.
|
||||
* @return {Promise<Object>} The processed manifest.
|
||||
*/
|
||||
ManifestObtainer.prototype.obtainManifest = Task.async(
|
||||
function* (aWindowOrBrowser) {
|
||||
const msgKey = 'DOM:ManifestObtainer:Obtain';
|
||||
if (!(aWindowOrBrowser && (aWindowOrBrowser.namespaceURI || aWindowOrBrowser.location))) {
|
||||
throw new TypeError('Invalid input.');
|
||||
}
|
||||
if (isXULBrowser(aWindowOrBrowser)) {
|
||||
const mm = aWindowOrBrowser.messageManager;
|
||||
const {data: {success, result}} = yield PromiseMessage.send(mm, msgKey);
|
||||
if (!success) {
|
||||
const error = toError(result);
|
||||
throw error;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const manifest = yield fetchManifest(aWindowOrBrowser);
|
||||
return manifest;
|
||||
}
|
||||
);
|
||||
|
||||
function toError(aErrorClone) {
|
||||
let error;
|
||||
switch (aErrorClone.name) {
|
||||
case 'TypeError':
|
||||
error = new TypeError();
|
||||
break;
|
||||
default:
|
||||
error = new Error();
|
||||
}
|
||||
Object.getOwnPropertyNames(aErrorClone)
|
||||
.forEach(name => error[name] = aErrorClone[name]);
|
||||
return error;
|
||||
}
|
||||
|
||||
function isXULBrowser(aBrowser) {
|
||||
const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
|
||||
return (aBrowser.namespaceURI && aBrowser.namespaceURI === XUL);
|
||||
}
|
||||
|
||||
this.ManifestObtainer = ManifestObtainer; // jshint ignore:line
|
||||
this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line
|
@ -19,12 +19,10 @@
|
||||
* TODO: The constructor should accept the UA's supported display modes.
|
||||
* TODO: hook up developer tools to console. (1086997).
|
||||
*/
|
||||
/*globals Components*/
|
||||
/*globals Components, ValueExtractor, ImageObjectProcessor, ConsoleAPI*/
|
||||
'use strict';
|
||||
const {
|
||||
utils: Cu,
|
||||
interfaces: Ci,
|
||||
classes: Cc
|
||||
utils: Cu
|
||||
} = Components;
|
||||
Cu.importGlobalProperties(['URL']);
|
||||
const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
|
||||
@ -34,18 +32,12 @@ const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait',
|
||||
'portrait-primary', 'portrait-secondary', 'landscape-primary',
|
||||
'landscape-secondary'
|
||||
]);
|
||||
const {
|
||||
ConsoleAPI
|
||||
} = Cu.import('resource://gre/modules/devtools/Console.jsm', {});
|
||||
Cu.import('resource://gre/modules/devtools/Console.jsm');
|
||||
// ValueExtractor is used by the various processors to get values
|
||||
// from the manifest and to report errors.
|
||||
const {
|
||||
ValueExtractor
|
||||
} = Cu.import('resource://gre/modules/ValueExtractor.js', {});
|
||||
Cu.import('resource://gre/modules/ValueExtractor.jsm');
|
||||
// ImageObjectProcessor is used to process things like icons and images
|
||||
const {
|
||||
ImageObjectProcessor
|
||||
} = Cu.import('resource://gre/modules/ImageObjectProcessor.js', {});
|
||||
Cu.import('resource://gre/modules/ImageObjectProcessor.jsm');
|
||||
|
||||
function ManifestProcessor() {}
|
||||
|
@ -25,9 +25,7 @@ ValueExtractor.prototype = {
|
||||
// objectName: string used to construct the developer warning.
|
||||
// property: the name of the property being extracted.
|
||||
// trim: boolean, if the value should be trimmed (used by string type).
|
||||
extractValue({
|
||||
expectedType, object, objectName, property, trim
|
||||
}) {
|
||||
extractValue({expectedType, object, objectName, property, trim}) {
|
||||
const value = object[property];
|
||||
const isArray = Array.isArray(value);
|
||||
// We need to special-case "array", as it's not a JS primitive.
|
@ -1,19 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
/*exported EXPORTED_SYMBOLS, ManifestProcessor, ManifestObtainer*/
|
||||
/*globals Components */
|
||||
'use strict';
|
||||
const {
|
||||
utils: Cu
|
||||
} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
'ManifestObtainer',
|
||||
'ManifestProcessor'
|
||||
];
|
||||
|
||||
// Export public interfaces
|
||||
for (let symbl of EXPORTED_SYMBOLS) {
|
||||
Cu.import(`resource://gre/modules/${symbl}.js`);
|
||||
}
|
@ -5,11 +5,11 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ImageObjectProcessor.js',
|
||||
'ManifestObtainer.js',
|
||||
'ManifestProcessor.js',
|
||||
'ValueExtractor.js',
|
||||
'WebManifest.jsm'
|
||||
'ImageObjectProcessor.jsm',
|
||||
'ManifestFinder.jsm',
|
||||
'ManifestObtainer.jsm',
|
||||
'ManifestProcessor.jsm',
|
||||
'ValueExtractor.jsm',
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
@ -1,2 +1,3 @@
|
||||
[DEFAULT]
|
||||
[browser_ManifestObtainer_obtain.js]
|
||||
[browser_hasManifestLink.js]
|
||||
[browser_ManifestObtainer_obtain.js]
|
||||
|
@ -3,7 +3,7 @@
|
||||
'use strict';
|
||||
const {
|
||||
ManifestObtainer
|
||||
} = Cu.import('resource://gre/modules/WebManifest.jsm', {});
|
||||
} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', {});
|
||||
|
||||
requestLongerTimeout(4); // e10s tests take time.
|
||||
const defaultURL =
|
||||
|
109
dom/manifest/test/browser_hasManifestLink.js
Normal file
109
dom/manifest/test/browser_hasManifestLink.js
Normal file
@ -0,0 +1,109 @@
|
||||
//Used by JSHint:
|
||||
/*global Cu, BrowserTestUtils, is, ok, add_task, gBrowser, ManifestFinder */
|
||||
'use strict';
|
||||
Cu.import('resource://gre/modules/ManifestFinder.jsm', this); // jshint ignore:line
|
||||
|
||||
const finder = new ManifestFinder();
|
||||
const defaultURL =
|
||||
'http://example.org/tests/dom/manifest/test/resource.sjs';
|
||||
const tests = [{
|
||||
expected: 'Document has a web manifest.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, true, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>
|
||||
<link rel="foo bar manifest bar test" href='${defaultURL}?body={"name":"value"}'>
|
||||
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}, {
|
||||
expected: 'Document does not have a web manifest.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, false, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="amanifista" href='${defaultURL}?body={"name":"fail"}'>
|
||||
<link rel="foo bar manifesto bar test" href='${defaultURL}?body={"name":"pass-1"}'>
|
||||
<link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}, {
|
||||
expected: 'Manifest link is has empty href.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, false, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="manifest" href="">
|
||||
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}, {
|
||||
expected: 'Manifest link is missing.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, false, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="manifest">
|
||||
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}];
|
||||
|
||||
/**
|
||||
* Test basic API error conditions
|
||||
*/
|
||||
add_task(function* () {
|
||||
let expected = 'Invalid types should throw a TypeError.';
|
||||
for (let invalidValue of [undefined, null, 1, {}, 'test']) {
|
||||
try {
|
||||
yield finder.hasManifestLink(invalidValue);
|
||||
ok(false, expected);
|
||||
} catch (e) {
|
||||
is(e.name, 'TypeError', expected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let test of tests) {
|
||||
let tabOptions = {
|
||||
gBrowser: gBrowser,
|
||||
url: test.tabURL,
|
||||
};
|
||||
yield BrowserTestUtils.withNewTab(
|
||||
tabOptions,
|
||||
browser => testHasManifest(browser, test)
|
||||
);
|
||||
}
|
||||
|
||||
function* testHasManifest(aBrowser, aTest) {
|
||||
aBrowser.contentWindowAsCPOW.document.head.innerHTML = aTest.testData;
|
||||
const result = yield finder.hasManifestLink(aBrowser);
|
||||
aTest.run(result);
|
||||
}
|
||||
});
|
@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Common infrastructure for manifest tests.
|
||||
**/
|
||||
|
||||
/*globals SpecialPowers, ManifestProcessor*/
|
||||
'use strict';
|
||||
const {
|
||||
ManifestProcessor
|
||||
} = SpecialPowers.Cu.import('resource://gre/modules/WebManifest.jsm');
|
||||
} = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.jsm');
|
||||
const processor = new ManifestProcessor();
|
||||
const manifestURL = new URL(document.location.origin + '/manifest.json');
|
||||
const docURL = document.location;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "mozilla/Snprintf.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "soundtouch/SoundTouch.h"
|
||||
#include "Latency.h"
|
||||
#include "CubebUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
@ -130,6 +129,7 @@ AudioStream::AudioStream()
|
||||
, mOutChannels(0)
|
||||
, mWritten(0)
|
||||
, mAudioClock(this)
|
||||
, mTimeStretcher(nullptr)
|
||||
, mLatencyRequest(HighLatency)
|
||||
, mReadPoint(0)
|
||||
, mDumpFile(nullptr)
|
||||
@ -152,6 +152,9 @@ AudioStream::~AudioStream()
|
||||
if (mDumpFile) {
|
||||
fclose(mDumpFile);
|
||||
}
|
||||
if (mTimeStretcher) {
|
||||
soundtouch::destroySoundTouchObj(mTimeStretcher);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -174,7 +177,7 @@ nsresult AudioStream::EnsureTimeStretcherInitializedUnlocked()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
if (!mTimeStretcher) {
|
||||
mTimeStretcher = new soundtouch::SoundTouch();
|
||||
mTimeStretcher = soundtouch::createSoundTouchObj();
|
||||
mTimeStretcher->setSampleRate(mInRate);
|
||||
mTimeStretcher->setChannels(mOutChannels);
|
||||
mTimeStretcher->setPitch(1.0);
|
||||
|
@ -15,10 +15,7 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "CubebUtils.h"
|
||||
|
||||
namespace soundtouch {
|
||||
class SoundTouch;
|
||||
}
|
||||
#include "soundtouch/SoundTouchFactory.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -332,7 +329,7 @@ private:
|
||||
// Number of frames written to the buffers.
|
||||
int64_t mWritten;
|
||||
AudioClock mAudioClock;
|
||||
nsAutoPtr<soundtouch::SoundTouch> mTimeStretcher;
|
||||
soundtouch::SoundTouch* mTimeStretcher;
|
||||
nsRefPtr<AsyncLatencyLogger> mLatencyLog;
|
||||
|
||||
// copy of Latency logger's starting time for offset calculations
|
||||
|
@ -119,6 +119,14 @@ public:
|
||||
return TimeUnit(INT64_MAX);
|
||||
}
|
||||
|
||||
static TimeUnit Invalid() {
|
||||
TimeUnit ret;
|
||||
ret.mValue = CheckedInt64(INT64_MAX);
|
||||
// Force an overflow to render the CheckedInt invalid.
|
||||
ret.mValue += 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t ToMicroseconds() const {
|
||||
return mValue.value();
|
||||
}
|
||||
|
@ -29,6 +29,10 @@ CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
|
||||
return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
|
||||
}
|
||||
|
||||
media::TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate) {
|
||||
return (media::TimeUnit::FromMicroseconds(aFrames) * USECS_PER_S) / aRate;
|
||||
}
|
||||
|
||||
// Converts from microseconds to number of audio frames, given the specified
|
||||
// audio rate.
|
||||
CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {
|
||||
|
@ -127,10 +127,11 @@ media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStr
|
||||
int64_t aDurationUsecs);
|
||||
|
||||
// Converts from number of audio frames (aFrames) to microseconds, given
|
||||
// the specified audio rate (aRate). Stores result in aOutUsecs. Returns true
|
||||
// if the operation succeeded, or false if there was an integer overflow
|
||||
// while calulating the conversion.
|
||||
// the specified audio rate (aRate).
|
||||
CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate);
|
||||
// Converts from number of audio frames (aFrames) TimeUnit, given
|
||||
// the specified audio rate (aRate).
|
||||
media::TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate);
|
||||
|
||||
// Converts from microseconds (aUsecs) to number of audio frames, given the
|
||||
// specified audio rate (aRate). Stores the result in aOutFrames. Returns
|
||||
|
@ -14,3 +14,7 @@ FAIL_ON_WARNINGS = True
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
]
|
||||
|
||||
USE_LIBS += [
|
||||
'lgpllibs',
|
||||
]
|
||||
|
@ -423,7 +423,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
}
|
||||
|
||||
// Get the duration, and report it to the decoder if we have it.
|
||||
Microseconds duration;
|
||||
mp4_demuxer::Microseconds duration;
|
||||
{
|
||||
MonitorAutoLock lock(mDemuxerMonitor);
|
||||
duration = mDemuxer->Duration();
|
||||
@ -561,7 +561,7 @@ MP4Reader::GetDecoderData(TrackType aTrack)
|
||||
return mVideo;
|
||||
}
|
||||
|
||||
Microseconds
|
||||
mp4_demuxer::Microseconds
|
||||
MP4Reader::GetNextKeyframeTime()
|
||||
{
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
@ -596,7 +596,7 @@ MP4Reader::ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
|
||||
// if the time threshold (the current playback position) is after the next
|
||||
// keyframe in the stream. This means we'll only skip frames that we have
|
||||
// no hope of ever playing.
|
||||
Microseconds nextKeyframe = -1;
|
||||
mp4_demuxer::Microseconds nextKeyframe = -1;
|
||||
if (!sDemuxSkipToNextKeyframe ||
|
||||
(nextKeyframe = GetNextKeyframeTime()) == -1) {
|
||||
return aSkipToNextKeyframe;
|
||||
@ -1090,7 +1090,7 @@ MP4Reader::GetBuffered()
|
||||
nsresult rv = resource->GetCachedRanges(ranges);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsTArray<Interval<Microseconds>> timeRanges;
|
||||
nsTArray<Interval<mp4_demuxer::Microseconds>> timeRanges;
|
||||
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
|
||||
for (size_t i = 0; i < timeRanges.Length(); i++) {
|
||||
buffered += media::TimeInterval(
|
||||
|
@ -118,7 +118,7 @@ private:
|
||||
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
|
||||
virtual bool IsWaitingOnCDMResource() override;
|
||||
|
||||
Microseconds GetNextKeyframeTime();
|
||||
mp4_demuxer::Microseconds GetNextKeyframeTime();
|
||||
bool ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
|
||||
|
||||
size_t SizeOfQueue(TrackType aTrack);
|
||||
|
@ -27,7 +27,6 @@ class MediaDataDecoder;
|
||||
class MediaDataDecoderCallback;
|
||||
class FlushableMediaTaskQueue;
|
||||
class CDMProxy;
|
||||
typedef int64_t Microseconds;
|
||||
|
||||
// The PlatformDecoderModule interface is used by the MP4Reader to abstract
|
||||
// access to the H264 and Audio (AAC/MP3) decoders provided by various platforms.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -51,9 +52,10 @@ public:
|
||||
}
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsRefPtr<MediaData> data = mCreator->Create(mSample->mTime,
|
||||
mSample->mDuration,
|
||||
mSample->mOffset);
|
||||
nsRefPtr<MediaData> data =
|
||||
mCreator->Create(media::TimeUnit::FromMicroseconds(mSample->mTime),
|
||||
media::TimeUnit::FromMicroseconds(mSample->mDuration),
|
||||
mSample->mOffset);
|
||||
mCallback->Output(data);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -103,7 +105,7 @@ public:
|
||||
}
|
||||
|
||||
already_AddRefed<MediaData>
|
||||
Create(Microseconds aDTS, Microseconds aDuration, int64_t aOffsetInStream)
|
||||
Create(const media::TimeUnit& aDTS, const media::TimeUnit& aDuration, int64_t aOffsetInStream)
|
||||
{
|
||||
// Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
|
||||
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
|
||||
@ -141,11 +143,11 @@ public:
|
||||
mImageContainer,
|
||||
nullptr,
|
||||
aOffsetInStream,
|
||||
aDTS,
|
||||
aDuration,
|
||||
aDTS.ToMicroseconds(),
|
||||
aDuration.ToMicroseconds(),
|
||||
buffer,
|
||||
true,
|
||||
aDTS,
|
||||
aDTS.ToMicroseconds(),
|
||||
mPicture);
|
||||
}
|
||||
private:
|
||||
@ -164,13 +166,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
MediaData* Create(Microseconds aDTS,
|
||||
Microseconds aDuration,
|
||||
MediaData* Create(const media::TimeUnit& aDTS,
|
||||
const media::TimeUnit& aDuration,
|
||||
int64_t aOffsetInStream)
|
||||
{
|
||||
// Convert duration to frames. We add 1 to duration to account for
|
||||
// rounding errors, so we get a consistent tone.
|
||||
CheckedInt64 frames = UsecsToFrames(aDuration+1, mSampleRate);
|
||||
CheckedInt64 frames =
|
||||
UsecsToFrames(aDuration.ToMicroseconds()+1, mSampleRate);
|
||||
if (!frames.isValid() ||
|
||||
!mChannelCount ||
|
||||
!mSampleRate ||
|
||||
@ -189,8 +192,8 @@ public:
|
||||
mFrameSum++;
|
||||
}
|
||||
return new AudioData(aOffsetInStream,
|
||||
aDTS,
|
||||
aDuration,
|
||||
aDTS.ToMicroseconds(),
|
||||
aDuration.ToMicroseconds(),
|
||||
uint32_t(frames.value()),
|
||||
samples,
|
||||
mChannelCount,
|
||||
|
@ -105,7 +105,8 @@ public:
|
||||
return eglImage;
|
||||
}
|
||||
|
||||
virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, Microseconds aDuration) override {
|
||||
virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat,
|
||||
const media::TimeUnit& aDuration) override {
|
||||
if (!EnsureGLContext()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -168,7 +169,7 @@ public:
|
||||
mImageContainer,
|
||||
offset,
|
||||
presentationTimeUs,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
img,
|
||||
isSync,
|
||||
presentationTimeUs,
|
||||
@ -213,7 +214,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
nsresult Output(BufferInfo::Param aInfo, void* aBuffer, MediaFormat::Param aFormat, Microseconds aDuration) {
|
||||
nsresult Output(BufferInfo::Param aInfo, void* aBuffer,
|
||||
MediaFormat::Param aFormat,
|
||||
const media::TimeUnit& aDuration) {
|
||||
// The output on Android is always 16-bit signed
|
||||
|
||||
nsresult rv;
|
||||
@ -239,7 +242,7 @@ public:
|
||||
NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
|
||||
|
||||
nsRefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
numFrames,
|
||||
audio,
|
||||
numChannels,
|
||||
@ -485,7 +488,7 @@ void MediaCodecDataDecoder::DecoderLoop()
|
||||
sample->mTime, 0);
|
||||
HANDLE_DECODER_ERROR();
|
||||
|
||||
mDurations.push(sample->mDuration);
|
||||
mDurations.push(media::TimeUnit::FromMicroseconds(sample->mDuration));
|
||||
sample = nullptr;
|
||||
outputDone = false;
|
||||
}
|
||||
@ -543,7 +546,7 @@ void MediaCodecDataDecoder::DecoderLoop()
|
||||
|
||||
MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
|
||||
|
||||
Microseconds duration = 0;
|
||||
media::TimeUnit duration;
|
||||
if (!mDurations.empty()) {
|
||||
duration = mDurations.front();
|
||||
mDurations.pop();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "AndroidSurfaceTexture.h"
|
||||
|
||||
#include "MediaCodec.h"
|
||||
#include "TimeUnits.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
#include <queue>
|
||||
@ -81,12 +82,13 @@ protected:
|
||||
bool mStopping;
|
||||
|
||||
SampleQueue mQueue;
|
||||
std::queue<Microseconds> mDurations;
|
||||
// Durations are stored in microseconds.
|
||||
std::queue<media::TimeUnit> mDurations;
|
||||
|
||||
virtual nsresult InitDecoder(widget::sdk::Surface::Param aSurface);
|
||||
|
||||
virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
|
||||
virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
|
||||
virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, const media::TimeUnit& aDuration) { return NS_OK; }
|
||||
virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, const media::TimeUnit& aDuration) { return NS_OK; }
|
||||
virtual void Cleanup() {};
|
||||
|
||||
nsresult ResetInputBuffers();
|
||||
|
@ -261,8 +261,8 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample)
|
||||
|
||||
size_t numFrames = outputData.Length() / channels;
|
||||
int rate = mOutputFormat.mSampleRate;
|
||||
CheckedInt<Microseconds> duration = FramesToUsecs(numFrames, rate);
|
||||
if (!duration.isValid()) {
|
||||
media::TimeUnit duration = FramesToTimeUnit(numFrames, rate);
|
||||
if (!duration.IsValid()) {
|
||||
NS_WARNING("Invalid count of accumulated audio samples");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -270,14 +270,14 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample)
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("pushed audio at time %lfs; duration %lfs\n",
|
||||
(double)aSample->mTime / USECS_PER_S,
|
||||
(double)duration.value() / USECS_PER_S);
|
||||
duration.ToSeconds());
|
||||
#endif
|
||||
|
||||
nsAutoArrayPtr<AudioDataValue> data(new AudioDataValue[outputData.Length()]);
|
||||
PodCopy(data.get(), &outputData[0], outputData.Length());
|
||||
nsRefPtr<AudioData> audio = new AudioData(aSample->mOffset,
|
||||
aSample->mTime,
|
||||
duration.value(),
|
||||
duration.ToMicroseconds(),
|
||||
numFrames,
|
||||
data.forget(),
|
||||
channels,
|
||||
|
@ -195,9 +195,9 @@ PlatformCallback(void* decompressionOutputRefCon,
|
||||
AutoCFRelease<CFNumberRef> kfref =
|
||||
(CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_KEYFRAME"));
|
||||
|
||||
Microseconds dts;
|
||||
Microseconds pts;
|
||||
Microseconds duration;
|
||||
int64_t dts;
|
||||
int64_t pts;
|
||||
int64_t duration;
|
||||
int64_t byte_offset;
|
||||
char is_sync_point;
|
||||
|
||||
@ -208,11 +208,12 @@ PlatformCallback(void* decompressionOutputRefCon,
|
||||
CFNumberGetValue(kfref, kCFNumberSInt8Type, &is_sync_point);
|
||||
|
||||
nsAutoPtr<AppleVDADecoder::AppleFrameRef> frameRef(
|
||||
new AppleVDADecoder::AppleFrameRef(dts,
|
||||
pts,
|
||||
duration,
|
||||
byte_offset,
|
||||
is_sync_point == 1));
|
||||
new AppleVDADecoder::AppleFrameRef(
|
||||
media::TimeUnit::FromMicroseconds(dts),
|
||||
media::TimeUnit::FromMicroseconds(pts),
|
||||
media::TimeUnit::FromMicroseconds(duration),
|
||||
byte_offset,
|
||||
is_sync_point == 1));
|
||||
|
||||
// Forward the data back to an object method which can access
|
||||
// the correct MP4Reader callback.
|
||||
@ -252,9 +253,9 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
|
||||
|
||||
LOG("mp4 output frame %lld dts %lld pts %lld duration %lld us%s",
|
||||
aFrameRef->byte_offset,
|
||||
aFrameRef->decode_timestamp,
|
||||
aFrameRef->composition_timestamp,
|
||||
aFrameRef->duration,
|
||||
aFrameRef->decode_timestamp.ToMicroseconds(),
|
||||
aFrameRef->composition_timestamp.ToMicroseconds(),
|
||||
aFrameRef->duration.ToMicroseconds(),
|
||||
aFrameRef->is_sync_point ? " keyframe" : ""
|
||||
);
|
||||
|
||||
@ -277,10 +278,11 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
|
||||
data = VideoData::CreateFromImage(info,
|
||||
mImageContainer,
|
||||
aFrameRef->byte_offset,
|
||||
aFrameRef->composition_timestamp,
|
||||
aFrameRef->duration, image.forget(),
|
||||
aFrameRef->composition_timestamp.ToMicroseconds(),
|
||||
aFrameRef->duration.ToMicroseconds(),
|
||||
image.forget(),
|
||||
aFrameRef->is_sync_point,
|
||||
aFrameRef->decode_timestamp,
|
||||
aFrameRef->decode_timestamp.ToMicroseconds(),
|
||||
visible);
|
||||
|
||||
if (!data) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "MP4Decoder.h"
|
||||
#include "nsIThread.h"
|
||||
#include "ReorderQueue.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
#include "VideoDecodeAcceleration/VDADecoder.h"
|
||||
|
||||
@ -28,24 +29,24 @@ class AppleVDADecoder : public MediaDataDecoder {
|
||||
public:
|
||||
class AppleFrameRef {
|
||||
public:
|
||||
Microseconds decode_timestamp;
|
||||
Microseconds composition_timestamp;
|
||||
Microseconds duration;
|
||||
media::TimeUnit decode_timestamp;
|
||||
media::TimeUnit composition_timestamp;
|
||||
media::TimeUnit duration;
|
||||
int64_t byte_offset;
|
||||
bool is_sync_point;
|
||||
|
||||
explicit AppleFrameRef(const MediaRawData& aSample)
|
||||
: decode_timestamp(aSample.mTimecode)
|
||||
, composition_timestamp(aSample.mTime)
|
||||
, duration(aSample.mDuration)
|
||||
: decode_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTimecode))
|
||||
, composition_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTime))
|
||||
, duration(media::TimeUnit::FromMicroseconds(aSample.mDuration))
|
||||
, byte_offset(aSample.mOffset)
|
||||
, is_sync_point(aSample.mKeyframe)
|
||||
{
|
||||
}
|
||||
|
||||
AppleFrameRef(Microseconds aDts,
|
||||
Microseconds aPts,
|
||||
Microseconds aDuration,
|
||||
AppleFrameRef(const media::TimeUnit& aDts,
|
||||
const media::TimeUnit& aPts,
|
||||
const media::TimeUnit& aDuration,
|
||||
int64_t aByte_offset,
|
||||
bool aIs_sync_point)
|
||||
: decode_timestamp(aDts)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "FFmpegRuntimeLinker.h"
|
||||
|
||||
#include "FFmpegAudioDecoder.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
#define MAX_CHANNELS 16
|
||||
|
||||
@ -97,7 +98,7 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
|
||||
}
|
||||
|
||||
int64_t samplePosition = aSample->mOffset;
|
||||
Microseconds pts = aSample->mTime;
|
||||
media::TimeUnit pts = media::TimeUnit::FromMicroseconds(aSample->mTime);
|
||||
|
||||
while (packet.size > 0) {
|
||||
int decoded;
|
||||
@ -117,23 +118,28 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
|
||||
nsAutoArrayPtr<AudioDataValue> audio(
|
||||
CopyAndPackAudio(mFrame, numChannels, mFrame->nb_samples));
|
||||
|
||||
CheckedInt<Microseconds> duration =
|
||||
FramesToUsecs(mFrame->nb_samples, samplingRate);
|
||||
if (!duration.isValid()) {
|
||||
media::TimeUnit duration =
|
||||
FramesToTimeUnit(mFrame->nb_samples, samplingRate);
|
||||
if (!duration.IsValid()) {
|
||||
NS_WARNING("Invalid count of accumulated audio samples");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<AudioData> data = new AudioData(samplePosition,
|
||||
pts,
|
||||
duration.value(),
|
||||
pts.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
mFrame->nb_samples,
|
||||
audio.forget(),
|
||||
numChannels,
|
||||
samplingRate);
|
||||
mCallback->Output(data);
|
||||
pts += duration.value();
|
||||
pts += duration;
|
||||
if (!pts.IsValid()) {
|
||||
NS_WARNING("Invalid count of accumulated audio samples");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
packet.data += bytesConsumed;
|
||||
packet.size -= bytesConsumed;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "VideoUtils.h"
|
||||
#include "WMFUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
@ -290,17 +291,18 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
|
||||
|
||||
buffer->Unlock();
|
||||
|
||||
CheckedInt64 timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate);
|
||||
NS_ENSURE_TRUE(timestamp.isValid(), E_FAIL);
|
||||
media::TimeUnit timestamp =
|
||||
FramesToTimeUnit(mAudioFrameOffset + mAudioFrameSum, mAudioRate);
|
||||
NS_ENSURE_TRUE(timestamp.IsValid(), E_FAIL);
|
||||
|
||||
mAudioFrameSum += numFrames;
|
||||
|
||||
CheckedInt64 duration = FramesToUsecs(numFrames, mAudioRate);
|
||||
NS_ENSURE_TRUE(duration.isValid(), E_FAIL);
|
||||
media::TimeUnit duration = FramesToTimeUnit(numFrames, mAudioRate);
|
||||
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
|
||||
|
||||
aOutData = new AudioData(aStreamOffset,
|
||||
timestamp.value(),
|
||||
duration.value(),
|
||||
timestamp.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
numFrames,
|
||||
audioData.forget(),
|
||||
mAudioChannels,
|
||||
@ -308,7 +310,7 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
|
||||
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
|
||||
timestamp, duration, currentLength);
|
||||
timestamp.ToMicroseconds(), duration.ToMicroseconds(), currentLength);
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
|
@ -70,23 +70,23 @@ MFOffsetToInt32(const MFOffset& aOffset)
|
||||
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
|
||||
}
|
||||
|
||||
int64_t
|
||||
media::TimeUnit
|
||||
GetSampleDuration(IMFSample* aSample)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, -1);
|
||||
NS_ENSURE_TRUE(aSample, media::TimeUnit::Invalid());
|
||||
int64_t duration = 0;
|
||||
aSample->GetSampleDuration(&duration);
|
||||
return HNsToUsecs(duration);
|
||||
return media::TimeUnit::FromMicroseconds(HNsToUsecs(duration));
|
||||
}
|
||||
|
||||
int64_t
|
||||
media::TimeUnit
|
||||
GetSampleTime(IMFSample* aSample)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, -1);
|
||||
NS_ENSURE_TRUE(aSample, media::TimeUnit::Invalid());
|
||||
LONGLONG timestampHns = 0;
|
||||
HRESULT hr = aSample->GetSampleTime(×tampHns);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), -1);
|
||||
return HNsToUsecs(timestampHns);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), media::TimeUnit::Invalid());
|
||||
return media::TimeUnit::FromMicroseconds(HNsToUsecs(timestampHns));
|
||||
}
|
||||
|
||||
// Gets the sub-region of the video frame that should be displayed.
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "WMF.h"
|
||||
#include "nsString.h"
|
||||
#include "nsRect.h"
|
||||
#include "TimeUnits.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
// Various utilities shared by WMF backend files.
|
||||
@ -46,14 +47,14 @@ MFOffsetToInt32(const MFOffset& aOffset);
|
||||
HRESULT
|
||||
GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion);
|
||||
|
||||
// Returns the duration of a IMFSample in microseconds.
|
||||
// Returns -1 on failure.
|
||||
int64_t
|
||||
// Returns the duration of a IMFSample in TimeUnit.
|
||||
// Returns media::TimeUnit::Invalid() on failure.
|
||||
media::TimeUnit
|
||||
GetSampleDuration(IMFSample* aSample);
|
||||
|
||||
// Returns the presentation time of a IMFSample in microseconds.
|
||||
// Returns -1 on failure.
|
||||
int64_t
|
||||
// Returns the presentation time of a IMFSample in TimeUnit.
|
||||
// Returns media::TimeUnit::Invalid() on failure.
|
||||
media::TimeUnit
|
||||
GetSampleTime(IMFSample* aSample);
|
||||
|
||||
inline bool
|
||||
|
@ -410,8 +410,10 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
b.mPlanes[2].mOffset = 0;
|
||||
b.mPlanes[2].mSkip = 0;
|
||||
|
||||
Microseconds pts = GetSampleTime(aSample);
|
||||
Microseconds duration = GetSampleDuration(aSample);
|
||||
media::TimeUnit pts = GetSampleTime(aSample);
|
||||
NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
|
||||
media::TimeUnit duration = GetSampleDuration(aSample);
|
||||
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
|
||||
|
||||
nsRefPtr<layers::PlanarYCbCrImage> image =
|
||||
new IMFYCbCrImage(buffer, twoDBuffer);
|
||||
@ -426,8 +428,8 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
VideoData::CreateFromImage(mVideoInfo,
|
||||
mImageContainer,
|
||||
aStreamOffset,
|
||||
std::max(0LL, pts),
|
||||
duration,
|
||||
pts.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
image.forget(),
|
||||
false,
|
||||
-1,
|
||||
@ -458,13 +460,15 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
NS_ENSURE_TRUE(image, E_FAIL);
|
||||
|
||||
Microseconds pts = GetSampleTime(aSample);
|
||||
Microseconds duration = GetSampleDuration(aSample);
|
||||
media::TimeUnit pts = GetSampleTime(aSample);
|
||||
NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
|
||||
media::TimeUnit duration = GetSampleDuration(aSample);
|
||||
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
|
||||
nsRefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo,
|
||||
mImageContainer,
|
||||
aStreamOffset,
|
||||
pts,
|
||||
duration,
|
||||
pts.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
image.forget(),
|
||||
false,
|
||||
-1,
|
||||
|
@ -204,7 +204,7 @@ PluginPRLibrary::NPP_New(NPMIMEType pluginType, NPP instance,
|
||||
|
||||
nsresult
|
||||
PluginPRLibrary::NPP_ClearSiteData(const char* site, uint64_t flags,
|
||||
uint64_t maxAge)
|
||||
uint64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback)
|
||||
{
|
||||
if (!mNPP_ClearSiteData) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
@ -213,39 +213,44 @@ PluginPRLibrary::NPP_ClearSiteData(const char* site, uint64_t flags,
|
||||
MAIN_THREAD_JNI_REF_GUARD;
|
||||
NPError result = mNPP_ClearSiteData(site, flags, maxAge);
|
||||
|
||||
nsresult rv;
|
||||
switch (result) {
|
||||
case NPERR_NO_ERROR:
|
||||
return NS_OK;
|
||||
rv = NS_OK;
|
||||
break;
|
||||
case NPERR_TIME_RANGE_NOT_SUPPORTED:
|
||||
return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
|
||||
rv = NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
|
||||
break;
|
||||
case NPERR_MALFORMED_SITE:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
rv = NS_ERROR_INVALID_ARG;
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
callback->Callback(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginPRLibrary::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
|
||||
PluginPRLibrary::NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback)
|
||||
{
|
||||
if (!mNPP_GetSitesWithData) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
result.Clear();
|
||||
|
||||
MAIN_THREAD_JNI_REF_GUARD;
|
||||
char** sites = mNPP_GetSitesWithData();
|
||||
if (!sites) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
InfallibleTArray<nsCString> result;
|
||||
char** iterator = sites;
|
||||
while (*iterator) {
|
||||
result.AppendElement(*iterator);
|
||||
free(*iterator);
|
||||
++iterator;
|
||||
}
|
||||
callback->SitesWithData(result);
|
||||
free(sites);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -105,8 +105,8 @@ public:
|
||||
NPError* aError) override;
|
||||
|
||||
virtual nsresult NPP_ClearSiteData(const char* aSite, uint64_t aFlags,
|
||||
uint64_t aMaxAge) override;
|
||||
virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& aResult) override;
|
||||
uint64_t aMaxAge, nsCOMPtr<nsIClearSiteDataCallback> callback) override;
|
||||
virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) override;
|
||||
|
||||
virtual nsresult AsyncSetWindow(NPP aInstance, NPWindow* aWindow) override;
|
||||
virtual nsresult GetImageContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override;
|
||||
|
@ -27,7 +27,16 @@ interface nsIPluginPlayPreviewInfo : nsISupports
|
||||
boolean checkWhitelist(in AUTF8String pageURI, in AUTF8String objectURI);
|
||||
};
|
||||
|
||||
[scriptable, uuid(d7d5b2e0-105b-4c9d-8558-b6b31f28b7df)]
|
||||
[scriptable, function, uuid(9c311778-7c2c-4ad8-b439-b8a2786a20dd)]
|
||||
interface nsIClearSiteDataCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* callback with the result from a call to clearSiteData
|
||||
*/
|
||||
void callback(in nsresult rv);
|
||||
};
|
||||
|
||||
[scriptable, uuid(a884e736-5396-4400-bc82-9a23d871d12c)]
|
||||
interface nsIPluginHost : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -77,7 +86,8 @@ interface nsIPluginHost : nsISupports
|
||||
* general or for that particular site and/or flag combination.
|
||||
*/
|
||||
void clearSiteData(in nsIPluginTag plugin, in AUTF8String domain,
|
||||
in uint64_t flags, in int64_t maxAge);
|
||||
in uint64_t flags, in int64_t maxAge,
|
||||
in nsIClearSiteDataCallback callback);
|
||||
|
||||
/*
|
||||
* Determine if a plugin has stored data for a given site.
|
||||
|
@ -1969,7 +1969,7 @@ nsJSNPRuntime::OnPluginDestroy(NPP npp)
|
||||
}
|
||||
|
||||
if (sNPObjWrappers) {
|
||||
for (auto i = sNPObjWrappers->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = sNPObjWrappers->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<NPObjWrapperHashEntry*>(i.Get());
|
||||
|
||||
if (entry->mNpp == npp) {
|
||||
|
@ -1534,10 +1534,77 @@ nsPluginHost::GetPlayPreviewInfo(const nsACString& mimeType,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
#define ClearDataFromSitesClosure_CID {0x9fb21761, 0x2403, 0x41ad, {0x9e, 0xfd, 0x36, 0x7e, 0xc4, 0x4f, 0xa4, 0x5e}}
|
||||
|
||||
|
||||
// Class to hold all the data we need need for IterateMatchesAndClear and ClearDataFromSites
|
||||
class ClearDataFromSitesClosure : public nsIClearSiteDataCallback, public nsIGetSitesWithDataCallback {
|
||||
public:
|
||||
ClearDataFromSitesClosure(nsIPluginTag* plugin, const nsACString& domain, uint64_t flags,
|
||||
int64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback,
|
||||
nsPluginHost* host) :
|
||||
domain(domain), callback(callback), tag(plugin), flags(flags), maxAge(maxAge), host(host) {}
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Callback from NPP_ClearSiteData, continue to iterate the matches and clear
|
||||
NS_IMETHOD Callback(nsresult rv) override {
|
||||
if (NS_FAILED(rv)) {
|
||||
callback->Callback(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
if (!matches.Length()) {
|
||||
callback->Callback(NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsCString match(matches[0]);
|
||||
matches.RemoveElement(match);
|
||||
PluginLibrary* library = static_cast<nsPluginTag*>(tag)->mPlugin->GetLibrary();
|
||||
rv = library->NPP_ClearSiteData(match.get(), flags, maxAge, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
callback->Callback(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Callback from NPP_GetSitesWithData, kick the iteration off to clear the data
|
||||
NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override
|
||||
{
|
||||
// Enumerate the sites and build a list of matches.
|
||||
nsresult rv = host->EnumerateSiteData(domain, sites, matches, false);
|
||||
Callback(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString domain;
|
||||
nsCOMPtr<nsIClearSiteDataCallback> callback;
|
||||
InfallibleTArray<nsCString> matches;
|
||||
nsIPluginTag* tag;
|
||||
uint64_t flags;
|
||||
int64_t maxAge;
|
||||
nsPluginHost* host;
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(ClearDataFromSitesClosure_CID)
|
||||
private:
|
||||
virtual ~ClearDataFromSitesClosure() {}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ClearDataFromSitesClosure, ClearDataFromSitesClosure_CID)
|
||||
|
||||
NS_IMPL_ADDREF(ClearDataFromSitesClosure)
|
||||
NS_IMPL_RELEASE(ClearDataFromSitesClosure)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ClearDataFromSitesClosure)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIClearSiteDataCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIGetSitesWithDataCallback)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClearSiteDataCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
|
||||
uint64_t flags, int64_t maxAge)
|
||||
uint64_t flags, int64_t maxAge, nsIClearSiteDataCallback* callbackFunc)
|
||||
{
|
||||
nsCOMPtr<nsIClearSiteDataCallback> callback(callbackFunc);
|
||||
// maxAge must be either a nonnegative integer or -1.
|
||||
NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
|
||||
|
||||
@ -1569,29 +1636,71 @@ nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
|
||||
|
||||
// If 'domain' is the null string, clear everything.
|
||||
if (domain.IsVoid()) {
|
||||
return library->NPP_ClearSiteData(nullptr, flags, maxAge);
|
||||
return library->NPP_ClearSiteData(nullptr, flags, maxAge, callback);
|
||||
}
|
||||
|
||||
// Get the list of sites from the plugin.
|
||||
InfallibleTArray<nsCString> sites;
|
||||
rv = library->NPP_GetSitesWithData(sites);
|
||||
nsCOMPtr<nsIGetSitesWithDataCallback> closure(new ClearDataFromSitesClosure(plugin, domain, flags,
|
||||
maxAge, callback, this));
|
||||
rv = library->NPP_GetSitesWithData(closure);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Enumerate the sites and build a list of matches.
|
||||
InfallibleTArray<nsCString> matches;
|
||||
rv = EnumerateSiteData(domain, sites, matches, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Clear the matches.
|
||||
for (uint32_t i = 0; i < matches.Length(); ++i) {
|
||||
const nsCString& match = matches[i];
|
||||
rv = library->NPP_ClearSiteData(match.get(), flags, maxAge);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define GetSitesClosure_CID {0x4c9268ac, 0x2fd1, 0x4f2a, {0x9a, 0x10, 0x7a, 0x09, 0xf1, 0xb7, 0x60, 0x3a}}
|
||||
|
||||
// Closure to contain the data needed to handle the callback from NPP_GetSitesWithData
|
||||
class GetSitesClosure : public nsIGetSitesWithDataCallback {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
GetSitesClosure(const nsACString& domain, nsPluginHost* host)
|
||||
: domain(domain), host(host), keepWaiting(true)
|
||||
{
|
||||
}
|
||||
NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override {
|
||||
retVal = HandleGetSites(sites);
|
||||
keepWaiting = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HandleGetSites(InfallibleTArray<nsCString>& sites) {
|
||||
// If there's no data, we're done.
|
||||
if (sites.IsEmpty()) {
|
||||
result = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If 'domain' is the null string, and there's data for at least one site,
|
||||
// we're done.
|
||||
if (domain.IsVoid()) {
|
||||
result = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Enumerate the sites and determine if there's a match.
|
||||
InfallibleTArray<nsCString> matches;
|
||||
nsresult rv = host->EnumerateSiteData(domain, sites, matches, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
result = !matches.IsEmpty();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString domain;
|
||||
nsRefPtr<nsPluginHost> host;
|
||||
bool result;
|
||||
bool keepWaiting;
|
||||
nsresult retVal;
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(GetSitesClosure_CID)
|
||||
private:
|
||||
virtual ~GetSitesClosure() {
|
||||
}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(GetSitesClosure, GetSitesClosure_CID)
|
||||
|
||||
NS_IMPL_ISUPPORTS(GetSitesClosure, GetSitesClosure, nsIGetSitesWithDataCallback)
|
||||
|
||||
// This will spin the event loop while waiting on an async
|
||||
// call to GetSitesWithData
|
||||
NS_IMETHODIMP
|
||||
nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
|
||||
bool* result)
|
||||
@ -1619,31 +1728,16 @@ nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
|
||||
|
||||
PluginLibrary* library = tag->mPlugin->GetLibrary();
|
||||
|
||||
// Get the list of sites from the plugin.
|
||||
InfallibleTArray<nsCString> sites;
|
||||
rv = library->NPP_GetSitesWithData(sites);
|
||||
// Get the list of sites from the plugin
|
||||
nsCOMPtr<GetSitesClosure> closure(new GetSitesClosure(domain, this));
|
||||
rv = library->NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback>(do_QueryInterface(closure)));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If there's no data, we're done.
|
||||
if (sites.IsEmpty()) {
|
||||
*result = false;
|
||||
return NS_OK;
|
||||
// Spin the event loop while we wait for the async call to GetSitesWithData
|
||||
while (closure->keepWaiting) {
|
||||
NS_ProcessNextEvent(nullptr, true);
|
||||
}
|
||||
|
||||
// If 'domain' is the null string, and there's data for at least one site,
|
||||
// we're done.
|
||||
if (domain.IsVoid()) {
|
||||
*result = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Enumerate the sites and determine if there's a match.
|
||||
InfallibleTArray<nsCString> matches;
|
||||
rv = EnumerateSiteData(domain, sites, matches, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*result = !matches.IsEmpty();
|
||||
return NS_OK;
|
||||
*result = closure->result;
|
||||
return closure->retVal;
|
||||
}
|
||||
|
||||
nsPluginHost::SpecialType
|
||||
|
@ -243,6 +243,11 @@ public:
|
||||
|
||||
void CreateWidget(nsPluginInstanceOwner* aOwner);
|
||||
|
||||
nsresult EnumerateSiteData(const nsACString& domain,
|
||||
const InfallibleTArray<nsCString>& sites,
|
||||
InfallibleTArray<nsCString>& result,
|
||||
bool firstMatchOnly);
|
||||
|
||||
private:
|
||||
friend class nsPluginUnloadRunnable;
|
||||
|
||||
@ -366,10 +371,6 @@ private:
|
||||
|
||||
// Helpers for ClearSiteData and SiteHasData.
|
||||
nsresult NormalizeHostname(nsCString& host);
|
||||
nsresult EnumerateSiteData(const nsACString& domain,
|
||||
const InfallibleTArray<nsCString>& sites,
|
||||
InfallibleTArray<nsCString>& result,
|
||||
bool firstMatchOnly);
|
||||
|
||||
nsWeakPtr mCurrentDocument; // weak reference, we use it to id document only
|
||||
|
||||
|
@ -76,11 +76,9 @@ child:
|
||||
returns (bool aURLRedirectNotify, bool aClearSiteData,
|
||||
bool aGetSitesWithData);
|
||||
|
||||
intr NPP_ClearSiteData(nsCString site, uint64_t flags, uint64_t maxAge)
|
||||
returns (NPError rv);
|
||||
async NPP_ClearSiteData(nsCString site, uint64_t flags, uint64_t maxAge, uint64_t aCallbackId);
|
||||
|
||||
intr NPP_GetSitesWithData()
|
||||
returns (nsCString[] sites);
|
||||
async NPP_GetSitesWithData(uint64_t aCallbackId);
|
||||
|
||||
// Windows specific message to set up an audio session in the plugin process
|
||||
async SetAudioSessionData(nsID aID,
|
||||
@ -148,6 +146,12 @@ parent:
|
||||
async NotifyContentModuleDestroyed();
|
||||
|
||||
async Profile(nsCString aProfile);
|
||||
|
||||
// Answers to request about site data
|
||||
async ReturnClearSiteData(NPError aRv, uint64_t aCallbackId);
|
||||
|
||||
async ReturnSitesWithData(nsCString[] aSites, uint64_t aCallbackId);
|
||||
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -28,6 +28,15 @@ class ImageContainer;
|
||||
}
|
||||
}
|
||||
|
||||
class nsIClearSiteDataCallback;
|
||||
|
||||
#define nsIGetSitesWithDataCallback_CID {0xd0028b83, 0xfdf9, 0x4c53, {0xb7, 0xbb, 0x47, 0x46, 0x0f, 0x6b, 0x83, 0x6c}}
|
||||
class nsIGetSitesWithDataCallback : public nsISupports {
|
||||
public:
|
||||
NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& result) = 0;
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(nsIGetSitesWithDataCallback_CID)
|
||||
};
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIGetSitesWithDataCallback, nsIGetSitesWithDataCallback_CID)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -62,8 +71,8 @@ public:
|
||||
NPError* error) = 0;
|
||||
|
||||
virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
|
||||
uint64_t maxAge) = 0;
|
||||
virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& aResult) = 0;
|
||||
uint64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback) = 0;
|
||||
virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) = 0;
|
||||
|
||||
virtual nsresult AsyncSetWindow(NPP instance, NPWindow* window) = 0;
|
||||
virtual nsresult GetImageContainer(NPP instance, mozilla::layers::ImageContainer** aContainer) = 0;
|
||||
|
@ -734,31 +734,34 @@ PluginModuleChild::AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerNPP_ClearSiteData(const nsCString& aSite,
|
||||
PluginModuleChild::RecvNPP_ClearSiteData(const nsCString& aSite,
|
||||
const uint64_t& aFlags,
|
||||
const uint64_t& aMaxAge,
|
||||
NPError* aResult)
|
||||
const uint64_t& aCallbackId)
|
||||
{
|
||||
*aResult =
|
||||
NPError result =
|
||||
mFunctions.clearsitedata(NullableStringGet(aSite), aFlags, aMaxAge);
|
||||
SendReturnClearSiteData(result, aCallbackId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult)
|
||||
PluginModuleChild::RecvNPP_GetSitesWithData(const uint64_t& aCallbackId)
|
||||
{
|
||||
char** result = mFunctions.getsiteswithdata();
|
||||
if (!result)
|
||||
InfallibleTArray<nsCString> array;
|
||||
if (!result) {
|
||||
SendReturnSitesWithData(array, aCallbackId);
|
||||
return true;
|
||||
|
||||
}
|
||||
char** iterator = result;
|
||||
while (*iterator) {
|
||||
aResult->AppendElement(*iterator);
|
||||
array.AppendElement(*iterator);
|
||||
free(*iterator);
|
||||
++iterator;
|
||||
}
|
||||
SendReturnSitesWithData(array, aCallbackId);
|
||||
free(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -112,13 +112,13 @@ protected:
|
||||
bool *aGetSitesWithData) override;
|
||||
|
||||
virtual bool
|
||||
AnswerNPP_ClearSiteData(const nsCString& aSite,
|
||||
RecvNPP_ClearSiteData(const nsCString& aSite,
|
||||
const uint64_t& aFlags,
|
||||
const uint64_t& aMaxAge,
|
||||
NPError* aResult) override;
|
||||
const uint64_t& aCallbackId) override;
|
||||
|
||||
virtual bool
|
||||
AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult) override;
|
||||
RecvNPP_GetSitesWithData(const uint64_t& aCallbackId) override;
|
||||
|
||||
virtual bool
|
||||
RecvSetAudioSessionData(const nsID& aId,
|
||||
|
@ -2654,35 +2654,34 @@ PluginModuleChromeParent::UpdatePluginTimeout()
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags,
|
||||
uint64_t maxAge)
|
||||
PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
|
||||
nsCOMPtr<nsIClearSiteDataCallback> callback)
|
||||
{
|
||||
if (!mClearSiteDataSupported)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
NPError result;
|
||||
if (!CallNPP_ClearSiteData(NullableString(site), flags, maxAge, &result))
|
||||
return NS_ERROR_FAILURE;
|
||||
static uint64_t callbackId = 0;
|
||||
callbackId++;
|
||||
mClearSiteDataCallbacks[callbackId] = callback;
|
||||
|
||||
switch (result) {
|
||||
case NPERR_NO_ERROR:
|
||||
return NS_OK;
|
||||
case NPERR_TIME_RANGE_NOT_SUPPORTED:
|
||||
return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
|
||||
case NPERR_MALFORMED_SITE:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
default:
|
||||
if (!SendNPP_ClearSiteData(NullableString(site), flags, maxAge, callbackId)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
|
||||
PluginModuleParent::NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback)
|
||||
{
|
||||
if (!mGetSitesWithDataSupported)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (!CallNPP_GetSitesWithData(&result))
|
||||
static uint64_t callbackId = 0;
|
||||
callbackId++;
|
||||
mSitesWithDataCallbacks[callbackId] = callback;
|
||||
|
||||
if (!SendNPP_GetSitesWithData(callbackId))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
@ -2936,6 +2935,49 @@ PluginModuleChromeParent::RecvNotifyContentModuleDestroyed()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::RecvReturnClearSiteData(const NPError& aRv,
|
||||
const uint64_t& aCallbackId)
|
||||
{
|
||||
if (mClearSiteDataCallbacks.find(aCallbackId) == mClearSiteDataCallbacks.end()) {
|
||||
return true;
|
||||
}
|
||||
if (!!mClearSiteDataCallbacks[aCallbackId]) {
|
||||
nsresult rv;
|
||||
switch (aRv) {
|
||||
case NPERR_NO_ERROR:
|
||||
rv = NS_OK;
|
||||
break;
|
||||
case NPERR_TIME_RANGE_NOT_SUPPORTED:
|
||||
rv = NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
|
||||
break;
|
||||
case NPERR_MALFORMED_SITE:
|
||||
rv = NS_ERROR_INVALID_ARG;
|
||||
break;
|
||||
default:
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
mClearSiteDataCallbacks[aCallbackId]->Callback(rv);
|
||||
}
|
||||
mClearSiteDataCallbacks.erase(aCallbackId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
|
||||
const uint64_t& aCallbackId)
|
||||
{
|
||||
if (mSitesWithDataCallbacks.find(aCallbackId) == mSitesWithDataCallbacks.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!!mSitesWithDataCallbacks[aCallbackId]) {
|
||||
mSitesWithDataCallbacks[aCallbackId]->SitesWithData(aSites);
|
||||
}
|
||||
mSitesWithDataCallbacks.erase(aCallbackId);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
// We only add the crash reporter to subprocess which have the filename
|
||||
|
@ -200,6 +200,12 @@ protected:
|
||||
|
||||
virtual bool RecvProfile(const nsCString& aProfile) override { return true; }
|
||||
|
||||
virtual bool RecvReturnClearSiteData(const NPError& aRv,
|
||||
const uint64_t& aCallbackId) override;
|
||||
|
||||
virtual bool RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
|
||||
const uint64_t& aCallbackId) override;
|
||||
|
||||
void SetPluginFuncs(NPPluginFuncs* aFuncs);
|
||||
|
||||
nsresult NPP_NewInternal(NPMIMEType pluginType, NPP instance, uint16_t mode,
|
||||
@ -264,9 +270,15 @@ protected:
|
||||
uint16_t mode, int16_t argc, char* argn[],
|
||||
char* argv[], NPSavedData* saved,
|
||||
NPError* error) override;
|
||||
virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
|
||||
uint64_t maxAge) override;
|
||||
virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& result) override;
|
||||
virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
|
||||
nsCOMPtr<nsIClearSiteDataCallback> callback) override;
|
||||
virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) override;
|
||||
|
||||
private:
|
||||
std::map<uint64_t, nsCOMPtr<nsIClearSiteDataCallback>> mClearSiteDataCallbacks;
|
||||
std::map<uint64_t, nsCOMPtr<nsIGetSitesWithDataCallback>> mSitesWithDataCallbacks;
|
||||
|
||||
public:
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) override;
|
||||
|
@ -28,9 +28,7 @@
|
||||
SimpleTest.executeSoon(function() {
|
||||
// Make sure clearing by timerange is supported.
|
||||
p.setSitesWithDataCapabilities(true);
|
||||
|
||||
ok(PluginUtils.withTestPlugin(runTest), "Test plugin found");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function stored(needles) {
|
||||
@ -59,7 +57,6 @@
|
||||
|
||||
function runTest(pluginTag) {
|
||||
this.pluginTag = pluginTag;
|
||||
|
||||
p.setSitesWithData(
|
||||
"foo.com:0:5," +
|
||||
"foo.com:0:7," +
|
||||
@ -69,75 +66,99 @@
|
||||
"qux.com:1:5," +
|
||||
"quz.com:1:8"
|
||||
);
|
||||
|
||||
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
|
||||
"Data stored for sites");
|
||||
|
||||
// Clear nothing.
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 4);
|
||||
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
|
||||
"Data stored for sites");
|
||||
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 4);
|
||||
// Clear nothing.
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 4, {callback: function() { test1(); }});
|
||||
}
|
||||
function test1() {
|
||||
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
|
||||
"Data stored for sites");
|
||||
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 4, {callback: function() { test2(); }});
|
||||
}
|
||||
function test2() {
|
||||
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
|
||||
"Data stored for sites");
|
||||
|
||||
// Clear cache data 5 seconds or older.
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 5);
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 5, {callback: function() { test3(); }});
|
||||
}
|
||||
function test3() {
|
||||
ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
|
||||
"Data stored for sites");
|
||||
ok(!stored(["qux.com"]), "Data cleared for qux.com");
|
||||
|
||||
// Clear cache data for foo.com, but leave non-cache data.
|
||||
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_CACHE, 20);
|
||||
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_CACHE, 20, {callback: function() { test4(); }});
|
||||
}
|
||||
function test4() {
|
||||
ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
|
||||
"Data stored for sites");
|
||||
|
||||
// Clear all data 7 seconds or older.
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 7);
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 7, {callback: function() { test5(); }});
|
||||
}
|
||||
function test5() {
|
||||
ok(stored(["bar.com","baz.com","quz.com"]), "Data stored for sites");
|
||||
ok(!stored(["foo.com"]), "Data cleared for foo.com");
|
||||
ok(!stored(["qux.com"]), "Data cleared for qux.com");
|
||||
|
||||
// Clear all cache data.
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20);
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20, {callback: function() { test6(); }});
|
||||
}
|
||||
function test6() {
|
||||
ok(stored(["bar.com","baz.com"]), "Data stored for sites");
|
||||
ok(!stored(["quz.com"]), "Data cleared for quz.com");
|
||||
|
||||
// Clear all data for bar.com.
|
||||
pluginHost.clearSiteData(pluginTag, "bar.com", FLAG_CLEAR_ALL, 20);
|
||||
pluginHost.clearSiteData(pluginTag, "bar.com", FLAG_CLEAR_ALL, 20, {callback: function(rv) { test7(rv); }});
|
||||
}
|
||||
function test7(rv) {
|
||||
ok(stored(["baz.com"]), "Data stored for baz.com");
|
||||
ok(!stored(["bar.com"]), "Data cleared for bar.com");
|
||||
|
||||
// Disable clearing by age.
|
||||
p.setSitesWithDataCapabilities(false);
|
||||
|
||||
// Attempt to clear data by age.
|
||||
checkThrows(function() {
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 20);
|
||||
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
|
||||
checkThrows(function() {
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20);
|
||||
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
|
||||
checkThrows(function() {
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, 20);
|
||||
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
|
||||
checkThrows(function() {
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, 20);
|
||||
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 20, {callback: function(rv) {
|
||||
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
test8(rv);
|
||||
}});
|
||||
}
|
||||
function test8(rv) {
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20, {callback: function(rv) {
|
||||
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
test9(rv);
|
||||
}});
|
||||
}
|
||||
function test9(rv) {
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, 20, {callback: function(rv) {
|
||||
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
test10(rv);
|
||||
}});
|
||||
}
|
||||
function test10(rv) {
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, 20, {callback: function(rv) {
|
||||
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
|
||||
test11();
|
||||
}});
|
||||
}
|
||||
function test11() {
|
||||
// Clear cache for baz.com and globally for all ages.
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, -1);
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, -1);
|
||||
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, -1, {callback: function(rv) { test12()}});
|
||||
}
|
||||
function test12() {
|
||||
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, -1, {callback: function(rv) { test13()}});
|
||||
}
|
||||
function test13() {
|
||||
// Check that all of the above were no-ops.
|
||||
ok(stored(["baz.com"]), "Data stored for baz.com");
|
||||
|
||||
// Clear everything for baz.com.
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test14()}});
|
||||
}
|
||||
function test14() {
|
||||
ok(!stored(["baz.com"]), "Data cleared for baz.com");
|
||||
ok(!stored(null), "All data cleared");
|
||||
|
||||
@ -150,26 +171,33 @@
|
||||
"[192.168.1.1]:0:0," +
|
||||
"localhost:0:0"
|
||||
);
|
||||
|
||||
ok(stored(["foo.com","nonexistent.foo.com","bar.com","192.168.1.1","localhost"]),
|
||||
"Data stored for sites");
|
||||
"Data stored for sites");
|
||||
|
||||
// Clear data for "foo.com" and its subdomains.
|
||||
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test15()}});
|
||||
}
|
||||
function test15() {
|
||||
ok(stored(["bar.com","192.168.1.1","localhost"]), "Data stored for sites");
|
||||
ok(!stored(["foo.com"]), "Data cleared for foo.com");
|
||||
ok(!stored(["bar.foo.com"]), "Data cleared for subdomains of foo.com");
|
||||
|
||||
// Clear data for "bar.com" using a subdomain.
|
||||
pluginHost.clearSiteData(pluginTag, "foo.bar.com", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "foo.bar.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test16()}});
|
||||
}
|
||||
function test16() {
|
||||
ok(!stored(["bar.com"]), "Data cleared for bar.com");
|
||||
|
||||
// Clear data for "192.168.1.1".
|
||||
pluginHost.clearSiteData(pluginTag, "192.168.1.1", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "192.168.1.1", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test17()}});
|
||||
}
|
||||
function test17() {
|
||||
ok(!stored(["192.168.1.1"]), "Data cleared for 192.168.1.1");
|
||||
|
||||
// Clear data for "localhost".
|
||||
pluginHost.clearSiteData(pluginTag, "localhost", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "localhost", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test18()}});
|
||||
}
|
||||
function test18() {
|
||||
ok(!stored(null), "All data cleared");
|
||||
|
||||
// Set data to test international domains.
|
||||
@ -178,18 +206,21 @@
|
||||
"b\u00FCcher.uk:0:0," +
|
||||
"xn--bcher-kva.NZ:0:0"
|
||||
);
|
||||
|
||||
// Check that both the ACE and UTF-8 representations register.
|
||||
// Check that both the ACE and UTF-8 representations register.
|
||||
ok(stored(["b\u00FCcher.es","xn--bcher-kva.es","b\u00FCcher.uk","xn--bcher-kva.uk"]),
|
||||
"Data stored for sites");
|
||||
"Data stored for sites");
|
||||
|
||||
// Clear data for the UTF-8 version.
|
||||
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.es", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.es", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test19()}});
|
||||
}
|
||||
function test19() {
|
||||
ok(!stored(["b\u00FCcher.es"]), "Data cleared for UTF-8 representation");
|
||||
ok(!stored(["xn--bcher-kva.es"]), "Data cleared for ACE representation");
|
||||
|
||||
// Clear data for the ACE version.
|
||||
pluginHost.clearSiteData(pluginTag, "xn--bcher-kva.uk", FLAG_CLEAR_ALL, -1);
|
||||
pluginHost.clearSiteData(pluginTag, "xn--bcher-kva.uk", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test20()}});
|
||||
}
|
||||
function test20() {
|
||||
ok(!stored(["b\u00FCcher.uk"]), "Data cleared for UTF-8 representation");
|
||||
ok(!stored(["xn--bcher-kva.uk"]), "Data cleared for ACE representation");
|
||||
|
||||
@ -197,11 +228,14 @@
|
||||
// UTF-8. We do happen to normalize the result anyway, so while that's not
|
||||
// strictly required, we test it here.
|
||||
ok(stored(["b\u00FCcher.nz","xn--bcher-kva.nz"]),
|
||||
"Data stored for sites");
|
||||
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.nz", FLAG_CLEAR_ALL, -1);
|
||||
"Data stored for sites");
|
||||
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.nz", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test21()}});
|
||||
}
|
||||
function test21() {
|
||||
ok(!stored(["b\u00FCcher.nz"]), "Data cleared for UTF-8 representation");
|
||||
ok(!stored(["xn--bcher-kva.nz"]), "Data cleared for ACE representation");
|
||||
ok(!stored(null), "All data cleared");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
@ -5,21 +5,15 @@
|
||||
* In particular, the tests check that default-src and manifest-src directives are
|
||||
* are respected by the ManifestObtainer.
|
||||
*/
|
||||
/*globals Components*/
|
||||
/*globals SpecialPowers, requestLongerTimeout, ok, Cu, is, add_task, gBrowser, BrowserTestUtils, ManifestObtainer*/
|
||||
'use strict';
|
||||
requestLongerTimeout(10); // e10s tests take time.
|
||||
const {
|
||||
ManifestObtainer
|
||||
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
|
||||
Cu.import('resource://gre/modules/ManifestObtainer.jsm', this); // jshint ignore:line
|
||||
const path = '/tests/dom/security/test/csp/';
|
||||
const testFile = `file=${path}file_web_manifest.html`;
|
||||
const remoteFile = `file=${path}file_web_manifest_remote.html`;
|
||||
const httpsManifest = `file=${path}file_web_manifest_https.html`;
|
||||
const mixedContent = `file=${path}file_web_manifest_mixed_content.html`;
|
||||
const server = 'file_testserver.sjs';
|
||||
const defaultURL = `http://example.org${path}${server}`;
|
||||
const remoteURL = `http://mochi.test:8888`;
|
||||
const secureURL = `https://example.com${path}${server}`;
|
||||
const tests = [
|
||||
// CSP block everything, so trying to load a manifest
|
||||
// will result in a policy violation.
|
||||
@ -248,7 +242,7 @@ function NetworkObserver(test) {
|
||||
let success = false;
|
||||
this.finished = new Promise((resolver) => {
|
||||
finishedTest = resolver;
|
||||
})
|
||||
});
|
||||
this.observe = function observer(subject, topic) {
|
||||
SpecialPowers.removeObserver(this, 'csp-on-violate-policy');
|
||||
test.run(topic);
|
||||
|
@ -3,10 +3,12 @@
|
||||
* Check that mixed content blocker works prevents fetches of
|
||||
* mixed content manifests.
|
||||
*/
|
||||
/*globals Cu, add_task, ok, gBrowser, BrowserTestUtils, ManifestObtainer*/
|
||||
'use strict';
|
||||
const {
|
||||
ManifestObtainer
|
||||
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
|
||||
} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', this); // jshint ignore:line
|
||||
const obtainer = new ManifestObtainer();
|
||||
const path = '/tests/dom/security/test/csp/';
|
||||
const mixedContent = `file=${path}file_web_manifest_mixed_content.html`;
|
||||
const server = 'file_testserver.sjs';
|
||||
@ -31,7 +33,7 @@ const tests = [
|
||||
];
|
||||
|
||||
//jscs:disable
|
||||
add_task(function*() {
|
||||
add_task(function* () {
|
||||
//jscs:enable
|
||||
for (let test of tests) {
|
||||
let tabOptions = {
|
||||
@ -45,11 +47,11 @@ add_task(function*() {
|
||||
}
|
||||
|
||||
function* testObtainingManifest(aBrowser, aTest) {
|
||||
const obtainer = new ManifestObtainer();
|
||||
let manifest;
|
||||
try {
|
||||
yield obtainer.obtainManifest(aBrowser);
|
||||
} catch (e) {
|
||||
aTest.run(e)
|
||||
return aTest.run(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -147,10 +147,13 @@ function expectFocusShift(callback, expectedWindow, expectedElement, focusChange
|
||||
// for this test which fires a mouse event on a label, the document will
|
||||
// be focused first and then the label code will focus the related
|
||||
// control. This doesn't result in different focus events, but a command
|
||||
// update will occur for the document and then a secon command update will
|
||||
// occur when the control is focused.
|
||||
if (testid == "mouse on html label with content inside")
|
||||
// update will occur for the document and then a second command update will
|
||||
// occur when the control is focused. However, this will only happen on
|
||||
// platforms or controls where mouse clicks cause trigger focus.
|
||||
if (testid == "mouse on html label with content inside" &&
|
||||
mouseWillTriggerFocus(expectedElement)) {
|
||||
expectedEvents += " commandupdate: cu";
|
||||
}
|
||||
|
||||
if (expectedElement &&
|
||||
(!gNewExpectedWindow || gNewExpectedWindow.document.documentElement != expectedElement)) {
|
||||
@ -278,25 +281,36 @@ function getTopWindow(win)
|
||||
getInterface(Components.interfaces.nsIDOMWindow);
|
||||
}
|
||||
|
||||
function mouseWillTriggerFocus(element)
|
||||
{
|
||||
if (!element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (navigator.platform.indexOf("Mac") != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element.namespaceURI == "http://www.w3.org/1999/xhtml") {
|
||||
// links are special. They can be focused but show no focus ring
|
||||
if (element.localName == "a" || element.localName == "div" ||
|
||||
element.localName == "select" ||
|
||||
element.localName == "input" && (element.type == "text" ||
|
||||
element.type == "password")) {
|
||||
return true;
|
||||
}
|
||||
} else if (element.localName == "listbox") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function mouseOnElement(element, expectedElement, focusChanged, testid)
|
||||
{
|
||||
var expectedWindow = (element.ownerDocument.defaultView == gChildWindow) ? gChildWindow : window;
|
||||
// on Mac, form elements are not focused when clicking, except for lists and textboxes.
|
||||
var noFocusOnMouse = (navigator.platform.indexOf("Mac") == 0);
|
||||
if (noFocusOnMouse) {
|
||||
if (element.namespaceURI == "http://www.w3.org/1999/xhtml") {
|
||||
// links are special. They can be focused but show no focus ring
|
||||
if (element.localName == "a" || element.localName == "div" ||
|
||||
element.localName == "select" ||
|
||||
element.localName == "input" && (element.type == "text" ||
|
||||
element.type == "password")) {
|
||||
noFocusOnMouse = false;
|
||||
}
|
||||
}
|
||||
else if (element.localName == "listbox") {
|
||||
noFocusOnMouse = false;
|
||||
}
|
||||
}
|
||||
var noFocusOnMouse = !mouseWillTriggerFocus(element)
|
||||
|
||||
if (noFocusOnMouse) {
|
||||
// no focus so the last focus method will be 0
|
||||
@ -552,11 +566,9 @@ function startTest()
|
||||
}
|
||||
|
||||
// clicking on the labels
|
||||
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
|
||||
expectFocusShift(function () synthesizeMouse(getById("ad"), 2, 2, { }, gChildWindow),
|
||||
null, getById("t29"), true, "mouse on html label with content inside");
|
||||
expectFocusShift(function () synthesizeMouse(getById("ag"), 2, 2, { }, gChildWindow),
|
||||
null, getById("n6"), true, "mouse on html label with for attribute");
|
||||
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS | fm.FLAG_BYMOUSE;
|
||||
mouseOnElement(getById("ad"), getById("t29"), true, "mouse on html label with content inside");
|
||||
mouseOnElement(getById("ag"), getById("n6"), true, "mouse on html label with for attribute");
|
||||
gLastFocusMethod = 0;
|
||||
expectFocusShift(function () synthesizeMouse(getById("aj"), 2, 2, { }),
|
||||
null, getById("o9"), true, "mouse on xul label with content inside");
|
||||
|
@ -272,6 +272,11 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
|
||||
return;
|
||||
}
|
||||
|
||||
// Set composition timestamp here because we need it in
|
||||
// ComputeEffectiveTransforms (so the correct video frame size is picked) and
|
||||
// also to compute invalid regions properly.
|
||||
mCompositor->SetCompositionTime(aTimeStamp);
|
||||
|
||||
if (mRoot && mClonedLayerTreeProperties) {
|
||||
MOZ_ASSERT(!mTarget);
|
||||
nsIntRegion invalid =
|
||||
@ -290,9 +295,6 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
|
||||
|
||||
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
|
||||
MOZ_ASSERT(!aTimeStamp.IsNull());
|
||||
// Set composition timestamp here because we need it in
|
||||
// ComputeEffectiveTransforms (so the correct video frame size is picked)
|
||||
mCompositor->SetCompositionTime(aTimeStamp);
|
||||
// The results of our drawing always go directly into a pixel buffer,
|
||||
// so we don't need to pass any global transform here.
|
||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
||||
|
@ -439,7 +439,11 @@ CreateBoxShadow(DrawTarget& aDT, SourceSurface* aBlurMask, const gfxRGBA& aShado
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(boxShadowDT->GetType() == aDT.GetType());
|
||||
if (boxShadowDT->GetType() != aDT.GetType()) {
|
||||
printf_stderr("Box shadow type: %d, dest draw target type: %d\n",
|
||||
(int) boxShadowDT->GetType(), (int) aDT.GetType());
|
||||
MOZ_ASSERT(false, "Box shadows are incorrect type\n");
|
||||
}
|
||||
|
||||
ColorPattern shadowColor(ToDeviceColor(aShadowColor));
|
||||
boxShadowDT->MaskSurface(shadowColor, aBlurMask, Point(0, 0));
|
||||
|
@ -266,6 +266,7 @@ private:
|
||||
DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
|
||||
DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);
|
||||
DECL_GFX_PREF(Live, "image.infer-src-animation.threshold-ms", ImageInferSrcAnimationThresholdMS, uint32_t, 2000);
|
||||
DECL_GFX_PREF(Once, "image.mem.decode_bytes_at_a_time", ImageMemDecodeBytesAtATime, uint32_t, 200000);
|
||||
DECL_GFX_PREF(Live, "image.mem.discardable", ImageMemDiscardable, bool, false);
|
||||
DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1);
|
||||
|
@ -123,7 +123,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
||||
#ifdef JS_CODEGEN_ARM64
|
||||
// ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
|
||||
MOZ_ASSERT(!masm.GetStackPointer64().Is(sp));
|
||||
masm.moveStackPtrTo(masm.getStackPointer());
|
||||
masm.Mov(masm.GetStackPointer64(), sp);
|
||||
#endif
|
||||
|
||||
// Push non-volatile registers which might be modified by jitcode.
|
||||
|
@ -1095,8 +1095,12 @@ IonBuilder::initParameters()
|
||||
// interpreter and didn't accumulate type information, try to use that OSR
|
||||
// frame to determine possible initial types for 'this' and parameters.
|
||||
|
||||
if (thisTypes->empty() && baselineFrame_)
|
||||
thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc());
|
||||
if (thisTypes->empty() && baselineFrame_) {
|
||||
TypeSet::Type type = baselineFrame_->thisType;
|
||||
if (type.isSingletonUnchecked())
|
||||
checkNurseryObject(type.singleton());
|
||||
thisTypes->addType(type, alloc_->lifoAlloc());
|
||||
}
|
||||
|
||||
MParameter* param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
|
||||
current->add(param);
|
||||
@ -1107,7 +1111,10 @@ IonBuilder::initParameters()
|
||||
if (types->empty() && baselineFrame_ &&
|
||||
!script_->baselineScript()->modifiesArguments())
|
||||
{
|
||||
types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc());
|
||||
TypeSet::Type type = baselineFrame_->argTypes[i];
|
||||
if (type.isSingletonUnchecked())
|
||||
checkNurseryObject(type.singleton());
|
||||
types->addType(type, alloc_->lifoAlloc());
|
||||
}
|
||||
|
||||
param = MParameter::New(alloc(), i, types);
|
||||
@ -6995,6 +7002,9 @@ IonBuilder::newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, bool
|
||||
else
|
||||
existingType = baselineFrame_->varTypes[var];
|
||||
|
||||
if (existingType.isSingletonUnchecked())
|
||||
checkNurseryObject(existingType.singleton());
|
||||
|
||||
// Extract typeset from value.
|
||||
LifoAlloc* lifoAlloc = alloc().lifoAlloc();
|
||||
TemporaryTypeSet* typeSet =
|
||||
|
@ -23,6 +23,10 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
# include "jswin.h"
|
||||
#endif
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
@ -740,7 +744,28 @@ random_generateSeed()
|
||||
seed.u64 = 0;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/*
|
||||
* Temporary diagnostic for bug 1167248: Test whether the injected hooks
|
||||
* react differently to LoadLibraryW / LoadLibraryExW.
|
||||
*/
|
||||
HMODULE oldWay = LoadLibraryW(L"ADVAPI32.DLL");
|
||||
HMODULE newWay = LoadLibraryExW(L"ADVAPI32.DLL",
|
||||
nullptr,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
/* Fallback for older versions of Windows */
|
||||
if (!newWay && GetLastError() == ERROR_INVALID_PARAMETER)
|
||||
newWay = LoadLibraryExW(L"ADVAPI32.DLL", nullptr, 0);
|
||||
|
||||
if (oldWay && !newWay)
|
||||
MOZ_CRASH();
|
||||
|
||||
errno_t error = rand_s(&seed.u32[0]);
|
||||
|
||||
if (oldWay)
|
||||
FreeLibrary(oldWay);
|
||||
if (newWay)
|
||||
FreeLibrary(newWay);
|
||||
|
||||
MOZ_ASSERT(error == 0, "rand_s() error?!");
|
||||
|
||||
error = rand_s(&seed.u32[1]);
|
||||
|
@ -808,7 +808,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
||||
// At this point there may be JSObjects using them that have
|
||||
// been removed from the other maps.
|
||||
if (!nsXPConnect::XPConnect()->IsShuttingDown()) {
|
||||
for (auto i = self->mNativeScriptableSharedMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = self->mNativeScriptableSharedMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<XPCNativeScriptableSharedMap::Entry*>(i.Get());
|
||||
XPCNativeScriptableShared* shared = entry->key;
|
||||
if (shared->IsMarked()) {
|
||||
@ -821,14 +821,14 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
||||
}
|
||||
|
||||
if (!isCompartmentGC) {
|
||||
for (auto i = self->mClassInfo2NativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = self->mClassInfo2NativeSetMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<ClassInfo2NativeSetMap::Entry*>(i.Get());
|
||||
if (!entry->value->IsMarked())
|
||||
i.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = self->mNativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = self->mNativeSetMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
|
||||
XPCNativeSet* set = entry->key_value;
|
||||
if (set->IsMarked()) {
|
||||
@ -839,7 +839,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = self->mIID2NativeInterfaceMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = self->mIID2NativeInterfaceMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<IID2NativeInterfaceMap::Entry*>(i.Get());
|
||||
XPCNativeInterface* iface = entry->value;
|
||||
if (iface->IsMarked()) {
|
||||
@ -904,7 +904,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
|
||||
// referencing the protos in the dying list are themselves dead.
|
||||
// So, we can safely delete all the protos in the list.
|
||||
|
||||
for (auto i = self->mDyingWrappedNativeProtoMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = self->mDyingWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
|
||||
delete static_cast<const XPCWrappedNativeProto*>(entry->key);
|
||||
i.Remove();
|
||||
@ -3658,7 +3658,7 @@ XPCJSRuntime::DebugDump(int16_t depth)
|
||||
// iterate sets...
|
||||
if (depth && mNativeSetMap->Count()) {
|
||||
XPC_LOG_INDENT();
|
||||
for (auto i = mNativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = mNativeSetMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
|
||||
entry->key_value->DebugDump(depth);
|
||||
}
|
||||
|
@ -150,8 +150,6 @@ public:
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
~Native2WrappedNativeMap();
|
||||
@ -263,7 +261,7 @@ public:
|
||||
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
@ -319,7 +317,7 @@ public:
|
||||
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
|
||||
|
||||
// ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
|
||||
// So we don't want to count those XPCNativeSets, because they are better
|
||||
@ -377,7 +375,7 @@ public:
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
@ -448,7 +446,7 @@ public:
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
@ -545,7 +543,7 @@ public:
|
||||
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
|
||||
|
||||
~XPCNativeScriptableSharedMap();
|
||||
private:
|
||||
@ -586,7 +584,7 @@ public:
|
||||
inline uint32_t Count() { return mTable->EntryCount(); }
|
||||
|
||||
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
|
||||
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
|
||||
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
|
||||
|
||||
~XPCWrappedNativeProtoMap();
|
||||
private:
|
||||
|
@ -651,12 +651,12 @@ XPCWrappedNativeScope::SystemIsBeingShutDown()
|
||||
|
||||
// Walk the protos first. Wrapper shutdown can leave dangling
|
||||
// proto pointers in the proto map.
|
||||
for (auto i = cur->mWrappedNativeProtoMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
|
||||
entry->value->SystemIsBeingShutDown();
|
||||
i.Remove();
|
||||
}
|
||||
for (auto i = cur->mWrappedNativeMap->RemovingIter(); !i.Done(); i.Next()) {
|
||||
for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
|
||||
auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
|
||||
XPCWrappedNative* wrapper = entry->value;
|
||||
if (wrapper->IsValid()) {
|
||||
|
@ -7343,6 +7343,7 @@ UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
|
||||
nsIAtom* fType = aFrame->GetType();
|
||||
if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
|
||||
fType == nsGkAtoms::scrollFrame ||
|
||||
fType == nsGkAtoms::listControlFrame ||
|
||||
fType == nsGkAtoms::svgOuterSVGFrame) {
|
||||
return u;
|
||||
}
|
||||
|
@ -582,8 +582,10 @@ public:
|
||||
static bool ShouldApplyOverflowClipping(const nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisp)
|
||||
{
|
||||
// clip overflow:-moz-hidden-unscrollable ...
|
||||
if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP)) {
|
||||
// clip overflow:-moz-hidden-unscrollable, except for nsListControlFrame,
|
||||
// which is an nsHTMLScrollFrame.
|
||||
if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP &&
|
||||
aFrame->GetType() != nsGkAtoms::listControlFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,8 @@ nsImageFrame::nsImageFrame(nsStyleContext* aContext) :
|
||||
mIntrinsicRatio(0, 0),
|
||||
mDisplayingIcon(false),
|
||||
mFirstFrameComplete(false),
|
||||
mReflowCallbackPosted(false)
|
||||
mReflowCallbackPosted(false),
|
||||
mForceSyncDecoding(false)
|
||||
{
|
||||
// We assume our size is not constrained and we haven't gotten an
|
||||
// initial reflow yet, so don't touch those flags.
|
||||
@ -1621,11 +1622,16 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
|
||||
StylePosition(),
|
||||
&anchorPoint);
|
||||
|
||||
uint32_t flags = aFlags;
|
||||
if (mForceSyncDecoding) {
|
||||
flags |= imgIContainer::FLAG_SYNC_DECODE;
|
||||
}
|
||||
|
||||
DrawResult result =
|
||||
nsLayoutUtils::DrawSingleImage(*aRenderingContext.ThebesContext(),
|
||||
PresContext(), aImage,
|
||||
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
|
||||
nullptr, aFlags, &anchorPoint);
|
||||
nullptr, flags, &anchorPoint);
|
||||
|
||||
nsImageMap* map = GetImageMap();
|
||||
if (map) {
|
||||
|
@ -233,6 +233,9 @@ protected:
|
||||
*/
|
||||
void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus);
|
||||
|
||||
/// Always sync decode our image when painting if @aForce is true.
|
||||
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
|
||||
|
||||
private:
|
||||
// random helpers
|
||||
inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
|
||||
@ -308,6 +311,7 @@ private:
|
||||
bool mDisplayingIcon;
|
||||
bool mFirstFrameComplete;
|
||||
bool mReflowCallbackPosted;
|
||||
bool mForceSyncDecoding;
|
||||
|
||||
static nsIIOService* sIOService;
|
||||
|
||||
|
@ -367,8 +367,8 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
|
||||
case eCSSProperty_border_right:
|
||||
case eCSSProperty_border_bottom:
|
||||
case eCSSProperty_border_left:
|
||||
case eCSSProperty_border_start:
|
||||
case eCSSProperty_border_end:
|
||||
case eCSSProperty_border_inline_start:
|
||||
case eCSSProperty_border_inline_end:
|
||||
case eCSSProperty_border_block_start:
|
||||
case eCSSProperty_border_block_end:
|
||||
case eCSSProperty__moz_column_rule:
|
||||
|
@ -6964,15 +6964,15 @@ static const nsCSSProperty kBorderLeftIDs[] = {
|
||||
eCSSProperty_border_left_style,
|
||||
eCSSProperty_border_left_color
|
||||
};
|
||||
static const nsCSSProperty kBorderStartIDs[] = {
|
||||
eCSSProperty_border_start_width,
|
||||
eCSSProperty_border_start_style,
|
||||
eCSSProperty_border_start_color
|
||||
static const nsCSSProperty kBorderInlineStartIDs[] = {
|
||||
eCSSProperty_border_inline_start_width,
|
||||
eCSSProperty_border_inline_start_style,
|
||||
eCSSProperty_border_inline_start_color
|
||||
};
|
||||
static const nsCSSProperty kBorderEndIDs[] = {
|
||||
eCSSProperty_border_end_width,
|
||||
eCSSProperty_border_end_style,
|
||||
eCSSProperty_border_end_color
|
||||
static const nsCSSProperty kBorderInlineEndIDs[] = {
|
||||
eCSSProperty_border_inline_end_width,
|
||||
eCSSProperty_border_inline_end_style,
|
||||
eCSSProperty_border_inline_end_color
|
||||
};
|
||||
static const nsCSSProperty kBorderBlockStartIDs[] = {
|
||||
eCSSProperty_border_block_start_width,
|
||||
@ -10066,10 +10066,10 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
|
||||
return ParseBorderSide(kBorderBlockStartIDs, false);
|
||||
case eCSSProperty_border_bottom:
|
||||
return ParseBorderSide(kBorderBottomIDs, false);
|
||||
case eCSSProperty_border_end:
|
||||
return ParseBorderSide(kBorderEndIDs, false);
|
||||
case eCSSProperty_border_start:
|
||||
return ParseBorderSide(kBorderStartIDs, false);
|
||||
case eCSSProperty_border_inline_end:
|
||||
return ParseBorderSide(kBorderInlineEndIDs, false);
|
||||
case eCSSProperty_border_inline_start:
|
||||
return ParseBorderSide(kBorderInlineStartIDs, false);
|
||||
case eCSSProperty_border_left:
|
||||
return ParseBorderSide(kBorderLeftIDs, false);
|
||||
case eCSSProperty_border_right:
|
||||
|
@ -127,51 +127,51 @@ CSS_PROP_ALIAS(-moz-font-language-override,
|
||||
font_language_override,
|
||||
MozFontLanguageOverride,
|
||||
"layout.css.prefixes.font-features")
|
||||
CSS_PROP_ALIAS(padding-inline-end,
|
||||
padding_end,
|
||||
PaddingInlineEnd,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(padding-inline-start,
|
||||
padding_start,
|
||||
PaddingInlineStart,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(margin-inline-end,
|
||||
margin_end,
|
||||
MarginInlineEnd,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(margin-inline-start,
|
||||
margin_start,
|
||||
MarginInlineStart,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-end,
|
||||
border_end,
|
||||
BorderInlineEnd,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-end-color,
|
||||
border_end_color,
|
||||
BorderInlineEndColor,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-end-style,
|
||||
border_end_style,
|
||||
BorderInlineEndStyle,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-end-width,
|
||||
border_end_width,
|
||||
BorderInlineEndWidth,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-start,
|
||||
border_start,
|
||||
BorderInlineStart,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-start-color,
|
||||
border_start_color,
|
||||
BorderInlineStartColor,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-start-style,
|
||||
border_start_style,
|
||||
BorderInlineStartStyle,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(border-inline-start-width,
|
||||
border_start_width,
|
||||
BorderInlineStartWidth,
|
||||
"layout.css.vertical-text.enabled")
|
||||
CSS_PROP_ALIAS(-moz-padding-end,
|
||||
padding_inline_end,
|
||||
MozPaddingEnd,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-padding-start,
|
||||
padding_inline_start,
|
||||
MozPaddingStart,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-margin-end,
|
||||
margin_inline_end,
|
||||
MozMarginEnd,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-margin-start,
|
||||
margin_inline_start,
|
||||
MozMarginStart,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-end,
|
||||
border_inline_end,
|
||||
MozBorderEnd,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-end-color,
|
||||
border_inline_end_color,
|
||||
MozBorderEndColor,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-end-style,
|
||||
border_inline_end_style,
|
||||
MozBorderEndStyle,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-end-width,
|
||||
border_inline_end_width,
|
||||
MozBorderEndWidth,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-start,
|
||||
border_inline_start,
|
||||
MozBorderStart,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-start-color,
|
||||
border_inline_start_color,
|
||||
MozBorderStartColor,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-start-style,
|
||||
border_inline_start_style,
|
||||
MozBorderStartStyle,
|
||||
"")
|
||||
CSS_PROP_ALIAS(-moz-border-start-width,
|
||||
border_inline_start_width,
|
||||
MozBorderStartWidth,
|
||||
"")
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user