This commit is contained in:
Wes Kocher 2015-09-17 15:25:57 -07:00
Родитель a88389dd17 86c8db452c
Коммит 218c9bb81a
178 изменённых файлов: 10846 добавлений и 8032 удалений

Просмотреть файл

@ -537,6 +537,48 @@ SettingsListener.observe("theme.selected",
setPAC();
})();
#ifdef MOZ_B2G_RIL
XPCOMUtils.defineLazyModuleGetter(this, "AppsUtils",
"resource://gre/modules/AppsUtils.jsm");
// ======================= Dogfooders FOTA ==========================
SettingsListener.observe('debug.performance_data.dogfooding', false,
isDogfooder => {
if (!isDogfooder) {
dump('AUS:Settings: Not a dogfooder!\n');
return;
}
if (!('mozTelephony' in navigator)) {
dump('AUS:Settings: There is no mozTelephony!\n');
return;
}
if (!('mozMobileConnections' in navigator)) {
dump('AUS:Settings: There is no mozMobileConnections!\n');
return;
}
let conn = navigator.mozMobileConnections[0];
conn.addEventListener('radiostatechange', function onradiostatechange() {
if (conn.radioState !== 'enabled') {
return;
}
conn.removeEventListener('radiostatechange', onradiostatechange);
navigator.mozTelephony.dial('*#06#').then(call => {
return call.result.then(res => {
if (res.success && res.statusMessage
&& (res.serviceCode === 'scImei')) {
Services.prefs.setCharPref("app.update.imei_hash",
AppsUtils.computeHash(res.statusMessage, "SHA512"));
}
});
});
});
});
#endif
// =================== Various simple mapping ======================
var settingsToObserve = {
'accessibility.screenreader_quicknav_modes': {

Просмотреть файл

@ -15,11 +15,11 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -15,11 +15,11 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -19,12 +19,12 @@
<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="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>

Просмотреть файл

@ -17,9 +17,9 @@
</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="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1f9532e4157df2dc8d3e9c8100120f80117dcd4"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -15,11 +15,11 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -15,11 +15,11 @@
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -19,12 +19,12 @@
<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="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>

Просмотреть файл

@ -15,11 +15,11 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "aede8622d780ec71f766a3ecccbff74c04aaba4e",
"git_revision": "2082894c8e974b0c371e4dec298e0ad0f3ac56b1",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "dbd3a4ea9042cae987147f2d05f41d2a7ebaccbc",
"revision": "0e712c8d330e10908f99194a9638e62a07c5c483",
"repo_path": "integration/gaia-central"
}

Просмотреть файл

@ -17,9 +17,9 @@
</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="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a1f9532e4157df2dc8d3e9c8100120f80117dcd4"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -15,11 +15,11 @@
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="aede8622d780ec71f766a3ecccbff74c04aaba4e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2082894c8e974b0c371e4dec298e0ad0f3ac56b1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>

Просмотреть файл

@ -163,7 +163,7 @@
<menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
<menupopup rolluponmousewheel="true"
#ifdef XP_WIN
consumeoutsideclicks="false"
consumeoutsideclicks="false" ignorekeys="handled"
#endif
/>
</menulist>

Просмотреть файл

@ -23,7 +23,7 @@ const PAGECONTENT =
" <optgroup label='Third Group'>" +
" <option value='Seven'> Seven </option>" +
" <option value='Eight'>&nbsp;&nbsp;Eight&nbsp;&nbsp;</option>" +
" </optgroup></select><input />" +
" </optgroup></select><input />Text" +
"</body></html>";
function openSelectPopup(selectPopup, withMouse)
@ -108,6 +108,12 @@ function doSelectTests(contentType, dtd)
is((yield getChangeEvents()), 0, "Before closed - number of change events");
EventUtils.synthesizeKey("a", { accelKey: true });
let selection = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
return String(content.getSelection());
});
is(selection, isWindows ? "Text" : "", "Select all while popup is open");
yield hideSelectPopup(selectPopup);
is(menulist.selectedIndex, 3, "Item 3 still selected");

Просмотреть файл

@ -75,8 +75,8 @@ def main():
# Run |nm|. Options:
# -u: show only undefined symbols
# -C: demangle symbol names
# -l: show a filename and line number for each undefined symbol
cmd = ['nm', '-u', '-C', '-l', args.file]
# -A: show an object filename for each undefined symbol
cmd = ['nm', '-u', '-C', '-A', args.file]
lines = subprocess.check_output(cmd, universal_newlines=True,
stderr=subprocess.PIPE).split('\n')
@ -112,26 +112,30 @@ def main():
# This regexp matches the relevant lines in the output of |nm|, which look
# like the following.
#
# U malloc /path/to/objdir/dist/include/js/Utility.h:142
# js/src/libjs_static.a:jsutil.o: U malloc
#
alloc_fns_re = r'U (' + r'|'.join(alloc_fns) + r').*\/([\w\.]+):(\d+)$'
alloc_fns_re = r'([^:/ ]+):\s+U (' + r'|'.join(alloc_fns) + r')'
# This tracks which allocation/free functions have been seen in jsutil.cpp.
jsutil_cpp = set([])
# Would it be helpful to emit detailed line number information after a failure?
emit_line_info = False
for line in lines:
m = re.search(alloc_fns_re, line)
if m is None:
continue
fn = m.group(1)
filename = m.group(2)
linenum = m.group(3)
if filename == 'jsutil.cpp':
filename = m.group(1)
fn = m.group(2)
if filename == 'jsutil.o':
jsutil_cpp.add(fn)
else:
# An allocation is present in a non-special file. Fail!
fail("'" + fn + "' present at " + filename + ':' + linenum)
fail("'" + fn + "' present in " + filename)
# Try to give more precise information about the offending code.
emit_line_info = True
# Check that all functions we expect are used in jsutil.cpp. (This will
@ -147,6 +151,34 @@ def main():
fail('unexpected allocation fns used in jsutil.cpp: ' +
', '.join(jsutil_cpp))
# If we found any improper references to allocation functions, try to use
# DWARF debug info to get more accurate line number information about the
# bad calls. This is a lot slower than 'nm -A', and it is not always
# precise when building with --enable-optimized.
if emit_line_info:
print('check_vanilla_allocations.py: Source lines with allocation calls:')
print('check_vanilla_allocations.py: Accurate in unoptimized builds; jsutil.cpp expected.')
# Run |nm|. Options:
# -u: show only undefined symbols
# -C: demangle symbol names
# -l: show line number information for each undefined symbol
cmd = ['nm', '-u', '-C', '-l', args.file]
lines = subprocess.check_output(cmd, universal_newlines=True,
stderr=subprocess.PIPE).split('\n')
# This regexp matches the relevant lines in the output of |nm -l|,
# which look like the following.
#
# U malloc jsutil.cpp:117
#
alloc_lines_re = r'U ((' + r'|'.join(alloc_fns) + r').*)\s+(\S+:\d+)$'
for line in lines:
m = re.search(alloc_lines_re, line)
if m:
print('check_vanilla_allocations.py:', m.group(1), 'called at', m.group(3))
if has_failed:
sys.exit(1)

Просмотреть файл

@ -7251,9 +7251,6 @@ if test -z "$MOZ_MEMORY"; then
esac
else
AC_DEFINE(MOZ_MEMORY)
if test -n "$NIGHTLY_BUILD"; then
MOZ_JEMALLOC4=1
fi
if test -n "$MOZ_JEMALLOC4"; then
AC_DEFINE(MOZ_JEMALLOC4)
fi

Просмотреть файл

@ -10871,10 +10871,7 @@ nsDocShell::DoChannelLoad(nsIChannel* aChannel,
// If the user pressed shift-reload, then do not allow ServiceWorker
// interception to occur. See step 12.1 of the SW HandleFetch algorithm.
if (mLoadType == LOAD_RELOAD_BYPASS_CACHE ||
mLoadType == LOAD_RELOAD_BYPASS_PROXY ||
mLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
if (IsForceReloadType(mLoadType)) {
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aChannel);
if (internal) {
internal->ForceNoIntercept();
@ -11163,11 +11160,7 @@ nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel, nsISupports* aOwner,
* for the page. Save the new cacheKey in Session History.
* see bug 90098
*/
if (aChannel &&
(aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
aLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT)) {
if (aChannel && IsForceReloadType(aLoadType)) {
NS_ASSERTION(!updateSHistory,
"We shouldn't be updating session history for forced"
" reloads!");

Просмотреть файл

@ -101,5 +101,17 @@ IsValidLoadType(uint32_t aLoadType)
return false;
}
static inline bool
IsForceReloadType(uint32_t aLoadType) {
switch (aLoadType) {
case LOAD_RELOAD_BYPASS_CACHE:
case LOAD_RELOAD_BYPASS_PROXY:
case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
return true;
}
return false;
}
#endif // MOZILLA_INTERNAL_API
#endif

Просмотреть файл

@ -560,7 +560,7 @@ Animation::CanThrottle() const
return true;
}
return mIsRunningOnCompositor;
return IsRunningOnCompositor();
}
void
@ -763,11 +763,6 @@ Animation::DoPause(ErrorResult& aRv)
reuseReadyPromise = true;
}
// Mark this as no longer running on the compositor so that next time
// we update animations we won't throttle them and will have a chance
// to remove the animation from any layer it might be on.
mIsRunningOnCompositor = false;
if (!reuseReadyPromise) {
// Clear ready promise. We'll create a new one lazily.
mReady = nullptr;
@ -1202,5 +1197,11 @@ Animation::DispatchPlaybackEvent(const nsAString& aName)
asyncDispatcher->PostDOMEvent();
}
bool
Animation::IsRunningOnCompositor() const
{
return mEffect && mEffect->IsRunningOnCompositor();
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -58,7 +58,6 @@ public:
, mPlaybackRate(1.0)
, mPendingState(PendingState::NotPending)
, mAnimationIndex(sNextAnimationIndex++)
, mIsRunningOnCompositor(false)
, mFinishedAtLastComposeStyle(false)
, mIsRelevant(false)
, mFinishedIsResolved(false)
@ -109,7 +108,7 @@ public:
virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior);
virtual void Pause(ErrorResult& aRv);
virtual void Reverse(ErrorResult& aRv);
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
bool IsRunningOnCompositor() const;
IMPL_EVENT_HANDLER(finish);
IMPL_EVENT_HANDLER(cancel);
@ -269,8 +268,6 @@ public:
*/
virtual bool HasLowerCompositeOrderThan(const Animation& aOther) const;
void SetIsRunningOnCompositor() { mIsRunningOnCompositor = true; }
void ClearIsRunningOnCompositor() { mIsRunningOnCompositor = false; }
/**
* Returns true if this animation does not currently need to update
* style on the main thread (e.g. because it is empty, or is
@ -409,7 +406,6 @@ protected:
// possible for two different objects to have the same index.
uint64_t mAnimationIndex;
bool mIsRunningOnCompositor;
bool mFinishedAtLastComposeStyle;
// Indicates that the animation should be exposed in an element's
// getAnimations() list.

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/FloatingPoint.h"
#include "AnimationCommon.h"
#include "nsCSSPropertySet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
namespace mozilla {
@ -74,6 +75,20 @@ NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadOnly)
NS_IMPL_ADDREF_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly)
NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly)
KeyframeEffectReadOnly::KeyframeEffectReadOnly(
nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming& aTiming)
: AnimationEffectReadOnly(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
ResetIsRunningOnCompositor();
}
JSObject*
KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
@ -396,5 +411,50 @@ KeyframeEffectReadOnly::ComposeStyle(nsRefPtr<AnimValuesStyleRule>& aStyleRule,
}
}
bool
KeyframeEffectReadOnly::IsRunningOnCompositor() const
{
// We consider animation is running on compositor if there is at least
// one property running on compositor.
// Animation.IsRunningOnCompotitor will return more fine grained
// information in bug 1196114.
for (bool isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
if (isPropertyRunningOnCompositor) {
return true;
}
}
return false;
}
void
KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty,
bool aIsRunning)
{
static_assert(
MOZ_ARRAY_LENGTH(LayerAnimationInfo::sRecords) ==
MOZ_ARRAY_LENGTH(mIsPropertyRunningOnCompositor),
"The length of mIsPropertyRunningOnCompositor should equal to"
"the length of LayserAnimationInfo::sRecords");
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
"Property being animated on compositor is a recognized "
"compositor-animatable property");
const auto& info = LayerAnimationInfo::sRecords;
for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
if (info[i].mProperty == aProperty) {
mIsPropertyRunningOnCompositor[i] = aIsRunning;
return;
}
}
}
void
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
{
for (bool& isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
isPropertyRunningOnCompositor = false;
}
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsIDocument.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
#include "mozilla/StickyTimeDuration.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimeStamp.h"
@ -199,14 +200,7 @@ public:
KeyframeEffectReadOnly(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming)
: AnimationEffectReadOnly(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
}
const AnimationTiming& aTiming);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly,
@ -308,9 +302,12 @@ public:
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(nsRefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties);
bool IsRunningOnCompositor() const;
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
protected:
virtual ~KeyframeEffectReadOnly() { }
void ResetIsRunningOnCompositor();
nsCOMPtr<Element> mTarget;
Nullable<TimeDuration> mParentTime;
@ -319,6 +316,17 @@ protected:
nsCSSPseudoElements::Type mPseudoType;
InfallibleTArray<AnimationProperty> mProperties;
// Parallel array corresponding to CommonAnimationManager::sLayerAnimationInfo
// such that mIsPropertyRunningOnCompositor[x] is true only if this effect has
// an animation of CommonAnimationManager::sLayerAnimationInfo[x].mProperty
// that is currently running on the compositor.
//
// Note that when the owning Animation requests a non-throttled restyle, in
// between calling RequestRestyle on its AnimationCollection and when the
// restyle is performed, this member may temporarily become false even if
// the animation remains on the layer after the restyle.
bool mIsPropertyRunningOnCompositor[LayerAnimationInfo::kRecords];
};
} // namespace dom

Просмотреть файл

@ -1,3 +1,8 @@
[DEFAULT]
support-files =
testcommon.js
../../imptests/testharness.js
../../imptests/testharnessreport.js
[chrome/test_animation_observers.html]
[chrome/test_running_on_compositor.html]
skip-if = buildapp == 'b2g'

Просмотреть файл

@ -3,18 +3,23 @@
<meta charset=utf-8>
<title>Bug 1045994 - Add a chrome-only property to inspect if an animation is
running on the compositor or not</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="../testharness.js"></script>
<script type="application/javascript" src="../testharnessreport.js"></script>
<script type="application/javascript" src="../testcommon.js"></script>
<style>
@keyframes anim {
to { transform: translate(100px) }
}
@keyframes background_and_translate {
to { background-color: red; transform: translate(100px); }
}
@keyframes background {
to { background-color: red; }
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
div {
/* Element needs geometry to be eligible for layerization */
width: 100px;
@ -26,47 +31,241 @@ div {
<body>
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1045994"
target="_blank">Mozilla Bug 1045994</a>
<div id="log"></div>
<script>
'use strict';
/** Test for bug 1045994 - Add a chrome-only property to inspect if an
animation is running on the compositor or not **/
function addDiv(attrs) {
var div = document.createElement('div');
if (attrs) {
for (var attrName in attrs) {
div.setAttribute(attrName, attrs[attrName]);
}
}
document.body.appendChild(div);
return div;
}
const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
SpecialPowers.getBoolPref(OMTAPrefKey);
add_task(function* play_and_pause_from_style() {
promise_test(function(t) {
// FIXME: When we implement Element.animate, use that here instead of CSS
// so that we remove any dependency on the CSS mapping.
var div = addDiv({ style: 'animation: anim 100s' });
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
yield animation.ready;
is(animation.isRunningOnCompositor, omtaEnabled,
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' during playback');
div.style.animationPlayState = 'paused';
yield animation.ready;
is(animation.isRunningOnCompositor, false,
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when paused');
div.parentNode.removeChild(div);
});
}));
}, '');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: background 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' for animation of "background"');
}));
}, 'isRunningOnCompositor is false for animation of "background"');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: background_and_translate 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' when the animation has two properties, where one can run'
+ ' on the compositor, the other cannot');
}));
}, 'isRunningOnCompositor is true if the animation has at least one ' +
'property can run on compositor');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.pause();
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when animation.pause() is called');
}));
}, 'isRunningOnCompositor is false when the animation.pause() is called');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.finish();
// We need to wait for two frames here to ensure isRunningOnCompositor
// flag is cleared. The first frame is for waking root refresh driver up,
// the second one is for clearing the flag.
// In most cases root refresh driver has been dormant because there is
// nothing to do for the root refresh driver (e.g. nothing change on
// chrome window). In the first frame document's refresh driver wakes the
// root refresh driver up as a result of animation's style changes.
// In the second frame the root refresh driver clears the flag as a
// result of a paint.
return waitForAnimationFrames(2);
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when animation.finish() is called');
}));
}, 'isRunningOnCompositor is false when the animation.finish() is called');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.currentTime = 100000; // 100s
// We need to wait for up to two frames here to ensure the "is running on
// compositor" flag is cleared.
// See the description in the 'isRunningOnCompositor is false when the
// animation.finish() is called' test for the rationale.
return waitForAnimationFrames(2);
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when manually seeking the animation to the end');
}));
}, 'isRunningOnCompositor is false when manually seeking the animation to ' +
'the end');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.cancel();
// We need to wait for up to two frames here to ensure the "is running on
// compositor" flag is cleared.
// See the description in the 'isRunningOnCompositor is false when the
// animation.finish() is called' test for the rationale.
return waitForAnimationFrames(2);
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when animation.cancel() is called');
}));
}, 'isRunningOnCompositor is false when animation.cancel() is called');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' while in the delay phase');
}));
}, 'isRunningOnCompositor is false while in the delay phase');
// This is to test that we don't simply clobber the flag when ticking
// animations and then set it again during painting.
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
return new Promise(t.step_func(function(resolve) {
window.requestAnimationFrame(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' in requestAnimationFrame callback');
resolve();
}));
}));
}));
}, 'isRunningOnCompositor is true in requestAnimationFrame callback');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
return new Promise(t.step_func(function(resolve) {
var observer = new MutationObserver(t.step_func(function(records) {
var changedAnimation;
records.forEach(function(record) {
changedAnimation =
record.changedAnimations.find(function(changedAnim) {
return changedAnim == animation;
});
});
assert_true(!!changedAnimation, 'The animation should be recorded '
+ 'as one of the changedAnimations');
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' in MutationObserver callback');
resolve();
}));
observer.observe(div, { animations: true, subtree: false });
div.style.animationDuration = "200s";
}));
}));
}, 'isRunningOnCompositor is true in MutationObserver callback');
// This is to test that we don't temporarily clear the flag when forcing
// an unthrottled sample.
promise_test(function(t) {
return new Promise(function(resolve) {
// Needs scrollbars to cause overflow.
SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] },
resolve);
}).then(t.step_func(function() {
var div = addDiv(t, { style: 'animation: rotate 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
return new Promise(t.step_func(function(resolve) {
var timeAtStart = window.performance.now();
function handleFrame() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' in requestAnimationFrame callback');
// we have to wait at least 200ms because this animation is
// unthrottled on every 200ms.
// See http://hg.mozilla.org/mozilla-central/file/cafb1c90f794/layout/style/AnimationCommon.cpp#l863
if (window.performance.now() - timeAtStart > 200) {
resolve();
return;
}
window.requestAnimationFrame(handleFrame);
}
window.requestAnimationFrame(handleFrame);
}));
}));
}));
}, 'isRunningOnCompositor remains true in requestAnimationFrameCallback for ' +
'overflow animation');
promise_test(function(t) {
var div = addDiv(t, { style: 'transition: opacity 100s; opacity: 1' });
getComputedStyle(div).opacity;
div.style.opacity = 0;
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Transition reports that it is running on the compositor'
+ ' during playback for opacity transition');
}));
}, 'isRunningOnCompositor for transitions');
</script>
</body>

Просмотреть файл

@ -89,20 +89,22 @@ function flushComputedStyle(elem) {
cs.marginLeft;
}
for (var funcName of ["async_test", "assert_not_equals", "assert_equals",
if (opener) {
for (var funcName of ["async_test", "assert_not_equals", "assert_equals",
"assert_approx_equals", "assert_less_than",
"assert_less_than_equal", "assert_between_inclusive",
"assert_true", "assert_false",
"assert_class_string", "assert_throws",
"assert_unreached", "test"]) {
window[funcName] = opener[funcName].bind(opener);
}
}
window.EventWatcher = opener.EventWatcher;
window.EventWatcher = opener.EventWatcher;
function done() {
function done() {
opener.add_completion_callback(function() {
self.close();
});
opener.done();
}
}

Просмотреть файл

@ -757,8 +757,8 @@ this.AppsUtils = {
return deferred.promise;
},
// Returns the MD5 hash of a string.
computeHash: function(aString) {
// Returns the hash of a string, with MD5 as a default hashing function.
computeHash: function(aString, aAlgorithm = "MD5") {
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
@ -768,7 +768,7 @@ this.AppsUtils = {
let hasher = Cc["@mozilla.org/security/hash;1"]
.createInstance(Ci.nsICryptoHash);
hasher.init(hasher.MD5);
hasher.initWithString(aAlgorithm);
hasher.update(data, data.length);
// We're passing false to get the binary hash and not base64.
let hash = hasher.finish(false);

Просмотреть файл

@ -135,8 +135,8 @@ class DestinationInsertionPointList;
// IID for the dom::Element interface
#define NS_ELEMENT_IID \
{ 0x31d3f3fb, 0xcdf8, 0x4e40, \
{ 0xb7, 0x09, 0x1a, 0x11, 0x43, 0x93, 0x61, 0x71 } }
{ 0xc67ed254, 0xfd3b, 0x4b10, \
{ 0x96, 0xa2, 0xc5, 0x8b, 0x7b, 0x64, 0x97, 0xd1 } }
class Element : public FragmentOrElement
{

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/css/Loader.h"
#include "mozilla/css/ImageLoader.h"
#include "nsDocShell.h"
#include "nsDocShellLoadTypes.h"
#include "nsIDocShellTreeItem.h"
#include "nsCOMArray.h"
#include "nsQueryObject.h"
@ -4730,15 +4731,13 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
}
nsCOMPtr<nsIChannel> channel = GetChannel();
if (!mMaybeServiceWorkerControlled && channel) {
nsLoadFlags loadFlags = 0;
channel->GetLoadFlags(&loadFlags);
if (!mMaybeServiceWorkerControlled && mDocumentContainer && mScriptGlobalObject && GetChannel()) {
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
uint32_t loadType;
docShell->GetLoadType(&loadType);
// If we are shift-reloaded, don't associate with a ServiceWorker.
// TODO: This should check the nsDocShell definition of shift-reload instead
// of trying to infer it from LOAD_BYPASS_CACHE. The current code
// will probably cause problems once bug 1120715 lands.
if (loadFlags & nsIRequest::LOAD_BYPASS_CACHE) {
if (IsForceReloadType(loadType)) {
NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
return;
}

Просмотреть файл

@ -12,8 +12,8 @@
class nsDOMAttributeMap;
#define NS_IATTRIBUTE_IID \
{ 0x233a9c4d, 0xb27f, 0x4662, \
{ 0xbd, 0x90, 0xba, 0xd6, 0x2e, 0x76, 0xc8, 0xe1 } }
{ 0x84d43da7, 0xb45d, 0x47ae, \
{ 0x8f, 0xbf, 0x95, 0x26, 0x78, 0x4d, 0x5e, 0x47 } }
class nsIAttribute : public nsINode
{

Просмотреть файл

@ -40,8 +40,8 @@ enum nsLinkState {
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0x70f7e9ea, 0xa9bf, 0x48cc, \
{ 0xad, 0x9d, 0x8a, 0xca, 0xee, 0xd2, 0x9b, 0x68 } }
{ 0x52cebfc8, 0x79ba, 0x4e38, \
{ 0x8a, 0x4c, 0x7f, 0x9d, 0xb1, 0xa2, 0xb6, 0x1d } }
/**
* A node of content in a document's content model. This interface

Просмотреть файл

@ -155,8 +155,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0x292450a1, 0x285e, 0x4a09, \
{ 0x9a, 0xf9, 0x61, 0xf9, 0xb1, 0xbd, 0x27, 0xcc } }
{ 0x72391609, 0x673d, 0x4bec, \
{ 0xbd, 0x75, 0x64, 0xbf, 0x1f, 0x6a, 0x6b, 0x5e } }
// Enum for requesting a particular type of document when creating a doc
enum DocumentFlavor {

Просмотреть файл

@ -2833,3 +2833,12 @@ nsINode::AddAnimationObserverUnlessExists(
AddMutationObserverUnlessExists(aAnimationObserver);
OwnerDoc()->SetMayHaveAnimationObservers();
}
bool
nsINode::HasApzAwareListeners() const
{
if (NodeMayHaveApzAwareListeners()) {
return EventTarget::HasApzAwareListeners();
}
return false;
}

Просмотреть файл

@ -250,8 +250,8 @@ private:
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0xe8fdd227, 0x27da, 0x46ee, \
{ 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 } }
{ 0x70ba4547, 0x7699, 0x44fc, \
{ 0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -949,6 +949,9 @@ public:
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
mozilla::ErrorResult& aRv) override;
using nsIDOMEventTarget::AddSystemEventListener;
virtual bool HasApzAwareListeners() const override;
virtual nsIDOMWindow* GetOwnerGlobalForBindings() override;
virtual nsIGlobalObject* GetOwnerGlobal() const override;
@ -1495,6 +1498,8 @@ private:
ElementHasWeirdParserInsertionMode,
// Parser sets this flag if it has notified about the node.
ParserHasNotified,
// EventListenerManager sets this flag in case we have apz aware listeners.
MayHaveApzAwareListeners,
// Guard value
BooleanFlagCount
};
@ -1637,6 +1642,12 @@ public:
void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); }
void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); };
bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); }
void SetMayHaveApzAwareListeners() { SetBoolFlag(MayHaveApzAwareListeners); }
bool NodeMayHaveApzAwareListeners() const
{
return GetBoolFlag(MayHaveApzAwareListeners);
}
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
void SetInDocument() { SetBoolFlag(IsInDocument); }

Просмотреть файл

@ -22,8 +22,8 @@ class TabParent;
} // namespace mozilla
#define NS_IWINDOWROOT_IID \
{ 0x238edca0, 0xb30d, 0x46d3, \
{ 0xb2, 0x6a, 0x17, 0xb6, 0x21, 0x28, 0x89, 0x7e } }
{ 0xb8724c49, 0xc398, 0x4f9b, \
{ 0x82, 0x59, 0x87, 0x27, 0xa6, 0x47, 0xdd, 0x0f } }
class nsPIWindowRoot : public mozilla::dom::EventTarget
{

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,346 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothDaemonCoreInterface_h
#define mozilla_dom_bluetooth_bluedroid_BluetoothDaemonCoreInterface_h
#include "BluetoothDaemonHelpers.h"
#include "BluetoothInterface.h"
#include "mozilla/ipc/DaemonRunnables.h"
BEGIN_BLUETOOTH_NAMESPACE
using mozilla::ipc::DaemonSocketPDU;
using mozilla::ipc::DaemonSocketPDUHeader;
using mozilla::ipc::DaemonSocketResultHandler;
class BluetoothDaemonCoreModule
{
public:
enum {
SERVICE_ID = 0x01
};
enum {
OPCODE_ERROR = 0x00,
OPCODE_ENABLE = 0x01,
OPCODE_DISABLE = 0x02,
OPCODE_GET_ADAPTER_PROPERTIES = 0x03,
OPCODE_GET_ADAPTER_PROPERTY = 0x04,
OPCODE_SET_ADAPTER_PROPERTY = 0x05,
OPCODE_GET_REMOTE_DEVICE_PROPERTIES = 0x06,
OPCODE_GET_REMOTE_DEVICE_PROPERTY = 0x07,
OPCODE_SET_REMOTE_DEVICE_PROPERTY = 0x08,
OPCODE_GET_REMOTE_SERVICE_RECORD = 0x09,
OPCODE_GET_REMOTE_SERVICES = 0x0a,
OPCODE_START_DISCOVERY = 0x0b,
OPCODE_CANCEL_DISCOVERY = 0x0c,
OPCODE_CREATE_BOND = 0x0d,
OPCODE_REMOVE_BOND = 0x0e,
OPCODE_CANCEL_BOND = 0x0f,
OPCODE_PIN_REPLY = 0x10,
OPCODE_SSP_REPLY = 0x11,
OPCODE_DUT_MODE_CONFIGURE = 0x12,
OPCODE_DUT_MODE_SEND = 0x13,
OPCODE_LE_TEST_MODE = 0x14,
OPCODE_ADAPTER_STATE_CHANGED_NTF = 0x81,
OPCODE_ADAPTER_PROPERTIES_NTF = 0x82,
OPCODE_REMOTE_DEVICE_PROPERTIES_NTF = 0x83,
OPCODE_DEVICE_FOUND_NTF = 0x84,
OPCODE_DISCOVERY_STATE_CHANGED_NTF = 0x85,
OPCODE_PIN_REQUEST_NTF = 0x86,
OPCODE_SSP_REQUEST_NTF = 0x87,
OPCODE_BOND_STATE_CHANGED_NTF = 0x88,
OPCODE_ACL_STATE_CHANGED_NTF = 0x89,
OPCODE_DUT_MODE_RECV_NTF = 0x8a,
OPCODE_LE_TEST_MODE_NTF = 0x8b
};
static const int MAX_NUM_CLIENTS;
virtual nsresult Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes) = 0;
void SetNotificationHandler(
BluetoothNotificationHandler* aNotificationHandler);
BluetoothNotificationHandler* GetNotificationHandler();
//
// Commands
//
nsresult EnableCmd(BluetoothResultHandler* aRes);
nsresult DisableCmd(BluetoothResultHandler* aRes);
nsresult GetAdapterPropertiesCmd(BluetoothResultHandler* aRes);
nsresult GetAdapterPropertyCmd(const nsAString& aName,
BluetoothResultHandler* aRes);
nsresult SetAdapterPropertyCmd(const BluetoothNamedValue& aProperty,
BluetoothResultHandler* aRes);
nsresult GetRemoteDevicePropertiesCmd(const nsAString& aRemoteAddr,
BluetoothResultHandler* aRes);
nsresult GetRemoteDevicePropertyCmd(const nsAString& aRemoteAddr,
const nsAString& aName,
BluetoothResultHandler* aRes);
nsresult SetRemoteDevicePropertyCmd(const nsAString& aRemoteAddr,
const BluetoothNamedValue& aProperty,
BluetoothResultHandler* aRes);
nsresult GetRemoteServiceRecordCmd(const nsAString& aRemoteAddr,
const uint8_t aUuid[16],
BluetoothResultHandler* aRes);
nsresult GetRemoteServicesCmd(const nsAString& aRemoteAddr,
BluetoothResultHandler* aRes);
nsresult StartDiscoveryCmd(BluetoothResultHandler* aRes);
nsresult CancelDiscoveryCmd(BluetoothResultHandler* aRes);
nsresult CreateBondCmd(const nsAString& aBdAddr,
BluetoothTransport aTransport,
BluetoothResultHandler* aRes);
nsresult RemoveBondCmd(const nsAString& aBdAddr,
BluetoothResultHandler* aRes);
nsresult CancelBondCmd(const nsAString& aBdAddr,
BluetoothResultHandler* aRes);
nsresult PinReplyCmd(const nsAString& aBdAddr, bool aAccept,
const nsAString& aPinCode,
BluetoothResultHandler* aRes);
nsresult SspReplyCmd(const nsAString& aBdAddr, BluetoothSspVariant aVariant,
bool aAccept, uint32_t aPasskey,
BluetoothResultHandler* aRes);
nsresult DutModeConfigureCmd(bool aEnable, BluetoothResultHandler* aRes);
nsresult DutModeSendCmd(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
BluetoothResultHandler* aRes);
nsresult LeTestModeCmd(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
BluetoothResultHandler* aRes);
protected:
void HandleSvc(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes);
private:
//
// Responses
//
typedef mozilla::ipc::DaemonResultRunnable0<
BluetoothResultHandler, void>
ResultRunnable;
typedef mozilla::ipc::DaemonResultRunnable1<
BluetoothResultHandler, void, BluetoothStatus, BluetoothStatus>
ErrorRunnable;
void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void EnableRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void DisableRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void GetAdapterPropertiesRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void GetAdapterPropertyRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void SetAdapterPropertyRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void GetRemoteDevicePropertiesRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void
GetRemoteDevicePropertyRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void SetRemoteDevicePropertyRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void GetRemoteServiceRecordRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void GetRemoteServicesRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void StartDiscoveryRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void CancelDiscoveryRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void CreateBondRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void RemoveBondRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void CancelBondRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void PinReplyRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void SspReplyRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void DutModeConfigureRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void DutModeSendRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void LeTestModeRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
BluetoothResultHandler* aRes);
void HandleRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes);
//
// Notifications
//
class NotificationHandlerWrapper;
typedef mozilla::ipc::DaemonNotificationRunnable1<
NotificationHandlerWrapper, void, bool>
AdapterStateChangedNotification;
typedef mozilla::ipc::DaemonNotificationRunnable3<
NotificationHandlerWrapper, void, BluetoothStatus, int,
nsAutoArrayPtr<BluetoothProperty>, BluetoothStatus, int,
const BluetoothProperty*>
AdapterPropertiesNotification;
typedef mozilla::ipc::DaemonNotificationRunnable4<
NotificationHandlerWrapper, void, BluetoothStatus, nsString, int,
nsAutoArrayPtr<BluetoothProperty>, BluetoothStatus, const nsAString&,
int, const BluetoothProperty*>
RemoteDevicePropertiesNotification;
typedef mozilla::ipc::DaemonNotificationRunnable2<
NotificationHandlerWrapper, void, int, nsAutoArrayPtr<BluetoothProperty>,
int, const BluetoothProperty*>
DeviceFoundNotification;
typedef mozilla::ipc::DaemonNotificationRunnable1<
NotificationHandlerWrapper, void, bool>
DiscoveryStateChangedNotification;
typedef mozilla::ipc::DaemonNotificationRunnable3<
NotificationHandlerWrapper, void, nsString, nsString, uint32_t,
const nsAString&, const nsAString&>
PinRequestNotification;
typedef mozilla::ipc::DaemonNotificationRunnable5<
NotificationHandlerWrapper, void, nsString, nsString, uint32_t,
BluetoothSspVariant, uint32_t, const nsAString&, const nsAString&>
SspRequestNotification;
typedef mozilla::ipc::DaemonNotificationRunnable3<
NotificationHandlerWrapper, void, BluetoothStatus, nsString,
BluetoothBondState, BluetoothStatus, const nsAString&>
BondStateChangedNotification;
typedef mozilla::ipc::DaemonNotificationRunnable3<
NotificationHandlerWrapper, void, BluetoothStatus, nsString, bool,
BluetoothStatus, const nsAString&>
AclStateChangedNotification;
typedef mozilla::ipc::DaemonNotificationRunnable3<
NotificationHandlerWrapper, void, uint16_t, nsAutoArrayPtr<uint8_t>,
uint8_t, uint16_t, const uint8_t*>
DutModeRecvNotification;
typedef mozilla::ipc::DaemonNotificationRunnable2<
NotificationHandlerWrapper, void, BluetoothStatus, uint16_t>
LeTestModeNotification;
class AclStateChangedInitOp;
class AdapterPropertiesInitOp;
class BondStateChangedInitOp;
class DeviceFoundInitOp;
class DutModeRecvInitOp;
class PinRequestInitOp;
class RemoteDevicePropertiesInitOp;
class SspRequestInitOp;
void AdapterStateChangedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void AdapterPropertiesNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void RemoteDevicePropertiesNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void DeviceFoundNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void DiscoveryStateChangedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void PinRequestNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void SspRequestNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void BondStateChangedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void AclStateChangedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void DutModeRecvNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void LeTestModeNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void HandleNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes);
static BluetoothNotificationHandler* sNotificationHandler;
};
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonCoreInterface_h

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -32,7 +32,9 @@ BluetoothDaemonSocketModule::ListenCmd(BluetoothSocketType aType,
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<DaemonSocketPDU> pdu(new DaemonSocketPDU(0x02, 0x01, 0));
nsAutoPtr<DaemonSocketPDU> pdu(
new DaemonSocketPDU(SERVICE_ID, OPCODE_LISTEN,
0));
nsresult rv = PackPDU(
aType,
@ -61,7 +63,9 @@ BluetoothDaemonSocketModule::ConnectCmd(const nsAString& aBdAddr,
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<DaemonSocketPDU> pdu(new DaemonSocketPDU(0x02, 0x02, 0));
nsAutoPtr<DaemonSocketPDU> pdu(
new DaemonSocketPDU(SERVICE_ID, OPCODE_CONNECT,
0));
nsresult rv = PackPDU(
PackConversion<nsAString, BluetoothAddress>(aBdAddr),
@ -166,9 +170,9 @@ BluetoothDaemonSocketModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
const DaemonSocketPDUHeader&,
DaemonSocketPDU&,
BluetoothSocketResultHandler*) = {
[0x00] = &BluetoothDaemonSocketModule::ErrorRsp,
[0x01] = &BluetoothDaemonSocketModule::ListenRsp,
[0x02] = &BluetoothDaemonSocketModule::ConnectRsp
[OPCODE_ERROR] = &BluetoothDaemonSocketModule::ErrorRsp,
[OPCODE_LISTEN] = &BluetoothDaemonSocketModule::ListenRsp,
[OPCODE_CONNECT] = &BluetoothDaemonSocketModule::ConnectRsp
};
if (NS_WARN_IF(MOZ_ARRAY_LENGTH(HandleRsp) <= aHeader.mOpcode) ||

Просмотреть файл

@ -20,6 +20,16 @@ using mozilla::ipc::DaemonSocketResultHandler;
class BluetoothDaemonSocketModule
{
public:
enum {
SERVICE_ID = 0x02
};
enum {
OPCODE_ERROR = 0x00,
OPCODE_LISTEN = 0x01,
OPCODE_CONNECT = 0x02
};
static const int MAX_NUM_CLIENTS;
virtual nsresult Send(DaemonSocketPDU* aPDU,

Просмотреть файл

@ -74,6 +74,7 @@ if CONFIG['MOZ_B2G_BT']:
'bluedroid/BluetoothAvrcpManager.cpp',
'bluedroid/BluetoothDaemonA2dpInterface.cpp',
'bluedroid/BluetoothDaemonAvrcpInterface.cpp',
'bluedroid/BluetoothDaemonCoreInterface.cpp',
'bluedroid/BluetoothDaemonGattInterface.cpp',
'bluedroid/BluetoothDaemonHandsfreeInterface.cpp',
'bluedroid/BluetoothDaemonHelpers.cpp',

Просмотреть файл

@ -72,7 +72,8 @@ var CopyPasteAssistent = {
collapsed: e.collapsed,
caretVisible: e.caretVisible,
selectionVisible: e.selectionVisible,
selectionEditable: e.selectionEditable
selectionEditable: e.selectionEditable,
selectedTextContent: e.selectedTextContent
};
// Get correct geometry information if we have nested iframe.

Просмотреть файл

@ -459,6 +459,8 @@ BrowserElementParent.prototype = {
// - caretVisible: Indicate the caret visiibility.
// - selectionVisible: Indicate current selection is visible or not.
// - selectionEditable: Indicate current selection is editable or not.
// - selectedTextContent: Contains current selected text content, which is
// equivalent to the string returned by Selection.toString().
_handleCaretStateChanged: function(data) {
let evt = this._createEvent('caretstatechanged', data.json,
/* cancelable = */ false);

Просмотреть файл

@ -405,6 +405,13 @@ EventListenerManager::AddEventListenerInternal(
}
}
if (IsApzAwareEvent(aTypeAtom)) {
nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
if (node) {
node->SetMayHaveApzAwareListeners();
}
}
if (aTypeAtom && mTarget) {
mTarget->EventListenerAdded(aTypeAtom);
}
@ -1490,6 +1497,30 @@ EventListenerManager::TraceListeners(JSTracer* aTrc)
}
}
bool
EventListenerManager::HasApzAwareListeners()
{
uint32_t count = mListeners.Length();
for (uint32_t i = 0; i < count; ++i) {
Listener* listener = &mListeners.ElementAt(i);
if (IsApzAwareEvent(listener->mTypeAtom)) {
return true;
}
}
return false;
}
bool
EventListenerManager::IsApzAwareEvent(nsIAtom* aEvent)
{
return aEvent == nsGkAtoms::ontouchstart ||
aEvent == nsGkAtoms::ontouchmove ||
aEvent == nsGkAtoms::onwheel ||
aEvent == nsGkAtoms::onDOMMouseScroll ||
aEvent == nsHtml5Atoms::onmousewheel ||
aEvent == nsGkAtoms::onMozMousePixelScroll;
}
already_AddRefed<nsIScriptGlobalObject>
EventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
{

Просмотреть файл

@ -443,6 +443,10 @@ public:
dom::EventTarget* GetTarget() { return mTarget; }
bool HasApzAwareListeners();
bool IsApzAwareEvent(nsIAtom* aEvent);
protected:
void HandleEventInternal(nsPresContext* aPresContext,
WidgetEvent* aEvent,

Просмотреть файл

@ -56,5 +56,12 @@ EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
GetOrCreateListenerManager()->SetEventHandler(aType, aTypeString, aHandler);
}
bool
EventTarget::HasApzAwareListeners() const
{
EventListenerManager* elm = GetExistingListenerManager();
return elm && elm->HasApzAwareListeners();
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -28,8 +28,8 @@ template <class T> struct Nullable;
// IID for the dom::EventTarget interface
#define NS_EVENTTARGET_IID \
{ 0x605158a9, 0xe229, 0x45b1, \
{ 0xbc, 0x12, 0x02, 0x9f, 0xa3, 0xa9, 0x3f, 0xcb } }
{ 0xde651c36, 0x0053, 0x4c67, \
{ 0xb1, 0x3d, 0x67, 0xb9, 0x40, 0xfc, 0x82, 0xe4 } }
class EventTarget : public nsIDOMEventTarget,
public nsWrapperCache
@ -88,6 +88,8 @@ public:
*/
virtual EventListenerManager* GetExistingListenerManager() const = 0;
virtual bool HasApzAwareListeners() const;
protected:
EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
const nsAString& aTypeString);

Просмотреть файл

@ -232,7 +232,7 @@ HTMLVideoElement::GetVideoPlaybackQuality()
}
if (mDecoder) {
MediaDecoder::FrameStatistics& stats = mDecoder->GetFrameStatistics();
FrameStatistics& stats = mDecoder->GetFrameStatistics();
totalFrames = stats.GetParsedFrames();
droppedFrames = stats.GetDroppedFrames();
corruptedFrames = 0;

Просмотреть файл

@ -45,10 +45,12 @@ this.Keyboard = {
_keyboardMM: null, // The keyboard app message manager.
_keyboardID: -1, // The keyboard app's ID number. -1 = invalid
_nextKeyboardID: 0, // The ID number counter.
_systemMMs: [], // The message managers registered to handle system async
// messages.
_supportsSwitchingTypes: [],
_systemMessageNames: [
'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions',
'SetSupportsSwitchingTypes'
'SetSupportsSwitchingTypes', 'RegisterSync', 'Unregister'
],
_messageNames: [
@ -57,7 +59,7 @@ this.Keyboard = {
'SwitchToNextInputMethod', 'HideInputMethod',
'GetText', 'SendKey', 'GetContext',
'SetComposition', 'EndComposition',
'Register', 'Unregister'
'RegisterSync', 'Unregister'
],
get formMM() {
@ -89,6 +91,20 @@ this.Keyboard = {
} catch(e) { }
},
sendToSystem: function(name, data) {
if (!this._systemMMs.length) {
dump("Keyboard.jsm: Attempt to send message " + name +
" to system but no message manager registered.\n");
return;
}
this._systemMMs.forEach((mm, i) => {
data.inputManageId = i;
mm.sendAsyncMessage(name, data);
});
},
init: function keyboardInit() {
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
Services.obs.addObserver(this, 'remote-browser-shown', false);
@ -124,10 +140,14 @@ this.Keyboard = {
// keyboard app that the focus has been lost.
this.sendToKeyboard('Keyboard:Blur', {});
// Notify system app to hide keyboard.
this.sendToSystem('System:Blur', {});
// XXX: To be removed when content migrate away from mozChromeEvents.
SystemAppProxy.dispatchEvent({
type: 'inputmethod-contextchange',
inputType: 'blur'
});
this.formMM = null;
}
} else {
// Ignore notifications that aren't from a BrowserOrApp
@ -193,7 +213,7 @@ this.Keyboard = {
}
if (0 === msg.name.indexOf('Keyboard:') &&
('Keyboard:Register' !== msg.name && this._keyboardID !== kbID)
('Keyboard:RegisterSync' !== msg.name && this._keyboardID !== kbID)
) {
return;
}
@ -228,6 +248,24 @@ this.Keyboard = {
case 'Keyboard:RemoveFocus':
case 'System:RemoveFocus':
this.removeFocus();
break;
case 'System:RegisterSync': {
if (this._systemMMs.length !== 0) {
dump('Keyboard.jsm Warning: There are more than one content page ' +
'with input-manage permission. There will be undeterministic ' +
'responses to addInput()/removeInput() if both content pages are ' +
'trying to respond to the same request event.\n');
}
let id = this._systemMMs.length;
this._systemMMs.push(mm);
return id;
}
case 'System:Unregister':
this._systemMMs.splice(msg.data.id, 1);
break;
case 'System:SetSelectedOption':
this.setSelectedOption(msg);
@ -265,7 +303,7 @@ this.Keyboard = {
case 'Keyboard:EndComposition':
this.endComposition(msg);
break;
case 'Keyboard:Register':
case 'Keyboard:RegisterSync':
this._keyboardMM = mm;
if (kbID) {
// keyboard identifies itself, use its kbID
@ -293,10 +331,14 @@ this.Keyboard = {
.frameLoader.messageManager;
this.formMM = mm;
// Notify the current active input app to gain focus.
this.forwardEvent('Keyboard:Focus', msg);
// Chrome event, used also to render value selectors; that's why we need
// the info about choices / min / max here as well...
// Notify System app, used also to render value selectors for now;
// that's why we need the info about choices / min / max here as well...
this.sendToSystem('System:Focus', msg.data);
// XXX: To be removed when content migrate away from mozChromeEvents.
SystemAppProxy.dispatchEvent({
type: 'inputmethod-contextchange',
inputType: msg.data.inputType,
@ -322,7 +364,9 @@ this.Keyboard = {
this.formMM = null;
this.forwardEvent('Keyboard:Blur', msg);
this.sendToSystem('System:Blur', {});
// XXX: To be removed when content migrate away from mozChromeEvents.
SystemAppProxy.dispatchEvent({
type: 'inputmethod-contextchange',
inputType: 'blur'
@ -362,12 +406,18 @@ this.Keyboard = {
},
showInputMethodPicker: function keyboardShowInputMethodPicker() {
this.sendToSystem('System:ShowAll', {});
// XXX: To be removed with mozContentEvent support from shell.js
SystemAppProxy.dispatchEvent({
type: "inputmethod-showall"
});
},
switchToNextInputMethod: function keyboardSwitchToNextInputMethod() {
this.sendToSystem('System:Next', {});
// XXX: To be removed with mozContentEvent support from shell.js
SystemAppProxy.dispatchEvent({
type: "inputmethod-next"
});
@ -432,14 +482,17 @@ function InputRegistryGlue() {
ppmm.addMessageListener('InputRegistry:Add', this);
ppmm.addMessageListener('InputRegistry:Remove', this);
ppmm.addMessageListener('System:InputRegistry:Add:Done', this);
ppmm.addMessageListener('System:InputRegistry:Remove:Done', this);
};
InputRegistryGlue.prototype.receiveMessage = function(msg) {
let mm = Utils.getMMFromMessage(msg);
if (!Utils.checkPermissionForMM(mm, 'input')) {
let permName = msg.name.startsWith("System:") ? "input-mgmt" : "input";
if (!Utils.checkPermissionForMM(mm, permName)) {
dump("InputRegistryGlue message " + msg.name +
" from a content process with no 'input' privileges.");
" from a content process with no " + permName + " privileges.");
return;
}
@ -452,6 +505,12 @@ InputRegistryGlue.prototype.receiveMessage = function(msg) {
case 'InputRegistry:Remove':
this.removeInput(msg, mm);
break;
case 'System:InputRegistry:Add:Done':
case 'System:InputRegistry:Remove:Done':
this.returnMessage(msg.data);
break;
}
};
@ -465,6 +524,14 @@ InputRegistryGlue.prototype.addInput = function(msg, mm) {
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
Keyboard.sendToSystem('System:InputRegistry:Add', {
id: msgId,
manifestURL: manifestURL,
inputId: msg.data.inputId,
inputManifest: msg.data.inputManifest
});
// XXX: To be removed when content migrate away from mozChromeEvents.
SystemAppProxy.dispatchEvent({
type: 'inputregistry-add',
id: msgId,
@ -483,6 +550,13 @@ InputRegistryGlue.prototype.removeInput = function(msg, mm) {
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
Keyboard.sendToSystem('System:InputRegistry:Remove', {
id: msgId,
manifestURL: manifestURL,
inputId: msg.data.inputId
});
// XXX: To be removed when content migrate away from mozChromeEvents.
SystemAppProxy.dispatchEvent({
type: 'inputregistry-remove',
id: msgId,
@ -493,6 +567,8 @@ InputRegistryGlue.prototype.removeInput = function(msg, mm) {
InputRegistryGlue.prototype.returnMessage = function(detail) {
if (!this._msgMap.has(detail.id)) {
dump('InputRegistryGlue: Ignoring already handled message response. ' +
'id=' + detail.id + '\n');
return;
}
@ -500,6 +576,7 @@ InputRegistryGlue.prototype.returnMessage = function(detail) {
this._msgMap.delete(detail.id);
if (Cu.isDeadWrapper(mm)) {
dump('InputRegistryGlue: Message manager has already died.\n');
return;
}

Просмотреть файл

@ -7,6 +7,7 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -143,6 +144,54 @@ MozInputMethodManager.prototype = {
QueryInterface: XPCOMUtils.generateQI([]),
set oninputcontextfocus(handler) {
this.__DOM_IMPL__.setEventHandler("oninputcontextfocus", handler);
},
get oninputcontextfocus() {
return this.__DOM_IMPL__.getEventHandler("oninputcontextfocus");
},
set oninputcontextblur(handler) {
this.__DOM_IMPL__.setEventHandler("oninputcontextblur", handler);
},
get oninputcontextblur() {
return this.__DOM_IMPL__.getEventHandler("oninputcontextblur");
},
set onshowallrequest(handler) {
this.__DOM_IMPL__.setEventHandler("onshowallrequest", handler);
},
get onshowallrequest() {
return this.__DOM_IMPL__.getEventHandler("onshowallrequest");
},
set onnextrequest(handler) {
this.__DOM_IMPL__.setEventHandler("onnextrequest", handler);
},
get onnextrequest() {
return this.__DOM_IMPL__.getEventHandler("onnextrequest");
},
set onaddinputrequest(handler) {
this.__DOM_IMPL__.setEventHandler("onaddinputrequest", handler);
},
get onaddinputrequest() {
return this.__DOM_IMPL__.getEventHandler("onaddinputrequest");
},
set onremoveinputrequest(handler) {
this.__DOM_IMPL__.setEventHandler("onremoveinputrequest", handler);
},
get onremoveinputrequest() {
return this.__DOM_IMPL__.getEventHandler("onremoveinputrequest");
},
showAll: function() {
if (!WindowMap.isActive(this._window)) {
return;
@ -175,6 +224,169 @@ MozInputMethodManager.prototype = {
cpmm.sendAsyncMessage('System:SetSupportsSwitchingTypes', {
types: types
});
},
handleFocus: function(data) {
let detail = new MozInputContextFocusEventDetail(this._window, data);
let wrappedDetail =
this._window.MozInputContextFocusEventDetail._create(this._window, detail);
let event = new this._window.CustomEvent('inputcontextfocus',
{ cancelable: true, detail: wrappedDetail });
let handled = !this.__DOM_IMPL__.dispatchEvent(event);
// A gentle warning if the event is not preventDefault() by the content.
if (!handled) {
dump('MozKeyboard.js: A frame with input-manage permission did not' +
' handle the inputcontextfocus event dispatched.\n');
}
},
handleBlur: function(data) {
let event =
new this._window.Event('inputcontextblur', { cancelable: true });
let handled = !this.__DOM_IMPL__.dispatchEvent(event);
// A gentle warning if the event is not preventDefault() by the content.
if (!handled) {
dump('MozKeyboard.js: A frame with input-manage permission did not' +
' handle the inputcontextblur event dispatched.\n');
}
},
dispatchShowAllRequestEvent: function() {
this._fireSimpleEvent('showallrequest');
},
dispatchNextRequestEvent: function() {
this._fireSimpleEvent('nextrequest');
},
_fireSimpleEvent: function(eventType) {
let event = new this._window.Event(eventType);
let handled = !this.__DOM_IMPL__.dispatchEvent(event, { cancelable: true });
// A gentle warning if the event is not preventDefault() by the content.
if (!handled) {
dump('MozKeyboard.js: A frame with input-manage permission did not' +
' handle the ' + eventType + ' event dispatched.\n');
}
},
handleAddInput: function(data) {
let p = this._fireInputRegistryEvent('addinputrequest', data);
if (!p) {
return;
}
p.then(() => {
cpmm.sendAsyncMessage('System:InputRegistry:Add:Done', {
id: data.id
});
}, (error) => {
cpmm.sendAsyncMessage('System:InputRegistry:Add:Done', {
id: data.id,
error: error || 'Unknown Error'
});
});
},
handleRemoveInput: function(data) {
let p = this._fireInputRegistryEvent('removeinputrequest', data);
if (!p) {
return;
}
p.then(() => {
cpmm.sendAsyncMessage('System:InputRegistry:Remove:Done', {
id: data.id
});
}, (error) => {
cpmm.sendAsyncMessage('System:InputRegistry:Remove:Done', {
id: data.id,
error: error || 'Unknown Error'
});
});
},
_fireInputRegistryEvent: function(eventType, data) {
let detail = new MozInputRegistryEventDetail(this._window, data);
let wrappedDetail =
this._window.MozInputRegistryEventDetail._create(this._window, detail);
let event = new this._window.CustomEvent(eventType,
{ cancelable: true, detail: wrappedDetail });
let handled = !this.__DOM_IMPL__.dispatchEvent(event);
// A gentle warning if the event is not preventDefault() by the content.
if (!handled) {
dump('MozKeyboard.js: A frame with input-manage permission did not' +
' handle the ' + eventType + ' event dispatched.\n');
return null;
}
return detail.takeChainedPromise();
}
};
function MozInputContextFocusEventDetail(win, data) {
this.type = data.type;
this.inputType = data.inputType;
this.value = data.value;
// Exposed as MozInputContextChoicesInfo dictionary defined in WebIDL
this.choices = data.choices;
this.min = data.min;
this.max = data.max;
}
MozInputContextFocusEventDetail.prototype = {
classID: Components.ID("{e0794208-ac50-40e8-b22e-6ee0b4c4e6e8}"),
QueryInterface: XPCOMUtils.generateQI([]),
type: undefined,
inputType: undefined,
value: '',
choices: null,
min: undefined,
max: undefined
};
function MozInputRegistryEventDetail(win, data) {
this._window = win;
this.manifestURL = data.manifestURL;
this.inputId = data.inputId;
// Exposed as MozInputMethodInputManifest dictionary defined in WebIDL
this.inputManifest = data.inputManifest;
this._chainedPromise = Promise.resolve();
}
MozInputRegistryEventDetail.prototype = {
classID: Components.ID("{02130070-9b3e-4f38-bbd9-f0013aa36717}"),
QueryInterface: XPCOMUtils.generateQI([]),
_window: null,
manifestURL: undefined,
inputId: undefined,
inputManifest: null,
waitUntil: function(p) {
// Need an extra protection here since waitUntil will be an no-op
// when chainedPromise is already returned.
if (!this._chainedPromise) {
throw new this._window.DOMException(
'Must call waitUntil() within the event handling loop.',
'InvalidStateError');
}
this._chainedPromise = this._chainedPromise
.then(function() { return p; });
},
takeChainedPromise: function() {
var p = this._chainedPromise;
this._chainedPromise = null;
return p;
}
};
@ -188,10 +400,13 @@ function MozInputMethod() { }
MozInputMethod.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_window: null,
_inputcontext: null,
_wrappedInputContext: null,
_mgmt: null,
_wrappedMgmt: null,
_supportsSwitchingTypes: [],
_window: null,
_inputManageId: undefined,
classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
@ -204,6 +419,7 @@ MozInputMethod.prototype = {
init: function mozInputMethodInit(win) {
this._window = win;
this._mgmt = new MozInputMethodManager(win);
this._wrappedMgmt = win.MozInputMethodManager._create(win, this._mgmt);
this.innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
@ -217,11 +433,22 @@ MozInputMethod.prototype = {
cpmm.addWeakMessageListener('Keyboard:SupportsSwitchingTypesChange', this);
cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
if (this._hasInputManagePerm(win)) {
this._inputManageId = cpmm.sendSyncMessage('System:RegisterSync', {})[0];
cpmm.addWeakMessageListener('System:Focus', this);
cpmm.addWeakMessageListener('System:Blur', this);
cpmm.addWeakMessageListener('System:ShowAll', this);
cpmm.addWeakMessageListener('System:Next', this);
cpmm.addWeakMessageListener('System:InputRegistry:Add', this);
cpmm.addWeakMessageListener('System:InputRegistry:Remove', this);
}
},
uninit: function mozInputMethodUninit() {
this._window = null;
this._mgmt = null;
this._wrappedMgmt = null;
cpmm.removeWeakMessageListener('Keyboard:Focus', this);
cpmm.removeWeakMessageListener('Keyboard:Blur', this);
@ -231,15 +458,34 @@ MozInputMethod.prototype = {
cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
this.setActive(false);
if (typeof this._inputManageId === 'number') {
cpmm.sendAsyncMessage('System:Unregister', {
'id': this._inputManageId
});
cpmm.removeWeakMessageListener('System:Focus', this);
cpmm.removeWeakMessageListener('System:Blur', this);
cpmm.removeWeakMessageListener('System:ShowAll', this);
cpmm.removeWeakMessageListener('System:Next', this);
cpmm.removeWeakMessageListener('System:InputRegistry:Add', this);
cpmm.removeWeakMessageListener('System:InputRegistry:Remove', this);
}
},
receiveMessage: function mozInputMethodReceiveMsg(msg) {
if (!msg.name.startsWith('InputRegistry') &&
if (msg.name.startsWith('Keyboard') &&
!WindowMap.isActive(this._window)) {
return;
}
let data = msg.data;
if (msg.name.startsWith('System') &&
this._inputManageId !== data.inputManageId) {
return;
}
delete data.inputManageId;
let resolver = ('requestId' in data) ?
this.takePromiseResolver(data.requestId) : null;
@ -272,6 +518,30 @@ MozInputMethod.prototype = {
resolver.reject(data.error);
break;
case 'System:Focus':
this._mgmt.handleFocus(data);
break;
case 'System:Blur':
this._mgmt.handleBlur(data);
break;
case 'System:ShowAll':
this._mgmt.dispatchShowAllRequestEvent();
break;
case 'System:Next':
this._mgmt.dispatchNextRequestEvent();
break;
case 'System:InputRegistry:Add':
this._mgmt.handleAddInput(data);
break;
case 'System:InputRegistry:Remove':
this._mgmt.handleRemoveInput(data);
break;
}
},
@ -282,7 +552,7 @@ MozInputMethod.prototype = {
},
get mgmt() {
return this._mgmt;
return this._wrappedMgmt;
},
get inputcontext() {
@ -320,8 +590,7 @@ MozInputMethod.prototype = {
this._window.MozInputContext._create(this._window, this._inputcontext);
}
let event = new this._window.Event("inputcontextchange",
Cu.cloneInto({}, this._window));
let event = new this._window.Event("inputcontextchange");
this.__DOM_IMPL__.dispatchEvent(event);
},
@ -344,9 +613,9 @@ MozInputMethod.prototype = {
// we have to use a synchronous message
var kbID = WindowMap.getKbID(this._window);
if (kbID) {
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:Register', {});
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:RegisterSync', {});
} else {
let res = cpmm.sendSyncMessage('Keyboard:Register', {});
let res = cpmm.sendSyncMessage('Keyboard:RegisterSync', {});
WindowMap.setKbID(this._window, res[0]);
}
@ -405,6 +674,13 @@ MozInputMethod.prototype = {
removeFocus: function() {
cpmm.sendAsyncMessage('System:RemoveFocus', {});
},
_hasInputManagePerm: function(win) {
let principal = win.document.nodePrincipal;
let perm = Services.perms.testExactPermissionFromPrincipal(principal,
"input-manage");
return (perm === Ci.nsIPermissionManager.ALLOW_ACTION);
}
};

Просмотреть файл

@ -1135,6 +1135,8 @@ function getJSON(element, focusCounter) {
switch (inputTypeLowerCase) {
case "datetime":
case "datetime-local":
case "month":
case "week":
case "range":
inputType = inputTypeLowerCase;
break;

Просмотреть файл

@ -4,7 +4,7 @@ skip-if = (toolkit == 'android' || toolkit == 'gonk') || e10s
support-files =
inputmethod_common.js
file_inputmethod.html
file_inputmethod_1043828.html
file_blank.html
file_test_app.html
file_test_sendkey_cancel.html
file_test_sms_app.html
@ -22,8 +22,11 @@ support-files =
[test_bug1066515.html]
[test_bug1175399.html]
[test_bug1137557.html]
[test_focus_blur_manage_events.html]
[test_input_registry_events.html]
[test_sendkey_cancel.html]
[test_setSupportsSwitching.html]
[test_simple_manage_events.html]
[test_sync_edit.html]
[test_two_inputs.html]
[test_two_selects.html]

Просмотреть файл

@ -84,7 +84,7 @@ function runTest() {
document.body.appendChild(keyboardB);
// simulate two different keyboard apps
let imeUrl = basePath + '/file_inputmethod_1043828.html';
let imeUrl = basePath + '/file_blank.html';
SpecialPowers.pushPermissions([{
type: 'input',

Просмотреть файл

@ -0,0 +1,230 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1201407
-->
<head>
<title>Test inputcontextfocus and inputcontextblur event</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1201407">Mozilla Bug 1201407</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
let contentFrameMM;
function setupTestRunner() {
info('setupTestRunner');
let im = navigator.mozInputMethod;
let expectedEventDetails = [
{ type: 'input', inputType: 'text' },
{ type: 'input', inputType: 'search' },
{ type: 'textarea', inputType: 'textarea' },
{ type: 'contenteditable', inputType: 'textarea' },
{ type: 'input', inputType: 'number' },
{ type: 'input', inputType: 'tel' },
{ type: 'input', inputType: 'url' },
{ type: 'input', inputType: 'email' },
{ type: 'input', inputType: 'password' },
{ type: 'input', inputType: 'datetime' },
{ type: 'input', inputType: 'date',
value: '2015-08-03', min: '1990-01-01', max: '2020-01-01' },
{ type: 'input', inputType: 'month' },
{ type: 'input', inputType: 'week' },
{ type: 'input', inputType: 'time' },
{ type: 'input', inputType: 'datetime-local' },
{ type: 'input', inputType: 'color' },
{ type: 'select', inputType: 'select-one',
choices: {
multiple: false,
choices: [
{ group: false, inGroup: false, text: 'foo',
disabled: false, selected: true, optionIndex: 0 },
{ group: false, inGroup: false, text: 'bar',
disabled: true, selected: false, optionIndex: 1 },
{ group: true, text: 'group', disabled: false },
{ group: false, inGroup: true, text: 'baz',
disabled: false, selected: false, optionIndex: 2 } ] }
},
{ type: 'select', inputType: 'select-multiple',
choices: {
multiple: true,
choices: [
{ group: false, inGroup: false, text: 'foo',
disabled: false, selected: true, optionIndex: 0 },
{ group: false, inGroup: false, text: 'bar',
disabled: true, selected: false, optionIndex: 1 },
{ group: true, text: 'group', disabled: false },
{ group: false, inGroup: true, text: 'baz',
disabled: false, selected: false, optionIndex: 2 } ] }
}
];
let expectBlur = false;
function deepAssertObject(obj, expectedObj, desc) {
for (let prop in expectedObj) {
if (typeof expectedObj[prop] === 'object') {
deepAssertObject(obj[prop], expectedObj[prop], desc + '.' + prop);
} else {
is(obj[prop], expectedObj[prop], desc + '.' + prop);
}
}
}
im.mgmt.oninputcontextfocus =
im.mgmt.oninputcontextblur = function(evt) {
if (expectBlur) {
is(evt.type, 'inputcontextblur', 'evt.type');
evt.preventDefault();
expectBlur = false;
return;
}
let expectedEventDetail = expectedEventDetails.shift();
if (!expectedEventDetail) {
ok(false, 'Receving extra events');
inputmethod_cleanup();
return;
}
is(evt.type, 'inputcontextfocus', 'evt.type');
evt.preventDefault();
expectBlur = true;
let detail = evt.detail;
deepAssertObject(detail, expectedEventDetail, 'detail');
if (expectedEventDetails.length) {
contentFrameMM.sendAsyncMessage('test:next');
} else {
im.mgmt.oninputcontextfocus = im.mgmt.oninputcontextblur = null;
inputmethod_cleanup();
}
};
}
function setupInputAppFrame() {
info('setupInputAppFrame');
return new Promise((resolve, reject) => {
let appFrameScript = function appFrameScript() {
let im = content.navigator.mozInputMethod;
im.mgmt.oninputcontextfocus =
im.mgmt.oninputcontextblur = function(evt) {
sendAsyncMessage('text:appEvent', { type: evt.type });
};
content.document.body.textContent = 'I am a input app';
};
let path = location.pathname;
let basePath = location.protocol + '//' + location.host +
path.substring(0, path.lastIndexOf('/'));
let imeUrl = basePath + '/file_blank.html';
let inputAppFrame = document.createElement('iframe');
inputAppFrame.setAttribute('mozbrowser', true);
inputAppFrame.src = imeUrl;
document.body.appendChild(inputAppFrame);
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: {
url: imeUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
}], function() {
let mm = SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
inputAppFrame.addEventListener('mozbrowserloadend', function() {
mm.addMessageListener('text:appEvent', function(msg) {
ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
});
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
// Set the input app frame to be active
let req = inputAppFrame.setInputMethodActive(true);
resolve(req);
});
});
});
}
function setupContentFrame() {
info('setupContentFrame');
return new Promise((resolve, reject) => {
let contentFrameScript = function contentFrameScript() {
let input = content.document.body.firstElementChild;
let i = 0;
input.focus();
addMessageListener('test:next', function() {
content.document.body.children[++i].focus();
});
};
let iframe = document.createElement('iframe');
iframe.src = 'data:text/html,<html><body>' +
'<input type="text">' +
'<input type="search">' +
'<textarea></textarea>' +
'<p contenteditable></p>' +
'<input type="number">' +
'<input type="tel">' +
'<input type="url">' +
'<input type="email">' +
'<input type="password">' +
'<input type="datetime">' +
'<input type="date" value="2015-08-03" min="1990-01-01" max="2020-01-01">' +
'<input type="month">' +
'<input type="week">' +
'<input type="time">' +
'<input type="datetime-local">' +
'<input type="color">' +
'<select><option selected>foo</option><option disabled>bar</option>' +
'<optgroup label="group"><option>baz</option></optgroup></select>' +
'<select multiple><option selected>foo</option><option disabled>bar</option>' +
'<optgroup label="group"><option>baz</option></optgroup></select>' +
'</body></html>';
iframe.setAttribute('mozbrowser', true);
document.body.appendChild(iframe);
let mm = contentFrameMM =
SpecialPowers.getBrowserFrameMessageManager(iframe);
iframe.addEventListener('mozbrowserloadend', function() {
mm.loadFrameScript('data:,(' + encodeURIComponent(contentFrameScript.toString()) + ')();', false);
resolve();
});
});
}
inputmethod_setup(function() {
Promise.resolve()
.then(() => setupTestRunner())
.then(() => setupContentFrame())
.then(() => setupInputAppFrame())
.catch((e) => {
ok(false, 'Error' + e.toString());
console.error(e);
});
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,259 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1201407
-->
<head>
<title>Test addinputrequest and removeinputrequest event</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1201407">Mozilla Bug 1201407</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
let appFrameMM;
let nextStep;
function setupInputAppFrame() {
info('setupInputAppFrame');
return new Promise((resolve, reject) => {
let appFrameScript = function appFrameScript() {
let im = content.navigator.mozInputMethod;
addMessageListener('test:callAddInput', function() {
im.addInput('foo', {
launch_path: 'bar.html',
name: 'Foo',
description: 'foobar',
types: ['text', 'password']
})
.then((r) => {
sendAsyncMessage('test:resolved', { resolved: true, result: r });
}, (e) => {
sendAsyncMessage('test:rejected', { rejected: true, error: e });
});
});
addMessageListener('test:callRemoveInput', function() {
im.removeInput('foo')
.then((r) => {
sendAsyncMessage('test:resolved', { resolved: true, result: r });
}, (e) => {
sendAsyncMessage('test:rejected', { rejected: true, error: e });
});
});
im.mgmt.onaddinputrequest =
im.mgmt.onremoveinputrequest = function(evt) {
sendAsyncMessage('test:appEvent', { type: evt.type });
};
content.document.body.textContent = 'I am a input app';
};
let path = location.pathname;
let basePath = location.protocol + '//' + location.host +
path.substring(0, path.lastIndexOf('/'));
let imeUrl = basePath + '/file_blank.html';
let inputAppFrame = document.createElement('iframe');
inputAppFrame.setAttribute('mozbrowser', true);
inputAppFrame.src = imeUrl;
document.body.appendChild(inputAppFrame);
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: {
url: imeUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
}], function() {
let mm = appFrameMM =
SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
inputAppFrame.addEventListener('mozbrowserloadend', function() {
mm.addMessageListener('test:appEvent', function(msg) {
ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
});
mm.addMessageListener('test:resolved', function(msg) {
nextStep && nextStep(msg.data);
});
mm.addMessageListener('test:rejected', function(msg) {
nextStep && nextStep(msg.data);
});
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
resolve();
});
});
});
}
function Deferred() {
this.promise = new Promise((res, rej) => {
this.resolve = res;
this.reject = rej;
});
return this;
}
function deepAssertObject(obj, expectedObj, desc) {
for (let prop in expectedObj) {
if (typeof expectedObj[prop] === 'object') {
deepAssertObject(obj[prop], expectedObj[prop], desc + '.' + prop);
} else {
is(obj[prop], expectedObj[prop], desc + '.' + prop);
}
}
}
function setupTestRunner() {
let im = navigator.mozInputMethod;
let d;
let i = -1;
nextStep = function next(evt) {
i++;
info('Step ' + i);
switch (i) {
case 0:
appFrameMM.sendAsyncMessage('test:callAddInput');
break;
case 1:
is(evt.type, 'addinputrequest', 'evt.type');
deepAssertObject(evt.detail, {
inputId: 'foo',
manifestURL: null, // todo
inputManifest: {
launch_path: 'bar.html',
name: 'Foo',
description: 'foobar',
types: ['text', 'password']
}
}, 'detail');
d = new Deferred();
evt.detail.waitUntil(d.promise);
evt.preventDefault();
Promise.resolve().then(next);
break;
case 2:
d.resolve();
d = null;
break;
case 3:
ok(evt.resolved, 'resolved');
appFrameMM.sendAsyncMessage('test:callAddInput');
break;
case 4:
is(evt.type, 'addinputrequest', 'evt.type');
d = new Deferred();
evt.detail.waitUntil(d.promise);
evt.preventDefault();
Promise.resolve().then(next);
break;
case 5:
d.reject('Foo Error');
d = null;
break;
case 6:
ok(evt.rejected, 'rejected');
is(evt.error, 'Foo Error', 'rejected');
appFrameMM.sendAsyncMessage('test:callRemoveInput');
break;
case 7:
is(evt.type, 'removeinputrequest', 'evt.type');
deepAssertObject(evt.detail, {
inputId: 'foo',
manifestURL: null // todo
}, 'detail');
d = new Deferred();
evt.detail.waitUntil(d.promise);
evt.preventDefault();
Promise.resolve().then(next);
break;
case 8:
d.resolve();
d = null;
break;
case 9:
ok(evt.resolved, 'resolved');
appFrameMM.sendAsyncMessage('test:callRemoveInput');
break;
case 10:
is(evt.type, 'removeinputrequest', 'evt.type');
d = new Deferred();
evt.detail.waitUntil(d.promise);
evt.preventDefault();
Promise.resolve().then(next);
break;
case 11:
d.reject('Foo Error');
d = null;
break;
case 12:
ok(evt.rejected, 'rejected');
is(evt.error, 'Foo Error', 'rejected');
inputmethod_cleanup();
break;
default:
ok(false, 'received extra call.');
inputmethod_cleanup();
break;
}
}
im.mgmt.onaddinputrequest =
im.mgmt.onremoveinputrequest = nextStep;
}
inputmethod_setup(function() {
Promise.resolve()
.then(() => setupTestRunner())
.then(() => setupInputAppFrame())
.then(() => nextStep())
.catch((e) => {
ok(false, 'Error' + e.toString());
console.error(e);
});
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,164 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1201407
-->
<head>
<title>Test simple manage notification events on MozInputMethodManager</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1201407">Mozilla Bug 1201407</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
let appFrameMM;
let nextStep;
function setupTestRunner() {
info('setupTestRunner');
let im = navigator.mozInputMethod;
let i = 0;
im.mgmt.onshowallrequest =
im.mgmt.onnextrequest = nextStep = function(evt) {
i++;
switch (i) {
case 1:
is(evt.type, 'inputcontextchange', '1) inputcontextchange event');
appFrameMM.sendAsyncMessage('test:callShowAll');
break;
case 2:
is(evt.type, 'showallrequest', '2) showallrequest event');
ok(evt.target, im.mgmt, '2) evt.target');
evt.preventDefault();
appFrameMM.sendAsyncMessage('test:callNext');
break;
case 3:
is(evt.type, 'nextrequest', '3) nextrequest event');
ok(evt.target, im.mgmt, '3) evt.target');
evt.preventDefault();
im.mgmt.onshowallrequest =
im.mgmt.onnextrequest = nextStep = null;
inputmethod_cleanup();
break;
default:
ok(false, 'Receving extra events');
inputmethod_cleanup();
break;
}
};
}
function setupInputAppFrame() {
info('setupInputAppFrame');
return new Promise((resolve, reject) => {
let appFrameScript = function appFrameScript() {
let im = content.navigator.mozInputMethod;
addMessageListener('test:callShowAll', function() {
im.mgmt.showAll();
});
addMessageListener('test:callNext', function() {
im.mgmt.next();
});
im.mgmt.onshowallrequest =
im.mgmt.onnextrequest = function(evt) {
sendAsyncMessage('test:appEvent', { type: evt.type });
};
im.oninputcontextchange = function(evt) {
sendAsyncMessage('test:inputcontextchange', {});
};
content.document.body.textContent = 'I am a input app';
};
let path = location.pathname;
let basePath = location.protocol + '//' + location.host +
path.substring(0, path.lastIndexOf('/'));
let imeUrl = basePath + '/file_blank.html';
let inputAppFrame = document.createElement('iframe');
inputAppFrame.setAttribute('mozbrowser', true);
inputAppFrame.src = imeUrl;
document.body.appendChild(inputAppFrame);
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: {
url: imeUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
}], function() {
let mm = appFrameMM =
SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
inputAppFrame.addEventListener('mozbrowserloadend', function() {
mm.addMessageListener('test:appEvent', function(msg) {
ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
});
mm.addMessageListener('test:inputcontextchange', function(msg) {
nextStep && nextStep({ type: 'inputcontextchange' });
});
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
// Set the input app frame to be active
let req = inputAppFrame.setInputMethodActive(true);
resolve(req);
});
});
});
}
function setupContentFrame() {
let contentFrameScript = function contentFrameScript() {
let input = content.document.body.firstElementChild;
input.focus();
};
let iframe = document.createElement('iframe');
iframe.src = 'data:text/html,<html><body><input type="text"></body></html>';
iframe.setAttribute('mozbrowser', true);
document.body.appendChild(iframe);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
iframe.addEventListener('mozbrowserloadend', function() {
mm.loadFrameScript('data:,(' + encodeURIComponent(contentFrameScript.toString()) + ')();', false);
});
}
inputmethod_setup(function() {
Promise.resolve()
.then(() => setupTestRunner())
.then(() => setupContentFrame())
.then(() => setupInputAppFrame())
.catch((e) => {
ok(false, 'Error' + e.toString());
console.error(e);
});
});
</script>
</pre>
</body>
</html>

106
dom/media/FrameStatistics.h Normal file
Просмотреть файл

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FrameStatistics_h_
#define FrameStatistics_h_
namespace mozilla {
// Frame decoding/painting related performance counters.
// Threadsafe.
class FrameStatistics {
public:
FrameStatistics() :
mReentrantMonitor("FrameStats"),
mParsedFrames(0),
mDecodedFrames(0),
mPresentedFrames(0),
mDroppedFrames(0),
mCorruptFrames(0) {}
// Returns number of frames which have been parsed from the media.
// Can be called on any thread.
uint32_t GetParsedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mParsedFrames;
}
// Returns the number of parsed frames which have been decoded.
// Can be called on any thread.
uint32_t GetDecodedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDecodedFrames;
}
// Returns the number of decoded frames which have been sent to the rendering
// pipeline for painting ("presented").
// Can be called on any thread.
uint32_t GetPresentedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mPresentedFrames;
}
// Number of frames that have been skipped because they have missed their
// compoisition deadline.
uint32_t GetDroppedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDroppedFrames + mCorruptFrames;
}
uint32_t GetCorruptedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mCorruptFrames;
}
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) {
if (aParsed == 0 && aDecoded == 0 && aDropped == 0)
return;
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mParsedFrames += aParsed;
mDecodedFrames += aDecoded;
mDroppedFrames += aDropped;
}
// Increments the presented frame counters.
// Can be called on any thread.
void NotifyPresentedFrame() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mPresentedFrames;
}
void NotifyCorruptFrame() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mCorruptFrames;
}
private:
// ReentrantMonitor to protect access of playback statistics.
ReentrantMonitor mReentrantMonitor;
// Number of frames parsed and demuxed from media.
// Access protected by mReentrantMonitor.
uint32_t mParsedFrames;
// Number of parsed frames which were actually decoded.
// Access protected by mReentrantMonitor.
uint32_t mDecodedFrames;
// Number of decoded frames which were actually sent down the rendering
// pipeline to be painted ("presented"). Access protected by mReentrantMonitor.
uint32_t mPresentedFrames;
uint32_t mDroppedFrames;
uint32_t mCorruptFrames;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -203,6 +203,7 @@ destroying the MediaDecoder object.
#include "nsITimer.h"
#include "AbstractMediaDecoder.h"
#include "FrameStatistics.h"
#include "MediaDecoderOwner.h"
#include "MediaEventSource.h"
#include "MediaMetadataManager.h"
@ -721,99 +722,6 @@ public:
// at any time.
MediaStatistics GetStatistics();
// Frame decoding/painting related performance counters.
// Threadsafe.
class FrameStatistics {
public:
FrameStatistics() :
mReentrantMonitor("MediaDecoder::FrameStats"),
mParsedFrames(0),
mDecodedFrames(0),
mPresentedFrames(0),
mDroppedFrames(0),
mCorruptFrames(0) {}
// Returns number of frames which have been parsed from the media.
// Can be called on any thread.
uint32_t GetParsedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mParsedFrames;
}
// Returns the number of parsed frames which have been decoded.
// Can be called on any thread.
uint32_t GetDecodedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDecodedFrames;
}
// Returns the number of decoded frames which have been sent to the rendering
// pipeline for painting ("presented").
// Can be called on any thread.
uint32_t GetPresentedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mPresentedFrames;
}
// Number of frames that have been skipped because they have missed their
// compoisition deadline.
uint32_t GetDroppedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDroppedFrames + mCorruptFrames;
}
uint32_t GetCorruptedFrames() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mCorruptFrames;
}
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) {
if (aParsed == 0 && aDecoded == 0 && aDropped == 0)
return;
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mParsedFrames += aParsed;
mDecodedFrames += aDecoded;
mDroppedFrames += aDropped;
}
// Increments the presented frame counters.
// Can be called on any thread.
void NotifyPresentedFrame() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mPresentedFrames;
}
void NotifyCorruptFrame() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mCorruptFrames;
}
private:
// ReentrantMonitor to protect access of playback statistics.
ReentrantMonitor mReentrantMonitor;
// Number of frames parsed and demuxed from media.
// Access protected by mReentrantMonitor.
uint32_t mParsedFrames;
// Number of parsed frames which were actually decoded.
// Access protected by mReentrantMonitor.
uint32_t mDecodedFrames;
// Number of decoded frames which were actually sent down the rendering
// pipeline to be painted ("presented"). Access protected by mReentrantMonitor.
uint32_t mPresentedFrames;
uint32_t mDroppedFrames;
uint32_t mCorruptFrames;
};
// Return the frame decode/paint related statistics.
FrameStatistics& GetFrameStatistics() { return mFrameStats; }

Просмотреть файл

@ -2498,7 +2498,7 @@ bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
// Update corrupt-frames statistics
if (aData->mImage && !aData->mImage->IsValid()) {
MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
frameStats.NotifyCorruptFrame();
// If more than 10% of the last 30 frames have been corrupted, then try disabling
// hardware acceleration. We use 10 as the corrupt value because RollingMean<>
@ -2635,7 +2635,7 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
VideoQueue().PushFront(currentFrame);
if (framesRemoved > 0) {
mVideoFrameEndTime = currentFrame->GetEndTime();
MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
frameStats.NotifyPresentedFrame();
}
}

Просмотреть файл

@ -33,6 +33,7 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsIInputStream.h"
#include "nsILineInputStream.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Types.h"
#include "mozilla/PeerIdentity.h"
#include "mozilla/dom/ContentChild.h"
@ -1579,6 +1580,16 @@ nsresult MediaManager::GenerateUUID(nsAString& aResult)
return NS_OK;
}
enum class GetUserMediaSecurityState {
Other = 0,
HTTPS = 1,
File = 2,
App = 3,
Localhost = 4,
Loop = 5,
Privileged = 6
};
/**
* The entry point for this file. A call from Navigator::mozGetUserMedia
* will end up here. MediaManager is a singleton that is responsible
@ -1630,9 +1641,47 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
bool privileged = loop || IsPrivileged();
bool isHTTPS = false;
docURI->SchemeIs("https", &isHTTPS);
nsCString host;
nsresult rv = docURI->GetHost(host);
// Test for some other schemes that ServiceWorker recognizes
bool isFile;
docURI->SchemeIs("file", &isFile);
bool isApp;
docURI->SchemeIs("app", &isApp);
// Same localhost check as ServiceWorkers uses
// (see IsFromAuthenticatedOriginInternal())
bool isLocalhost = NS_SUCCEEDED(rv) &&
(host.LowerCaseEqualsLiteral("localhost") ||
host.LowerCaseEqualsLiteral("127.0.0.1") ||
host.LowerCaseEqualsLiteral("::1"));
// Record telemetry about whether the source of the call was secure, i.e.,
// privileged or HTTPS. We may handle other cases
if (loop) {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::Loop);
} else if (privileged) {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::Privileged);
} else if (isHTTPS) {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::HTTPS);
} else if (isFile) {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::File);
} else if (isApp) {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::App);
} else if (isLocalhost) {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::Localhost);
} else {
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
(uint32_t) GetUserMediaSecurityState::Other);
}
nsCString origin;
nsresult rv = nsPrincipal::GetOriginForURI(docURI, origin);
rv = nsPrincipal::GetOriginForURI(docURI, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

Просмотреть файл

@ -112,6 +112,7 @@ EXPORTS += [
'EncodedBufferCache.h',
'FileBlockCache.h',
'FlushableTaskQueue.h',
'FrameStatistics.h',
'Intervals.h',
'Latency.h',
'MediaCache.h',

Просмотреть файл

@ -472,9 +472,9 @@ nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
if (HasAudio() || HasVideo()) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mInfo.mMetadataDuration.isNothing() && !mDecoder->IsOggDecoderShutdown() &&
mResource.GetLength() >= 0 && mDecoder->IsMediaSeekable())
{
if (mInfo.mMetadataDuration.isNothing() &&
!mDecoder->IsOggDecoderShutdown() &&
mResource.GetLength() >= 0) {
// We didn't get a duration from the index or a Content-Duration header.
// Seek to the end of file to find the end time.
int64_t length = mResource.GetLength();

Просмотреть файл

@ -545,6 +545,7 @@ DeallocPMediaParent(media::PMediaParent *aActor)
{
MOZ_ASSERT(sIPCServingParent == static_cast<Parent<PMediaParent>*>(aActor));
delete sIPCServingParent;
sIPCServingParent = nullptr;
return true;
}

Просмотреть файл

@ -8,7 +8,7 @@
<script type="application/javascript">
createHTML({
bug: "1087551",
title: "addCandidate behavior in different states"
title: "addIceCandidate behavior (local and remote) including invalid data"
});
var test;
@ -71,6 +71,28 @@
sdpMLineIndex: 0});
return test.pcRemote._pc.addIceCandidate(candidate)
.then(ok(true, "Successfully added valid ICE candidate"));
},
// bug 1095793
function PC_REMOTE_ADD_MISMATCHED_MID_AND_LEVEL_CANDIDATE(test) {
var bogus = new mozRTCIceCandidate(
{candidate:"candidate:1 1 UDP 2130706431 192.168.2.1 50005 typ host",
sdpMLineIndex: 0,
sdpMid: "sdparta_1"});
return test.pcRemote._pc.addIceCandidate(bogus)
.then(
generateErrorCallback("addIceCandidate should have failed."),
err => {
is(err.name, "InvalidCandidateError", "Error is InvalidCandidateError");
}
);
},
function PC_REMOTE_ADD_MATCHING_MID_AND_LEVEL_CANDIDATE(test) {
var candidate = new mozRTCIceCandidate(
{candidate:"candidate:1 1 UDP 2130706431 192.168.2.1 50005 typ host",
sdpMLineIndex: 0,
sdpMid: "sdparta_0"});
return test.pcRemote._pc.addIceCandidate(candidate)
.then(ok(true, "Successfully added valid ICE candidate with matching mid and level"));
}
]);
test.run();

Просмотреть файл

@ -20,6 +20,7 @@ dictionary CaretStateChangedEventInit : EventInit {
boolean caretVisible = false;
boolean selectionVisible = false;
boolean selectionEditable = false;
DOMString selectedTextContent = "";
};
[Constructor(DOMString type, optional CaretStateChangedEventInit eventInit),
@ -31,4 +32,5 @@ interface CaretStateChangedEvent : Event {
readonly attribute boolean caretVisible;
readonly attribute boolean selectionVisible;
readonly attribute boolean selectionEditable;
readonly attribute DOMString selectedTextContent;
};

Просмотреть файл

@ -120,7 +120,7 @@ interface MozInputMethod : EventTarget {
[JSImplementation="@mozilla.org/b2g-imm;1",
Pref="dom.mozInputMethod.enabled",
CheckAnyPermissions="input input-manage"]
interface MozInputMethodManager {
interface MozInputMethodManager : EventTarget {
/**
* Ask the OS to show a list of available inputs for users to switch from.
* OS should sliently ignore this request if the app is currently not the
@ -165,6 +165,149 @@ interface MozInputMethodManager {
*/
[CheckAllPermissions="input-manage"]
void setSupportsSwitchingTypes(sequence<MozInputMethodInputContextInputTypes> types);
/**
* CustomEvent dispatches to System when there is an input to handle.
* If the API consumer failed to handle and call preventDefault(),
* there will be a message printed on the console.
*
* evt.detail is defined by MozInputContextFocusEventDetail.
*/
[CheckAnyPermissions="input-manage"]
attribute EventHandler oninputcontextfocus;
/**
* Event dispatches to System when there is no longer an input to handle.
* If the API consumer failed to handle and call preventDefault(),
* there will be a message printed on the console.
*/
[CheckAnyPermissions="input-manage"]
attribute EventHandler oninputcontextblur;
/**
* Event dispatches to System when there is a showAll() call.
* If the API consumer failed to handle and call preventDefault(),
* there will be a message printed on the console.
*/
[CheckAnyPermissions="input-manage"]
attribute EventHandler onshowallrequest;
/**
* Event dispatches to System when there is a next() call.
* If the API consumer failed to handle and call preventDefault(),
* there will be a message printed on the console.
*/
[CheckAnyPermissions="input-manage"]
attribute EventHandler onnextrequest;
/**
* Event dispatches to System when there is a addInput() call.
* The API consumer must call preventDefault() to indicate the event is
* consumed, otherwise the request is not considered handled even if
* waitUntil() was called.
*
* evt.detail is defined by MozInputRegistryEventDetail.
*/
[CheckAnyPermissions="input-manage"]
attribute EventHandler onaddinputrequest;
/**
* Event dispatches to System when there is a removeInput() call.
* The API consumer must call preventDefault() to indicate the event is
* consumed, otherwise the request is not considered handled even if
* waitUntil() was called.
*
* evt.detail is defined by MozInputRegistryEventDetail.
*/
[CheckAnyPermissions="input-manage"]
attribute EventHandler onremoveinputrequest;
};
/**
* Detail of the inputcontextfocus event.
*/
[JSImplementation="@mozilla.org/b2g-imm-focus;1",
Pref="dom.mozInputMethod.enabled",
CheckAnyPermissions="input-manage"]
interface MozInputContextFocusEventDetail {
/**
* The type of the focused input.
*/
readonly attribute MozInputMethodInputContextTypes type;
/**
* The input type of the focused input.
*/
readonly attribute MozInputMethodInputContextInputTypes inputType;
/**
* The following is only needed for rendering and handling "option" input types,
* in System app.
*/
/**
* Current value of the input/select element.
*/
readonly attribute DOMString? value;
/**
* An object representing all the <optgroup> and <option> elements
* in the <select> element.
*/
[Pure, Cached, Frozen]
readonly attribute MozInputContextChoicesInfo? choices;
/**
* Max/min value of <input>
*/
readonly attribute DOMString? min;
readonly attribute DOMString? max;
};
/**
* Information about the options within the <select> element.
*/
dictionary MozInputContextChoicesInfo {
boolean multiple;
sequence<MozInputMethodChoiceDict> choices;
};
/**
* Content the header (<optgroup>) or an option (<option>).
*/
dictionary MozInputMethodChoiceDict {
boolean group;
DOMString text;
boolean disabled;
boolean? inGroup;
boolean? selected;
long? optionIndex;
};
/**
* detail of addinputrequest or removeinputrequest event.
*/
[JSImplementation="@mozilla.org/b2g-imm-input-registry;1",
Pref="dom.mozInputMethod.enabled",
CheckAnyPermissions="input-manage"]
interface MozInputRegistryEventDetail {
/**
* Manifest URL of the requesting app.
*/
readonly attribute DOMString manifestURL;
/**
* ID of the input
*/
readonly attribute DOMString inputId;
/**
* Input manifest of the input to add.
* Null for removeinputrequest event.
*/
[Pure, Cached, Frozen]
readonly attribute MozInputMethodInputManifest? inputManifest;
/**
* Resolve or Reject the addInput() or removeInput() call when the passed
* promises are resolved.
*/
[Throws]
void waitUntil(Promise<any> p);
};
/**
@ -397,19 +540,20 @@ dictionary CompositionClauseParameters {
* *and* the special keyword "contenteditable" for contenteditable element.
*/
enum MozInputMethodInputContextTypes {
"input", "textarea", "contenteditable"
"input", "textarea", "contenteditable",
/**
* <select> is managed by the API but it's not exposed through InputContext
* yet.
* <select> is managed by the API but it is handled by the System app only,
* so this value is only accessible by System app from inputcontextfocus event.
*/
// "select"
"select"
};
/**
* InputTypes of the input that InputContext is representing. The value
* is inferred from the type attribute of input element.
* is inferred from the type attribute of element.
*
* See https://html.spec.whatwg.org/multipage/forms.html#states-of-the-type-attribute
* for types of HTMLInputElement.
*
* They are divided into groups -- an layout/input capable of handling one type
* in the group is considered as capable of handling all of the types in the
@ -444,12 +588,15 @@ enum MozInputMethodInputContextInputTypes {
* Group "password".
* An non-Latin alphabet layout/input should not be able to handle this type.
*/
"password"
"password",
/**
* Group "option". These types are handled by System app itself currently, and
* not exposed and allowed to handled with input context.
* Group "option". These types are handled by System app itself currently, so
* no input app will be set to active for these input types.
* System app access these types from inputcontextfocus event.
* ("select-one" and "select-multiple" are valid HTMLSelectElement#type.)
*/
//"datetime", "date", "month", "week", "time", "datetime-local", "color",
"datetime", "date", "month", "week", "time", "datetime-local", "color",
"select-one", "select-multiple"
/**
* These types are ignored by the API even though they are valid
* HTMLInputElement#type.

Просмотреть файл

@ -162,6 +162,8 @@ support-files =
eventsource/*
sw_clients/file_blob_upload_frame.html
redirect_post.sjs
xslt_worker.js
xslt/*
[test_app_protocol.html]
skip-if = release_build
@ -250,6 +252,7 @@ skip-if = toolkit == "android" || toolkit == "gonk"
[test_workerupdatefoundevent.html]
[test_opaque_intercept.html]
[test_fetch_event_client_postmessage.html]
[test_xslt.html]
[test_escapedSlashes.html]
[test_eventsource_intercept.html]
[test_not_intercept_plugin.html]

Просмотреть файл

@ -0,0 +1,113 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1182113 - Test service worker XSLT interception</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content"></div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var registration;
var worker;
function start() {
return navigator.serviceWorker.register("xslt_worker.js",
{ scope: "./" })
.then((swr) => registration = swr);
}
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
}
function getXmlString(xmlObject) {
serializer = new XMLSerializer();
return serializer.serializeToString(iframe.contentDocument);
}
function synthetic() {
content = document.getElementById("content");
ok(content, "parent exists.");
iframe = document.createElement("iframe");
content.appendChild(iframe);
iframe.setAttribute('src', "xslt/test.xml");
var p = new Promise(function(res, rej) {
iframe.onload = function(e) {
dump("Set request mode\n");
registration.active.postMessage("synthetic");
xmlString = getXmlString(iframe.contentDocument);
ok(!xmlString.includes("Error"), "Load synthetic cross origin XSLT should be allowed");
res();
};
});
return p;
}
function cors() {
var p = new Promise(function(res, rej) {
iframe.onload = function(e) {
xmlString = getXmlString(iframe.contentDocument);
ok(!xmlString.includes("Error"), "Load CORS cross origin XSLT should be allowed");
res();
};
});
registration.active.postMessage("cors");
iframe.setAttribute('src', "xslt/test.xml");
return p;
}
function opaque() {
var p = new Promise(function(res, rej) {
iframe.onload = function(e) {
xmlString = getXmlString(iframe.contentDocument);
ok(xmlString.includes("Error"), "Load opaque cross origin XSLT should not be allowed");
res();
};
});
registration.active.postMessage("opaque");
iframe.setAttribute('src', "xslt/test.xml");
return p;
}
function runTest() {
start()
.then(synthetic)
.then(opaque)
.then(cors)
.then(unregister)
.catch(function(e) {
ok(false, "Some test failed with error " + e);
}).then(SimpleTest.finish);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.interception.enabled", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
]}, runTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<result>
<Title>Example</Title>
<Error>Error</Error>
</result>

Просмотреть файл

@ -0,0 +1,12 @@
function handleRequest(request, response) {
response.setHeader("Content-Type", "application/xslt+xml", false);
response.setHeader("Access-Control-Allow-Origin", "*");
var body = request.queryString;
if (!body) {
response.setStatusLine(null, 500, "Invalid querystring");
return;
}
response.write(unescape(body));
}

Просмотреть файл

@ -0,0 +1,52 @@
var testType = 'synthetic';
var xslt = "<?xml version=\"1.0\"?> " +
"<xsl:stylesheet version=\"1.0\"" +
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
" <xsl:template match=\"node()|@*\">" +
" <xsl:copy>" +
" <xsl:apply-templates select=\"node()|@*\"/>" +
" </xsl:copy>" +
" </xsl:template>" +
" <xsl:template match=\"Error\"/>" +
"</xsl:stylesheet>";
onfetch = function(event) {
if (event.request.url.includes('test.xsl')) {
if (testType == 'synthetic') {
if (event.request.mode != 'cors') {
event.respondWith(Response.error());
return;
}
event.respondWith(Promise.resolve(
new Response(xslt, { headers: {'Content-Type': 'application/xslt+xml'}})
));
}
else if (testType == 'cors') {
if (event.request.mode != 'cors') {
event.respondWith(Response.error());
return;
}
var url = "http://example.com/tests/dom/workers/test/serviceworkers/xslt/xslt.sjs?" + escape(xslt);
event.respondWith(fetch(url, { mode: 'cors' }));
}
else if (testType == 'opaque') {
if (event.request.mode != 'cors') {
event.respondWith(Response.error());
return;
}
var url = "http://example.com/tests/dom/workers/test/serviceworkers/xslt/xslt.sjs?" + escape(xslt);
event.respondWith(fetch(url, { mode: 'no-cors' }));
}
else {
event.respondWith(Response.error());
}
}
};
onmessage = function(event) {
testType = event.data;
};

Просмотреть файл

@ -1688,7 +1688,7 @@ static void
DrawPaintedLayer(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion* aDirtyRegion,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData)

Просмотреть файл

@ -316,6 +316,7 @@ GLContext::GLContext(const SurfaceCaps& caps,
mMaxTextureImageSize(0),
mMaxRenderbufferSize(0),
mNeedsTextureSizeChecks(false),
mNeedsFlushBeforeDeleteFB(false),
mWorkAroundDriverBugs(true),
mHeavyGLCallsSinceLastFlush(false)
{
@ -616,6 +617,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
"Adreno (TM) 200",
"Adreno (TM) 205",
"Adreno (TM) 320",
"Adreno (TM) 420",
"PowerVR SGX 530",
"PowerVR SGX 540",
"NVIDIA Tegra",
@ -1607,6 +1609,12 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mNeedsTextureSizeChecks = true;
}
#endif
if (mWorkAroundDriverBugs &&
Renderer() == GLRenderer::AdrenoTM420) {
// see bug 1194923. Calling glFlush before glDeleteFramebuffers
// prevents occasional driver crash.
mNeedsFlushBeforeDeleteFB = true;
}
mMaxTextureImageSize = mMaxTextureSize;
@ -2851,6 +2859,11 @@ GLContext::fDeleteFramebuffers(GLsizei n, const GLuint* names)
}
}
// Avoid crash by flushing before glDeleteFramebuffers. See bug 1194923.
if (mNeedsFlushBeforeDeleteFB) {
fFlush();
}
if (n == 1 && *names == 0) {
// Deleting framebuffer 0 causes hangs on the DROID. See bug 623228.
} else {

Просмотреть файл

@ -169,6 +169,7 @@ enum class GLRenderer {
AdrenoTM200,
AdrenoTM205,
AdrenoTM320,
AdrenoTM420,
SGX530,
SGX540,
Tegra,
@ -3504,6 +3505,7 @@ protected:
GLint mMaxViewportDims[2];
GLsizei mMaxSamples;
bool mNeedsTextureSizeChecks;
bool mNeedsFlushBeforeDeleteFB;
bool mWorkAroundDriverBugs;
bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const {

Просмотреть файл

@ -259,11 +259,12 @@ public:
* The callee must draw all of aRegionToDraw.
* This region is relative to 0,0 in the PaintedLayer.
*
* aDirtyRegion, if non-null, contains the total region that is due to be
* painted during the transaction, even though only aRegionToDraw should
* be drawn during this call. The sum of every aRegionToDraw over the
* course of the transaction must equal aDirtyRegion. aDirtyRegion can be
* null if the total dirty region is unknown.
* aDirtyRegion should contain the total region that is be due to be painted
* during the transaction, even though only aRegionToDraw should be drawn
* during this call. aRegionToDraw must be entirely contained within
* aDirtyRegion. If the total dirty region is unknown it is okay to pass a
* subregion of the total dirty region, e.g. just aRegionToDraw, though it
* may not be as efficient.
*
* aRegionToInvalidate contains a region whose contents have been
* changed by the layer manager and which must therefore be invalidated.
@ -285,7 +286,7 @@ public:
typedef void (* DrawPaintedLayerCallback)(PaintedLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion* aDirtyRegion,
const nsIntRegion& aDirtyRegion,
DrawRegionClip aClip,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);

Просмотреть файл

@ -1227,6 +1227,10 @@ TransformDisplacement(APZCTreeManager* aTreeManager,
AsyncPanZoomController* aTarget,
ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint) {
if (aSource == aTarget) {
return true;
}
// Convert start and end points to Screen coordinates.
Matrix4x4 untransformToApzc = aTreeManager->GetScreenToApzcTransform(aSource).Inverse();
ScreenPoint screenStart = TransformTo<ScreenPixel>(untransformToApzc, aStartPoint);
@ -1246,10 +1250,10 @@ TransformDisplacement(APZCTreeManager* aTreeManager,
return true;
}
bool
void
APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
ParentLayerPoint aStartPoint,
ParentLayerPoint aEndPoint,
ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint,
OverscrollHandoffState& aOverscrollHandoffState)
{
const OverscrollHandoffChain& overscrollHandoffChain = aOverscrollHandoffState.mChain;
@ -1259,34 +1263,39 @@ APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
// nothing more to scroll, so we ignore the rest of the pan gesture.
if (overscrollHandoffChainIndex >= overscrollHandoffChain.Length()) {
// Nothing more to scroll - ignore the rest of the pan gesture.
return false;
return;
}
next = overscrollHandoffChain.GetApzcAtIndex(overscrollHandoffChainIndex);
if (next == nullptr || next->IsDestroyed()) {
return false;
return;
}
// Convert the start and end points from |aPrev|'s coordinate space to
// |next|'s coordinate space. Since |aPrev| may be the same as |next|
// (if |aPrev| is the APZC that is initiating the scroll and there is no
// scroll grabbing to grab the scroll from it), don't bother doing the
// transformations in that case.
if (next != aPrev) {
// |next|'s coordinate space.
if (!TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint)) {
return false;
}
return;
}
// Scroll |next|. If this causes overscroll, it will call DispatchScroll()
// again with an incremented index.
return next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffState);
if (!next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffState)) {
// Transform |aStartPoint| and |aEndPoint| (which now represent the
// portion of the displacement that wasn't consumed by APZCs later
// in the handoff chain) back into |aPrev|'s coordinate space. This
// allows the caller (which is |aPrev|) to interpret the unconsumed
// displacement in its own coordinate space, and make use of it
// (e.g. by going into overscroll).
if (!TransformDisplacement(this, next, aPrev, aStartPoint, aEndPoint)) {
NS_WARNING("Failed to untransform scroll points during dispatch");
}
}
}
bool
void
APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
ParentLayerPoint aVelocity,
ParentLayerPoint& aVelocity,
nsRefPtr<const OverscrollHandoffChain> aOverscrollHandoffChain,
bool aHandoff)
{
@ -1303,7 +1312,7 @@ APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
// rather than (0, 0).
ParentLayerPoint startPoint; // (0, 0)
ParentLayerPoint endPoint;
ParentLayerPoint transformedVelocity = aVelocity;
ParentLayerPoint usedTransformedVelocity = aVelocity;
if (aHandoff) {
startIndex = aOverscrollHandoffChain->IndexOf(aPrev) + 1;
@ -1311,7 +1320,7 @@ APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
// IndexOf will return aOverscrollHandoffChain->Length() if
// |aPrev| is not found.
if (startIndex >= aOverscrollHandoffChainLength) {
return false;
return;
}
} else {
startIndex = 0;
@ -1322,10 +1331,10 @@ APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
// Make sure the apcz about to be handled can be handled
if (current == nullptr || current->IsDestroyed()) {
return false;
return;
}
endPoint = startPoint + transformedVelocity;
endPoint = startPoint + usedTransformedVelocity;
// Only transform when current apcz can be transformed with previous
if (startIndex > 0) {
@ -1334,20 +1343,34 @@ APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
current,
startPoint,
endPoint)) {
return false;
return;
}
}
transformedVelocity = endPoint - startPoint;
ParentLayerPoint transformedVelocity = endPoint - startPoint;
usedTransformedVelocity = transformedVelocity;
if (current->AttemptFling(transformedVelocity,
if (current->AttemptFling(usedTransformedVelocity,
aOverscrollHandoffChain,
aHandoff)) {
return true;
}
if (IsZero(usedTransformedVelocity)) {
aVelocity = ParentLayerPoint();
return;
}
return false;
// Subtract the proportion of used velocity from aVelocity
if (!FuzzyEqualsAdditive(transformedVelocity.x,
usedTransformedVelocity.x, COORDINATE_EPSILON)) {
aVelocity.x = aVelocity.x *
(usedTransformedVelocity.x / transformedVelocity.x);
}
if (!FuzzyEqualsAdditive(transformedVelocity.y,
usedTransformedVelocity.y, COORDINATE_EPSILON)) {
aVelocity.y = aVelocity.y *
(usedTransformedVelocity.y / transformedVelocity.y);
}
}
}
}
bool

Просмотреть файл

@ -327,9 +327,10 @@ public:
* |aOverscrollHandoffChainIndex| is the next position in the overscroll
* handoff chain that should be scrolled.
*
* Returns true iff. some APZC accepted the scroll and scrolled.
* This is to allow the sending APZC to go into an overscrolled state if
* no APZC further up in the handoff chain accepted the overscroll.
* aStartPoint and aEndPoint will be modified depending on how much of the
* scroll each APZC consumes. This is to allow the sending APZC to go into
* an overscrolled state if no APZC further up in the handoff chain accepted
* the entire scroll.
*
* The way this method works is best illustrated with an example.
* Consider three nested APZCs, A, B, and C, with C being the innermost one.
@ -352,9 +353,9 @@ public:
* Note: this should be used for panning only. For handing off overscroll for
* a fling, use DispatchFling().
*/
bool DispatchScroll(AsyncPanZoomController* aApzc,
ParentLayerPoint aStartPoint,
ParentLayerPoint aEndPoint,
void DispatchScroll(AsyncPanZoomController* aApzc,
ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint,
OverscrollHandoffState& aOverscrollHandoffState);
/**
@ -374,12 +375,13 @@ public:
* start a fling (in this case the fling is given to the
* first APZC in the chain)
*
* Returns true iff. an APZC accepted the fling. In the case of fling handoff,
* the caller uses this return value to determine whether it should consume
* the excess fling itself by going into an overscroll fling.
* aVelocity will be modified depending on how much of that velocity has
* been consumed by APZCs in the overscroll hand-off chain. The caller can
* use this value to determine whether it should consume the excess velocity
* by going into an overscroll fling.
*/
bool DispatchFling(AsyncPanZoomController* aApzc,
ParentLayerPoint aVelocity,
void DispatchFling(AsyncPanZoomController* aApzc,
ParentLayerPoint& aVelocity,
nsRefPtr<const OverscrollHandoffChain> aOverscrollHandoffChain,
bool aHandoff);

Просмотреть файл

@ -1578,9 +1578,9 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
*mInputQueue->CurrentWheelBlock()->GetOverscrollHandoffChain(),
distance,
ScrollSource::Wheel);
CallDispatchScroll(aEvent.mLocalOrigin,
aEvent.mLocalOrigin - delta,
handoffState);
ParentLayerPoint startPoint = aEvent.mLocalOrigin;
ParentLayerPoint endPoint = aEvent.mLocalOrigin - delta;
CallDispatchScroll(startPoint, endPoint, handoffState);
SetState(NOTHING);
RequestContentRepaint();
@ -1726,9 +1726,9 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
*CurrentPanGestureBlock()->GetOverscrollHandoffChain(),
panDistance,
ScrollSource::Wheel);
CallDispatchScroll(aEvent.mLocalPanStartPoint,
aEvent.mLocalPanStartPoint + aEvent.mLocalPanDisplacement,
handoffState);
ParentLayerPoint startPoint = aEvent.mLocalPanStartPoint;
ParentLayerPoint endPoint = aEvent.mLocalPanStartPoint + aEvent.mLocalPanDisplacement;
CallDispatchScroll(startPoint, endPoint, handoffState);
return nsEventStatus_eConsumeNoDefault;
}
@ -1983,11 +1983,19 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle) {
void AsyncPanZoomController::HandlePanning(double aAngle) {
ReentrantMonitorAutoEnter lock(mMonitor);
if (!gfxPrefs::APZCrossSlideEnabled() && (!mX.CanScrollNow() || !mY.CanScrollNow())) {
nsRefPtr<const OverscrollHandoffChain> overscrollHandoffChain =
GetInputQueue()->CurrentBlock()->GetOverscrollHandoffChain();
bool canScrollHorizontal = !mX.IsAxisLocked() &&
overscrollHandoffChain->CanScrollInDirection(this, Layer::HORIZONTAL);
bool canScrollVertical = !mY.IsAxisLocked() &&
overscrollHandoffChain->CanScrollInDirection(this, Layer::VERTICAL);
if (!gfxPrefs::APZCrossSlideEnabled() &&
(!canScrollHorizontal || !canScrollVertical)) {
SetState(PANNING);
} else if (IsCloseToHorizontal(aAngle, gfxPrefs::APZAxisLockAngle())) {
mY.SetAxisLocked(true);
if (mX.CanScrollNow()) {
if (canScrollHorizontal) {
SetState(PANNING_LOCKED_X);
} else {
SetState(CROSS_SLIDING_X);
@ -1995,7 +2003,7 @@ void AsyncPanZoomController::HandlePanning(double aAngle) {
}
} else if (IsCloseToVertical(aAngle, gfxPrefs::APZAxisLockAngle())) {
mX.SetAxisLocked(true);
if (mY.CanScrollNow()) {
if (canScrollVertical) {
SetState(PANNING_LOCKED_Y);
} else {
SetState(CROSS_SLIDING_Y);
@ -2067,8 +2075,8 @@ void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput&
mY.UpdateWithTouchAtDevicePoint(point.y, 0, aEvent.mTime);
}
bool AsyncPanZoomController::AttemptScroll(const ParentLayerPoint& aStartPoint,
const ParentLayerPoint& aEndPoint,
bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint,
OverscrollHandoffState& aOverscrollHandoffState) {
// "start - end" rather than "end - start" because e.g. moving your finger
@ -2099,6 +2107,9 @@ bool AsyncPanZoomController::AttemptScroll(const ParentLayerPoint& aStartPoint,
}
}
// Adjust the start point to reflect the consumed portion of the scroll.
aStartPoint = aEndPoint + overscroll;
// If we consumed the entire displacement as a normal scroll, great.
if (IsZero(overscroll)) {
return true;
@ -2111,8 +2122,10 @@ bool AsyncPanZoomController::AttemptScroll(const ParentLayerPoint& aStartPoint,
// Note: "+ overscroll" rather than "- overscroll" because "overscroll"
// is what's left of "displacement", and "displacement" is "start - end".
++aOverscrollHandoffState.mChainIndex;
if (CallDispatchScroll(aEndPoint + overscroll, aEndPoint,
aOverscrollHandoffState)) {
CallDispatchScroll(aStartPoint, aEndPoint, aOverscrollHandoffState);
overscroll = aStartPoint - aEndPoint;
if (IsZero(overscroll)) {
return true;
}
}
@ -2121,10 +2134,13 @@ bool AsyncPanZoomController::AttemptScroll(const ParentLayerPoint& aStartPoint,
// overscroll, try to accept it ourselves. We only accept it if we
// are pannable.
APZC_LOG("%p taking overscroll during panning\n", this);
return OverscrollForPanning(overscroll, aOverscrollHandoffState.mPanDistance);
OverscrollForPanning(overscroll, aOverscrollHandoffState.mPanDistance);
aStartPoint = aEndPoint + overscroll;
return IsZero(overscroll);
}
bool AsyncPanZoomController::OverscrollForPanning(ParentLayerPoint aOverscroll,
void AsyncPanZoomController::OverscrollForPanning(ParentLayerPoint& aOverscroll,
const ScreenPoint& aPanDistance) {
// Only allow entering overscroll along an axis if the pan distance along
// that axis is greater than the pan distance along the other axis by a
@ -2138,12 +2154,12 @@ bool AsyncPanZoomController::OverscrollForPanning(ParentLayerPoint aOverscroll,
}
}
return OverscrollBy(aOverscroll);
OverscrollBy(aOverscroll);
}
bool AsyncPanZoomController::OverscrollBy(const ParentLayerPoint& aOverscroll) {
void AsyncPanZoomController::OverscrollBy(ParentLayerPoint& aOverscroll) {
if (!gfxPrefs::APZOverscrollEnabled()) {
return false;
return;
}
ReentrantMonitorAutoEnter lock(mMonitor);
@ -2151,19 +2167,24 @@ bool AsyncPanZoomController::OverscrollBy(const ParentLayerPoint& aOverscroll) {
// scroll to begin with.
bool xCanScroll = mX.CanScroll();
bool yCanScroll = mY.CanScroll();
if (xCanScroll) {
bool xConsumed = FuzzyEqualsAdditive(aOverscroll.x, 0.0f, COORDINATE_EPSILON);
if (xCanScroll && !xConsumed) {
mX.OverscrollBy(aOverscroll.x);
aOverscroll.x = 0;
xConsumed = true;
}
if (yCanScroll) {
bool yConsumed = FuzzyEqualsAdditive(aOverscroll.y, 0.0f, COORDINATE_EPSILON);
if (yCanScroll && !yConsumed) {
mY.OverscrollBy(aOverscroll.y);
aOverscroll.y = 0;
yConsumed = true;
}
if (xCanScroll || yCanScroll) {
if ((xCanScroll && xConsumed) || (yCanScroll && yConsumed)) {
ScheduleComposite();
return true;
}
// TODO(botond): If one of the x- or y-overscroll was not accepted, we
// may want to propagate that one to an APZC earlier in the handoff chain.
return false;
}
nsRefPtr<const OverscrollHandoffChain> AsyncPanZoomController::BuildOverscrollHandoffChain() {
@ -2178,14 +2199,22 @@ nsRefPtr<const OverscrollHandoffChain> AsyncPanZoomController::BuildOverscrollHa
return result;
}
void AsyncPanZoomController::AcceptFling(const ParentLayerPoint& aVelocity,
void AsyncPanZoomController::AcceptFling(ParentLayerPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
bool aHandoff) {
ReentrantMonitorAutoEnter lock(mMonitor);
// We may have a pre-existing velocity for whatever reason (for example,
// a previously handed off fling). We don't want to clobber that.
APZC_LOG("%p accepting fling with velocity %s\n", this, Stringify(aVelocity).c_str());
if (mX.CanScroll()) {
mX.SetVelocity(mX.GetVelocity() + aVelocity.x);
aVelocity.x = 0;
}
if (mY.CanScroll()) {
mY.SetVelocity(mY.GetVelocity() + aVelocity.y);
aVelocity.y = 0;
}
SetState(FLING);
FlingAnimation *fling = new FlingAnimation(*this,
aOverscrollHandoffChain,
@ -2227,7 +2256,7 @@ void AsyncPanZoomController::AcceptFling(const ParentLayerPoint& aVelocity,
StartAnimation(fling);
}
bool AsyncPanZoomController::AttemptFling(ParentLayerPoint aVelocity,
bool AsyncPanZoomController::AttemptFling(ParentLayerPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
bool aHandoff) {
// If we are pannable, take over the fling ourselves.
@ -2244,14 +2273,12 @@ bool AsyncPanZoomController::AttemptFling(ParentLayerPoint aVelocity,
void AsyncPanZoomController::HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain) {
APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
if (!(treeManagerLocal && treeManagerLocal->DispatchFling(this,
aVelocity,
aOverscrollHandoffChain,
true /* handoff */))) {
// No one wanted the fling, so we "take it" ourselves by entering an
// overscroll animation starting with the fling's velocity.
if (IsPannable() && gfxPrefs::APZOverscrollEnabled()) {
StartOverscrollAnimation(aVelocity);
ParentLayerPoint velocity = aVelocity;
if (treeManagerLocal) {
treeManagerLocal->DispatchFling(this, velocity, aOverscrollHandoffChain,
true /* handoff */);
if (!IsZero(velocity) && IsPannable() && gfxPrefs::APZOverscrollEnabled()) {
StartOverscrollAnimation(velocity);
}
}
}
@ -2284,17 +2311,17 @@ void AsyncPanZoomController::StartOverscrollAnimation(const ParentLayerPoint& aV
StartAnimation(new OverscrollAnimation(*this, aVelocity));
}
bool AsyncPanZoomController::CallDispatchScroll(const ParentLayerPoint& aStartPoint,
const ParentLayerPoint& aEndPoint,
void AsyncPanZoomController::CallDispatchScroll(ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint,
OverscrollHandoffState& aOverscrollHandoffState) {
// Make a local copy of the tree manager pointer and check if it's not
// null before calling DispatchScroll(). This is necessary because
// Destroy(), which nulls out mTreeManager, could be called concurrently.
APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
if (!treeManagerLocal) {
return false;
return;
}
return treeManagerLocal->DispatchScroll(this,
treeManagerLocal->DispatchScroll(this,
aStartPoint, aEndPoint,
aOverscrollHandoffState);
}
@ -3103,13 +3130,16 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
targetZoom = CSSToParentLayerScale(std::min(compositionBounds.width / aRect.width,
compositionBounds.height / aRect.height));
}
// 1. If the rect is empty, request received from browserElementScrolling.js
// 1. If the rect is empty, the content-side logic for handling a double-tap
// requested that we zoom out.
// 2. currentZoom is equal to mZoomConstraints.mMaxZoom and user still double-tapping it
// 3. currentZoom is equal to localMinZoom and user still double-tapping it
// Treat these three cases as a request to zoom out as much as possible.
bool zoomOut = false;
if (aRect.IsEmpty() ||
(currentZoom == localMaxZoom && targetZoom >= localMaxZoom) ||
(currentZoom == localMinZoom && targetZoom <= localMinZoom)) {
zoomOut = true;
CSSSize compositedSize = mFrameMetrics.CalculateCompositedSizeInCssPixels();
float y = scrollOffset.y;
float newHeight =
@ -3143,6 +3173,14 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
aRect.x = aRect.x > 0 ? aRect.x : 0;
}
// Vertically center the zoomed element in the screen.
if (!zoomOut && (sizeAfterZoom.height > aRect.height)) {
aRect.y -= (sizeAfterZoom.height - aRect.height) * 0.5f;
if (aRect.y < 0.0f) {
aRect.y = 0.0f;
}
}
endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
endZoomToMetrics.SetDisplayPortMargins(
CalculatePendingDisplayPort(endZoomToMetrics,

Просмотреть файл

@ -855,15 +855,16 @@ private:
*/
public:
/**
* Attempt a fling with the given velocity. If we are not pannable, tehe fling
* Attempt a fling with the given velocity. If we are not pannable, the fling
* is handed off to the next APZC in the handoff chain via
* mTreeManager->DspatchFling(). Returns true iff. any APZC (whether this
* one or one further in the handoff chain) accepted the fling.
* mTreeManager->DispatchFling(). Returns true iff. the entire velocity of
* the fling was consumed by this APZC. aVelocity is modified to contain any
* unused, residual velocity.
* |aHandoff| should be true iff. the fling was handed off from a previous
* APZC, and determines whether acceleration is applied to the
* fling.
*/
bool AttemptFling(ParentLayerPoint aVelocity,
bool AttemptFling(ParentLayerPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
bool aHandoff);
@ -889,7 +890,7 @@ private:
void HandleSmoothScrollOverscroll(const ParentLayerPoint& aVelocity);
// Helper function used by TakeOverFling() and HandleFlingOverscroll().
void AcceptFling(const ParentLayerPoint& aVelocity,
void AcceptFling(ParentLayerPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
bool aHandoff);
@ -967,9 +968,11 @@ public:
* handoff chain, accepted the scroll (possibly entering an overscrolled
* state). If this returns false, the caller APZC knows that it should enter
* an overscrolled state itself if it can.
* aStartPoint and aEndPoint are modified depending on how much of the
* scroll gesture was consumed by APZCs in the handoff chain.
*/
bool AttemptScroll(const ParentLayerPoint& aStartPoint,
const ParentLayerPoint& aEndPoint,
bool AttemptScroll(ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint,
OverscrollHandoffState& aOverscrollHandoffState);
void FlushRepaintForOverscrollHandoff();
@ -1007,8 +1010,8 @@ private:
* Guards against the case where the APZC is being concurrently destroyed
* (and thus mTreeManager is being nulled out).
*/
bool CallDispatchScroll(const ParentLayerPoint& aStartPoint,
const ParentLayerPoint& aEndPoint,
void CallDispatchScroll(ParentLayerPoint& aStartPoint,
ParentLayerPoint& aEndPoint,
OverscrollHandoffState& aOverscrollHandoffState);
/**
@ -1016,16 +1019,15 @@ private:
* around OverscrollBy() that also implements restrictions on entering
* overscroll based on the pan angle.
*/
bool OverscrollForPanning(ParentLayerPoint aOverscroll,
void OverscrollForPanning(ParentLayerPoint& aOverscroll,
const ScreenPoint& aPanDistance);
/**
* Try to overscroll by 'aOverscroll'.
* If we are pannable, 'aOverscroll' is added to any existing overscroll,
* and the function returns true.
* Otherwise, nothing happens and the function return false.
* If we are pannable on a particular axis, that component of 'aOverscroll'
* is transferred to any existing overscroll.
*/
bool OverscrollBy(const ParentLayerPoint& aOverscroll);
void OverscrollBy(ParentLayerPoint& aOverscroll);
/* ===================================================================

Просмотреть файл

@ -510,6 +510,10 @@ CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const {
return 0;
}
bool Axis::IsAxisLocked() const {
return mAxisLocked;
}
float Axis::GetVelocity() const {
return mAxisLocked ? 0 : mVelocity;
}

Просмотреть файл

@ -223,6 +223,11 @@ public:
*/
bool ScaleWillOverscrollBothSides(float aScale) const;
/**
* Returns true if movement on this axis is locked.
*/
bool IsAxisLocked() const;
ParentLayerCoord GetOrigin() const;
ParentLayerCoord GetCompositionLength() const;
ParentLayerCoord GetPageStart() const;

Просмотреть файл

@ -105,25 +105,12 @@ void
OverscrollHandoffChain::SnapBackOverscrolledApzc(const AsyncPanZoomController* aStart) const
{
uint32_t i = IndexOf(aStart);
for (; i < Length(); ++i) {
AsyncPanZoomController* apzc = mChain[i];
if (!apzc->IsDestroyed() && apzc->SnapBackIfOverscrolled()) {
// At most one APZC from |aStart| onwards can be overscrolled.
break;
}
}
// In debug builds, verify our assumption that only one APZC from |aStart|
// onwards is overscrolled.
#ifdef DEBUG
++i;
for (; i < Length(); ++i) {
AsyncPanZoomController* apzc = mChain[i];
if (!apzc->IsDestroyed()) {
MOZ_ASSERT(!apzc->IsOverscrolled());
apzc->SnapBackIfOverscrolled();
}
}
#endif
}
bool

Просмотреть файл

@ -71,23 +71,44 @@ ShouldZoomToElement(const nsCOMPtr<dom::Element>& aElement) {
}
// Calculate the bounding rect of |aElement|, relative to the origin
// of the document associated with |aShell|.
// |aRootScrollFrame| should be the root scroll frame of the document in
// question.
// The implementation is adapted from Element::GetBoundingClientRect().
// of the scrolled content of |aRootScrollFrame|.
// The implementation of this calculation is adapted from
// Element::GetBoundingClientRect().
//
// Where the element is contained inside a scrollable subframe, the
// bounding rect is clipped to the bounds of the subframe.
static CSSRect
GetBoundingContentRect(const nsCOMPtr<nsIPresShell>& aShell,
const nsCOMPtr<dom::Element>& aElement,
GetBoundingContentRect(const nsCOMPtr<dom::Element>& aElement,
const nsIScrollableFrame* aRootScrollFrame) {
CSSRect result;
if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
return CSSRect::FromAppUnits(
nsIFrame* relativeTo = aRootScrollFrame->GetScrolledFrame();
result = CSSRect::FromAppUnits(
nsLayoutUtils::GetAllInFlowRectsUnion(
frame,
aShell->GetRootFrame(),
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS)
+ aRootScrollFrame->GetScrollPosition());
relativeTo,
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS));
// If the element is contained in a scrollable frame that is not
// the root scroll frame, make sure to clip the result so that it is
// not larger than the containing scrollable frame's bounds.
nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetNearestScrollableFrame(frame);
if (scrollFrame && scrollFrame != aRootScrollFrame) {
nsIFrame* subFrame = do_QueryFrame(scrollFrame);
MOZ_ASSERT(subFrame);
// Get the bounds of the scroll frame in the same coordinate space
// as |result|.
CSSRect subFrameRect = CSSRect::FromAppUnits(
nsLayoutUtils::TransformFrameRectToAncestor(
subFrame,
subFrame->GetRectRelativeToSelf(),
relativeTo));
result = subFrameRect.Intersect(result);
}
return CSSRect();
}
return result;
}
static bool
@ -143,7 +164,27 @@ CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& aRootContentDocument,
FrameMetrics metrics = nsLayoutUtils::CalculateBasicFrameMetrics(rootScrollFrame);
CSSRect compositedArea(metrics.GetScrollOffset(), metrics.CalculateCompositedSizeInCssPixels());
const CSSCoord margin = 15;
CSSRect rect = GetBoundingContentRect(shell, element, rootScrollFrame);
CSSRect rect = GetBoundingContentRect(element, rootScrollFrame);
// If the element is taller than the visible area of the page scale
// the height of the |rect| so that it has the same aspect ratio as
// the root frame. The clipped |rect| is centered on the y value of
// the touch point. This allows tall narrow elements to be zoomed.
if (!rect.IsEmpty() && compositedArea.width > 0.0f) {
const float widthRatio = rect.width / compositedArea.width;
float targetHeight = compositedArea.height * widthRatio;
if (widthRatio < 0.9 && targetHeight < rect.height) {
const CSSPoint scrollPoint = CSSPoint::FromAppUnits(rootScrollFrame->GetScrollPosition());
float newY = aPoint.y + scrollPoint.y - (targetHeight * 0.5f);
if ((newY + targetHeight) > (rect.y + rect.height)) {
rect.y += rect.height - targetHeight;
} else if (newY > rect.y) {
rect.y = newY;
}
rect.height = targetHeight;
}
}
rect = CSSRect(std::max(metrics.GetScrollableRect().x, rect.x - margin),
rect.y,
rect.width + 2 * margin,

Просмотреть файл

@ -91,7 +91,7 @@ BasicPaintedLayer::PaintThebes(gfxContext* aContext,
groupContext = aContext;
}
SetAntialiasingFlags(this, groupContext->GetDrawTarget());
aCallback(this, groupContext, toDraw, &toDraw,
aCallback(this, groupContext, toDraw, toDraw,
DrawRegionClip::NONE, nsIntRegion(), aCallbackData);
if (needsGroup) {
aContext->PopGroupToSource();

Просмотреть файл

@ -112,7 +112,7 @@ protected:
BasicManager()->SetTransactionIncomplete();
return;
}
aCallback(this, aContext, aExtendedRegionToDraw, &aExtendedRegionToDraw,
aCallback(this, aContext, aExtendedRegionToDraw, aExtendedRegionToDraw,
aClip, aRegionToInvalidate, aCallbackData);
// Everything that's visible has been validated. Do this instead of just
// OR-ing with aRegionToDraw, since that can lead to a very complex region

Просмотреть файл

@ -87,7 +87,7 @@ ClientPaintedLayer::PaintThebes()
ClientManager()->GetPaintedLayerCallback()(this,
ctx,
iter.mDrawRegion,
nullptr,
iter.mDrawRegion,
state.mClip,
state.mRegionToInvalidate,
ClientManager()->GetPaintedLayerCallbackData());

Просмотреть файл

@ -270,5 +270,26 @@ CompositableClient::DumpTextureClient(std::stringstream& aStream, TextureClient*
aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
}
AutoRemoveTexture::~AutoRemoveTexture()
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
if (mCompositable && mTexture && mCompositable->GetForwarder()) {
// remove old buffer from CompositableHost
RefPtr<AsyncTransactionWaiter> waiter = new AsyncTransactionWaiter();
RefPtr<AsyncTransactionTracker> tracker =
new RemoveTextureFromCompositableTracker(waiter);
// Hold TextureClient until transaction complete.
tracker->SetTextureClient(mTexture);
mTexture->SetRemoveFromCompositableWaiter(waiter);
// RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
mCompositable->GetForwarder()->RemoveTextureFromCompositableAsync(tracker, mCompositable, mTexture);
}
#else
if (mCompositable && mTexture) {
mCompositable->RemoveTexture(mTexture);
}
#endif
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -248,12 +248,7 @@ struct AutoRemoveTexture
, mCompositable(aCompositable)
{}
~AutoRemoveTexture()
{
if (mCompositable && mTexture) {
mCompositable->RemoveTexture(mTexture);
}
}
~AutoRemoveTexture();
RefPtr<TextureClient> mTexture;
private:

Просмотреть файл

@ -360,7 +360,6 @@ ImageClientOverlay::UpdateImage(ImageContainer* aContainer, uint32_t aContentFla
}
mLastUpdateGenerationCounter = (uint32_t)image->GetSerial();
AutoRemoveTexture autoRemoveTexture(this);
if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) {
OverlayImage* overlayImage = static_cast<OverlayImage*>(image);
uint32_t overlayId = overlayImage->GetOverlayId();

Просмотреть файл

@ -181,7 +181,7 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y));
aCallback(mPaintedLayer, ctx, paintRegion, &paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
aCallback(mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
}
// Mark the area we just drew into the back buffer as invalid in the front buffer as they're

Просмотреть файл

@ -964,7 +964,7 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferDraw",
js::ProfileEntry::Category::GRAPHICS);
mCallback(mPaintedLayer, ctxt, aPaintRegion, &aDirtyRegion,
mCallback(mPaintedLayer, ctxt, aPaintRegion, aDirtyRegion,
DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
}
@ -1171,7 +1171,7 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
ctx->SetMatrix(
ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin)));
mCallback(mPaintedLayer, ctx, aPaintRegion, &aDirtyRegion,
mCallback(mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
mMoz2DTiles.clear();
// Reset:

Просмотреть файл

@ -13,7 +13,7 @@
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/PNuwa.h"
#include "mozilla/hal_sandbox/PHal.h"
#if defined(DEBUG) || defined(ENABLE_TESTS)
@ -144,7 +144,7 @@ ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Sid
}
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess() &&
if (IsNuwaProcess() && NS_IsMainThread() &&
Preferences::GetBool("dom.ipc.processPrelaunch.testMode")) {
// The pref value is turned on in a deadlock test against the Nuwa
// process. The sleep here makes it easy to trigger the deadlock

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef jit_AsmJSCompile_h
#define jit_AsmJSCompile_h
#include "jit/CompileWrappers.h"
namespace js {
class AsmFunction;
class LifoAlloc;
class ModuleCompiler;
class ModuleCompileResults;
namespace jit {
class LIRGraph;
class MIRGenerator;
}
struct ModuleCompileInputs
{
jit::CompileCompartment* compartment;
jit::CompileRuntime* runtime;
bool usesSignalHandlersForOOB;
ModuleCompileInputs(jit::CompileCompartment* compartment,
jit::CompileRuntime* runtime,
bool usesSignalHandlersForOOB)
: compartment(compartment),
runtime(runtime),
usesSignalHandlersForOOB(usesSignalHandlersForOOB)
{}
};
class MOZ_RAII AsmModuleCompilerScope
{
ModuleCompiler* m_;
AsmModuleCompilerScope(const AsmModuleCompilerScope&) = delete;
AsmModuleCompilerScope(const AsmModuleCompilerScope&&) = delete;
AsmModuleCompilerScope& operator=(const AsmModuleCompilerScope&&) = delete;
public:
AsmModuleCompilerScope()
: m_(nullptr)
{}
void setModule(ModuleCompiler* m) {
MOZ_ASSERT(m);
m_ = m;
}
ModuleCompiler& module() const {
MOZ_ASSERT(m_);
return *m_;
}
~AsmModuleCompilerScope();
};
bool CreateAsmModuleCompiler(ModuleCompileInputs mci, AsmModuleCompilerScope* scope);
bool GenerateAsmFunctionMIR(ModuleCompiler& m, LifoAlloc& lifo, AsmFunction& func, jit::MIRGenerator** mir);
bool GenerateAsmFunctionCode(ModuleCompiler& m, AsmFunction& func, jit::MIRGenerator& mir, jit::LIRGraph& lir);
void FinishAsmModuleCompilation(ModuleCompiler& m, ScopedJSDeletePtr<ModuleCompileResults>* results);
} // namespace js
#endif // jit_AsmJSCompile_h

1148
js/src/asmjs/AsmJSGlobals.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -15,7 +15,8 @@ function usage() {
clean=1
platform=""
TIMEOUT=3h
# 3 hours. OS X doesn't support the "sleep 3h" syntax.
TIMEOUT=10800
while [ $# -gt 1 ]; do
case "$1" in
--dep)
@ -91,6 +92,8 @@ elif [ "$OSTYPE" = "linux-gnu" ]; then
MAKEFLAGS=-j4
if [ "$VARIANT" = "arm-sim" ]; then
USE_64BIT=false
elif [ "$VARIANT" = "arm64-sim" ]; then
USE_64BIT=true
else
case "$platform" in
linux64)
@ -168,6 +171,8 @@ if type setarch >/dev/null 2>&1; then
fi
RUN_JSTESTS=true
RUN_JITTEST=true
RUN_JSAPITESTS=true
PARENT=$$
@ -206,11 +211,21 @@ elif [[ "$VARIANT" = "warnaserr" ||
elif [[ "$VARIANT" = "arm-sim" ||
"$VARIANT" = "plaindebug" ]]; then
export JSTESTS_EXTRA_ARGS=--jitflags=debug
elif [[ "$VARIANT" = arm64* ]]; then
# The ARM64 JIT is not yet fully functional, and asm.js does not work.
# Just run "make check". We mostly care about not breaking the build at this point.
RUN_JITTEST=false
RUN_JSAPITESTS=false
RUN_JSTESTS=false
fi
$COMMAND_PREFIX $MAKE check || exit 1
$COMMAND_PREFIX $MAKE check-jit-test || exit 1
$COMMAND_PREFIX $OBJDIR/dist/bin/jsapi-tests || exit 1
if $RUN_JITTEST; then
$COMMAND_PREFIX $MAKE check-jit-test || exit 1
fi
if $RUN_JSAPITESTS; then
$COMMAND_PREFIX $OBJDIR/dist/bin/jsapi-tests || exit 1
fi
if $RUN_JSTESTS; then
$COMMAND_PREFIX $MAKE check-jstests || exit 1
fi

Просмотреть файл

@ -0,0 +1,5 @@
--enable-optimize
--enable-debug
--enable-stdcxx-compat
--disable-shared-js
--enable-simulator=arm64

Просмотреть файл

@ -38,7 +38,7 @@ function indirectCallCannotGC(fullCaller, fullVariable)
if (name == "op" && /GetWeakmapKeyDelegate/.test(caller))
return true;
var CheckCallArgs = "AsmJSValidate.cpp:uint8 CheckCallArgs(FunctionValidator*, js::frontend::ParseNode*, (uint8)(FunctionValidator*,js::frontend::ParseNode*,Type)*, Signature*)";
var CheckCallArgs = "AsmJSValidate.cpp:uint8 CheckCallArgs(FunctionValidator*, js::frontend::ParseNode*, (uint8)(FunctionValidator*,js::frontend::ParseNode*,js::wasm::Type)*, js::wasm::Signature*)";
if (name == "checkArg" && caller == CheckCallArgs)
return true;

Просмотреть файл

@ -31,6 +31,14 @@
#ifndef V8_REGEXP_AST_H_
#define V8_REGEXP_AST_H_
// Prevent msvc build failures as indicated in bug 1205328
#ifdef min
# undef min
#endif
#ifdef max
# undef max
#endif
#include "irregexp/RegExpEngine.h"
namespace js {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше