Merge m-c to fx-team. a=merge
Merge m-c to fx-team. a=merge
--- a/b2g/app.mozbuild
+++ b/b2g/app.mozbuild
@@ -1,15 +1,17 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
if not CONFIG['LIBXUL_SDK']:
include('/toolkit/toolkit.mozbuild')
elif CONFIG['ENABLE_TESTS']:
- add_tier_dir('testharness', 'testing/mochitest')
+ DIRS += ['/testing/mochitest']
if CONFIG['MOZ_EXTENSIONS']:
- add_tier_dir('app', 'extensions')
+ DIRS += ['/extensions']
-add_tier_dir('app', CONFIG['MOZ_BRANDING_DIRECTORY'])
-add_tier_dir('app', 'b2g')
+DIRS += [
+ '/%s' % CONFIG['MOZ_BRANDING_DIRECTORY'],
+ '/b2g',
+]
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<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="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<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="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"git_revision": "",
"remote": "",
"branch": ""
},
- "revision": "52f7b7099a47ab3904a70d9a295ab0ed927ad59e",
+ "revision": "3e43be9b8c24802b40fdfbcf17895c4355e6d238",
"repo_path": "/integration/gaia-central"
}
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<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="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<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="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<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="191d805f4911628d37a8a90a1e23a6013995138f"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d711d1e469eeeecf25a02b2407a542a598918b2c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="4f9042d3a705307849a6f63961eaaaa2e1d85d77"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/dev/app.mozbuild
+++ b/b2g/dev/app.mozbuild
@@ -2,24 +2,24 @@
# 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/.
if not CONFIG['LIBXUL_SDK']:
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
- add_tier_dir('app', 'extensions')
+ DIRS += ['/extensions']
-add_tier_dir('app', [CONFIG['MOZ_BRANDING_DIRECTORY']])
+DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
if CONFIG['MOZ_WEBAPP_RUNTIME']:
- add_tier_dir('app', 'webapprt')
-
-add_tier_dir('app', 'b2g/chrome')
-add_tier_dir('app', 'b2g/components')
+ DIRS += ['/webapprt']
-add_tier_dir('app', 'b2g/dev/app')
+DIRS += [
+ '/b2g/chrome',
+ '/b2g/components',
+ '/b2g/dev/app',
-# Never add tier dirs after browser because they apparently won't get
-# packaged properly on Mac.
-add_tier_dir('app', 'browser')
-
+ # Never add dirs after browser because they apparently won't get
+ # packaged properly on Mac.
+ '/browser',
+]
--- a/browser/app.mozbuild
+++ b/browser/app.mozbuild
@@ -2,19 +2,19 @@
# 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/.
if not CONFIG['LIBXUL_SDK']:
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
- add_tier_dir('app', 'extensions')
+ DIRS += ['/extensions']
-add_tier_dir('app', [CONFIG['MOZ_BRANDING_DIRECTORY']])
+DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
if CONFIG['MOZ_WEBAPP_RUNTIME']:
- add_tier_dir('app', 'webapprt')
+ DIRS += ['/webapprt']
-# Never add tier dirs after browser because they apparently won't get
+# Never add dirs after browser because they apparently won't get
# packaged properly on Mac.
-add_tier_dir('app', 'browser')
+DIRS += ['/browser']
--- a/build/valgrind/cross-architecture.sup
+++ b/build/valgrind/cross-architecture.sup
@@ -68,40 +68,44 @@
# Other leaks #
#################
{
Bug 794369
Memcheck:Leak
fun:malloc
fun:moz_xmalloc
+ ...
fun:_ZN20mozJSComponentLoader10LoadModuleERN7mozilla12FileLocationE
...
}
{
Bug 794370
Memcheck:Leak
fun:malloc
fun:moz_xmalloc
+ ...
fun:_ZN22nsComponentManagerImpl15RegisterFactoryERK4nsIDPKcS4_P10nsIFactory
...
}
{
Bug 794372
Memcheck:Leak
fun:malloc
fun:moz_xmalloc
+ ...
fun:_ZN22nsComponentManagerImpl22RegisterCIDEntryLockedEPKN7mozilla6Module8CIDEntryEPNS_11KnownModuleE
...
}
{
Bug 794374
Memcheck:Leak
fun:malloc
fun:moz_xmalloc
+ ...
fun:_ZN22nsComponentManagerImpl17ManifestComponentERNS_25ManifestProcessingContextEiPKPc
...
}
{
Bug 1017112
Memcheck:Leak
fun:malloc
...
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -96,17 +96,16 @@ else
SDK_HEADERS \
SDK_LIBRARY \
SHARED_LIBRARY_LIBS \
SHARED_LIBRARY_NAME \
SIMPLE_PROGRAMS \
SONAME \
STATIC_LIBRARY_NAME \
TEST_DIRS \
- TIERS \
TOOL_DIRS \
XPCSHELL_TESTS \
XPIDL_MODULE \
$(NULL)
_DEPRECATED_VARIABLES := \
ANDROID_RESFILES \
EXPORT_LIBRARY \
@@ -119,15 +118,16 @@ else
MOCHITEST_CHROME_FILES \
MOCHITEST_FILES \
MOCHITEST_FILES_PARTS \
MOCHITEST_METRO_FILES \
MOCHITEST_ROBOCOP_FILES \
SHORT_LIBNAME \
TESTING_JS_MODULES \
TESTING_JS_MODULE_DIR \
+ TIERS \
$(NULL)
# Freeze the values specified by moz.build to catch them if they fail.
$(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES) $(_DEPRECATED_VARIABLES),$(eval $(var)_FROZEN := '$($(var))'))
endif
--- a/config/makefiles/debugmake.mk
+++ b/config/makefiles/debugmake.mk
@@ -20,22 +20,16 @@ endef
define shell_quote
'$(subst $(CR),\$(CR),$(subst ','\'',$(1)))'
endef
echo-variable-%:
@echo $(call shell_quote,$($*))
-echo-tiers:
- @echo $(TIERS)
-
-echo-tier-dirs:
- @$(foreach tier,$(TIERS),echo '$(tier):'; echo ' dirs: $(tier_$(tier)_dirs)')
-
echo-dirs:
@echo $(call shell_quote,$(DIRS))
define print_var
@printf '%20s = %s\n' $1 $(call shell_quote,$($1))
endef
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -25,22 +25,16 @@ endif
# make -C foo/bar
# make -C foo/baz
# make -C qux
ifeq (.,$(DEPTH))
include root.mk
-# Disable build status for mach in top directories without TIERS.
-# In practice this disables it when recursing under js/src, which confuses mach.
-ifndef TIERS
-BUILDSTATUS =
-endif
-
# Main rules (export, compile, libs and tools) call recurse_* rules.
# This wrapping is only really useful for build status.
compile libs export tools::
$(call BUILDSTATUS,TIER_START $@)
+$(MAKE) recurse_$@
$(call BUILDSTATUS,TIER_FINISH $@)
# Special rule that does install-manifests (cf. Makefile.in) + compile
@@ -65,19 +59,17 @@ CURRENT_TIER := $(subst recurse_,,$(CURR
ifdef CURRENT_TIER
ifeq (0,$(MAKELEVEL))
export NO_RECURSE_MAKELEVEL=1
else
export NO_RECURSE_MAKELEVEL=$(word $(MAKELEVEL),2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
endif
endif
-# Get all directories traversed for all subtiers in the current tier, or use
-# directly the $(*_dirs) variables available in root.mk when there is no
-# TIERS (like for js/src).
+# Use the $(*_dirs) variables available in root.mk
CURRENT_DIRS := $($(CURRENT_TIER)_dirs)
# Need a list of compile targets because we can't use pattern rules:
# https://savannah.gnu.org/bugs/index.php?42833
.PHONY: $(compile_targets)
$(compile_targets):
$(call SUBMAKE,$(@F),$(@D))
@@ -118,42 +110,30 @@ ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVE
compile libs export tools::
else
#########################
# Tier traversal handling
#########################
-ifdef TIERS
-
-libs export tools::
- $(call BUILDSTATUS,TIER_START $@)
- $(foreach tier,$(TIERS), $(if $(filter-out libs_precompile tools_precompile,$@_$(tier)), \
- $(foreach dir, $(tier_$(tier)_dirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),$@))))
- $(call BUILDSTATUS,TIER_FINISH $@)
-
-else
-
define CREATE_SUBTIER_TRAVERSAL_RULE
.PHONY: $(1)
$(1):: $$(SUBMAKEFILES)
$$(LOOP_OVER_DIRS)
endef
$(foreach subtier,export libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
ifndef TOPLEVEL_BUILD
libs:: target host
endif
-endif # ifdef TIERS
-
endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
endif # ifeq (.,$(DEPTH))
recurse:
@$(RECURSED_COMMAND)
$(LOOP_OVER_DIRS)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -643,25 +643,18 @@ MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRA
checkout:
$(MAKE) -C $(topsrcdir) -f client.mk checkout
clean clobber realclean clobber_all::
-$(RM) $(ALL_TRASH)
-$(RM) -r $(ALL_TRASH_DIRS)
-ifdef TIERS
-clean clobber realclean clobber_all distclean::
- $(foreach dir, \
- $(foreach tier, $(TIERS), $(tier_$(tier)_dirs)), \
- -$(call SUBMAKE,$@,$(dir)))
-else
clean clobber realclean clobber_all distclean::
$(foreach dir,$(DIRS),-$(call SUBMAKE,$@,$(dir)))
-endif
distclean::
-$(RM) -r $(ALL_TRASH_DIRS)
-$(RM) $(ALL_TRASH) \
Makefile .HSancillary \
$(wildcard *.$(OBJ_SUFFIX)) $(wildcard *.ho) $(wildcard host_*.o*) \
$(wildcard *.$(LIB_SUFFIX)) $(wildcard *$(DLL_SUFFIX)) \
$(wildcard *.$(IMPORT_LIB_SUFFIX))
@@ -1631,17 +1624,16 @@ endif
FREEZE_VARIABLES = \
CSRCS \
CPPSRCS \
EXPORTS \
DIRS \
LIBRARY \
MODULE \
- TIERS \
EXTRA_COMPONENTS \
EXTRA_PP_COMPONENTS \
$(NULL)
$(foreach var,$(FREEZE_VARIABLES),$(eval $(var)_FROZEN := '$($(var))'))
CHECK_FROZEN_VARIABLES = $(foreach var,$(FREEZE_VARIABLES), \
$(if $(subst $($(var)_FROZEN),,'$($(var))'),$(error Makefile variable '$(var)' changed value after including rules.mk. Was $($(var)_FROZEN), now $($(var)).)))
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -641,16 +641,20 @@ public:
const nsAString& aLocalName,
ErrorResult& aError);
bool HasAttribute(const nsAString& aName) const
{
return InternalGetExistingAttrNameFromQName(aName) != nullptr;
}
bool HasAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName) const;
+ bool HasAttributes() const
+ {
+ return HasAttrs();
+ }
Element* Closest(const nsAString& aSelector,
ErrorResult& aResult);
bool Matches(const nsAString& aSelector,
ErrorResult& aError);
already_AddRefed<nsIHTMLCollection>
GetElementsByTagName(const nsAString& aQualifiedName);
already_AddRefed<nsIHTMLCollection>
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
@@ -1344,21 +1348,16 @@ inline mozilla::dom::Element* nsINode::A
}
inline const mozilla::dom::Element* nsINode::AsElement() const
{
MOZ_ASSERT(IsElement());
return static_cast<const mozilla::dom::Element*>(this);
}
-inline bool nsINode::HasAttributes() const
-{
- return IsElement() && AsElement()->HasAttrs();
-}
-
/**
* Macros to implement Clone(). _elementName is the class for which to implement
* Clone.
*/
#define NS_IMPL_ELEMENT_CLONE(_elementName) \
nsresult \
_elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const \
{ \
@@ -1532,16 +1531,21 @@ NS_IMETHOD HasAttribute(const nsAString&
} \
NS_IMETHOD HasAttributeNS(const nsAString& namespaceURI, \
const nsAString& localName, \
bool* _retval) MOZ_FINAL \
{ \
*_retval = Element::HasAttributeNS(namespaceURI, localName); \
return NS_OK; \
} \
+NS_IMETHOD HasAttributes(bool* _retval) MOZ_FINAL \
+{ \
+ *_retval = Element::HasAttributes(); \
+ return NS_OK; \
+} \
NS_IMETHOD GetAttributeNode(const nsAString& name, \
nsIDOMAttr** _retval) MOZ_FINAL \
{ \
NS_IF_ADDREF(*_retval = Element::GetAttributeNode(name)); \
return NS_OK; \
} \
NS_IMETHOD SetAttributeNode(nsIDOMAttr* newAttr, \
nsIDOMAttr** _retval) MOZ_FINAL \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -24,16 +24,17 @@
#include "mozilla/GuardObjects.h"
#include "mozilla/TimeStamp.h"
#include "nsContentListDeclarations.h"
#include "nsMathUtils.h"
#include "nsTArrayForwardDeclare.h"
#include "Units.h"
#include "mozilla/dom/AutocompleteInfoBinding.h"
#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/FloatingPoint.h"
#if defined(XP_WIN)
// Undefine LoadImage to prevent naming conflict with Windows.
#undef LoadImage
#endif
class imgICache;
class imgIContainer;
@@ -181,16 +182,17 @@ public:
static bool IsImageSrcSetDisabled();
static bool LookupBindingMember(JSContext* aCx, nsIContent *aContent,
JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc);
/**
* Returns the parent node of aChild crossing document boundaries.
+ * Uses the parent node in the composed document.
*/
static nsINode* GetCrossDocParentNode(nsINode* aChild);
/**
* Do not ever pass null pointers to this method. If one of your
* nsIContents is null, you have to decide for yourself what
* "IsDescendantOf" really means.
*
@@ -211,17 +213,18 @@ public:
* See the concept of "host-including inclusive ancestor" in the DOM
* specification.
*/
static bool ContentIsHostIncludingDescendantOf(
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
/**
* Similar to ContentIsDescendantOf except it crosses document boundaries,
- * also crosses ShadowRoot boundaries from ShadowRoot to its host.
+ * this function uses ancestor/descendant relations in the composed document
+ * (see shadow DOM spec).
*/
static bool ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
nsINode* aPossibleAncestor);
/*
* This method fills the |aArray| with all ancestor nodes of |aNode|
* including |aNode| at the zero index.
*/
@@ -2346,48 +2349,48 @@ public:
} // namespace dom
} // namespace mozilla
#define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator) \
if (aIID.Equals(NS_GET_IID(_interface))) { \
foundInterface = static_cast<_interface *>(_allocator); \
if (!foundInterface) { \
- *aInstancePtr = nullptr; \
+ *aInstancePtr = nullptr; \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} else
/*
* In the following helper macros we exploit the fact that the result of a
* series of additions will not be finite if any one of the operands in the
* series is not finite.
*/
#define NS_ENSURE_FINITE(f, rv) \
- if (!NS_finite(f)) { \
+ if (!mozilla::IsFinite(f)) { \
return (rv); \
}
#define NS_ENSURE_FINITE2(f1, f2, rv) \
- if (!NS_finite((f1)+(f2))) { \
+ if (!mozilla::IsFinite((f1)+(f2))) { \
return (rv); \
}
#define NS_ENSURE_FINITE4(f1, f2, f3, f4, rv) \
- if (!NS_finite((f1)+(f2)+(f3)+(f4))) { \
+ if (!mozilla::IsFinite((f1)+(f2)+(f3)+(f4))) { \
return (rv); \
}
#define NS_ENSURE_FINITE5(f1, f2, f3, f4, f5, rv) \
- if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5))) { \
+ if (!mozilla::IsFinite((f1)+(f2)+(f3)+(f4)+(f5))) { \
return (rv); \
}
#define NS_ENSURE_FINITE6(f1, f2, f3, f4, f5, f6, rv) \
- if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) { \
+ if (!mozilla::IsFinite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) { \
return (rv); \
}
// Deletes a linked list iteratively to avoid blowing up the stack (bug 460444).
#define NS_CONTENT_DELETE_LIST_MEMBER(type_, ptr_, member_) \
{ \
type_ *cur = (ptr_)->member_; \
(ptr_)->member_ = nullptr; \
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -101,16 +101,17 @@ struct CustomElementDefinition;
class DocumentFragment;
class DocumentType;
class DOMImplementation;
class DOMStringList;
class Element;
struct ElementRegistrationOptions;
class Event;
class EventTarget;
+class FontFaceSet;
class FrameRequestCallback;
class ImportManager;
class OverfillCallback;
class HTMLBodyElement;
struct LifecycleCallbackArgs;
class Link;
class GlobalObject;
class NodeFilter;
@@ -2385,16 +2386,21 @@ public:
nsWeakPtr weakNode = do_GetWeakReference(node);
if (weakNode) {
mBlockedTrackingNodes.AppendElement(weakNode);
}
}
+ // FontFaceSource
+ mozilla::dom::FontFaceSet* GetFonts(mozilla::ErrorResult& aRv);
+
+ bool DidFireDOMContentLoaded() const { return mDidFireDOMContentLoaded; }
+
private:
uint64_t mWarnedAbout;
SelectorCache mSelectorCache;
protected:
~nsIDocument();
nsPropertyTable* GetExtraPropertyTable(uint16_t aCategory);
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1635,18 +1635,17 @@ public:
const nsString& localName = LocalName();
if (localName.IsVoid()) {
aLocalName.SetNull();
} else {
aLocalName.SetStringBuffer(nsStringBuffer::FromString(localName),
localName.Length());
}
}
- // HasAttributes is defined inline in Element.h.
- bool HasAttributes() const;
+
nsDOMAttributeMap* GetAttributes();
void SetUserData(JSContext* aCx, const nsAString& aKey,
JS::Handle<JS::Value> aData,
JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
void GetUserData(JSContext* aCx, const nsAString& aKey,
JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
@@ -1989,22 +1988,16 @@ ToCanonicalSupports(nsINode* aPointer)
nsINode::GetPrefix(aPrefix); \
return NS_OK; \
} \
NS_IMETHOD GetLocalName(nsAString& aLocalName) __VA_ARGS__ \
{ \
aLocalName = nsINode::LocalName(); \
return NS_OK; \
} \
- using nsINode::HasAttributes; \
- NS_IMETHOD HasAttributes(bool* aResult) __VA_ARGS__ \
- { \
- *aResult = nsINode::HasAttributes(); \
- return NS_OK; \
- } \
NS_IMETHOD GetDOMBaseURI(nsAString& aBaseURI) __VA_ARGS__ \
{ \
nsINode::GetBaseURI(aBaseURI); \
return NS_OK; \
} \
NS_IMETHOD CompareDocumentPosition(nsIDOMNode* aOther, uint16_t* aResult) __VA_ARGS__ \
{ \
return nsINode::CompareDocumentPosition(aOther, aResult); \
--- a/content/base/src/ChildIterator.h
+++ b/content/base/src/ChildIterator.h
@@ -117,22 +117,24 @@ protected:
uint32_t mIndexInInserted;
// A flag to let us know that we haven't started iterating yet.
bool mIsFirst;
};
// Iterates over the flattened children of a node, which accounts for anonymous
// children and nodes moved by insertion points. If a node has anonymous
-// children, those are iterated over.
+// children, those are iterated over. The iterator can be initialized to start
+// at the end by providing false for aStartAtBeginning in order to start
+// iterating in reverse from the last child.
class FlattenedChildIterator : public ExplicitChildIterator
{
public:
- explicit FlattenedChildIterator(nsIContent* aParent)
- : ExplicitChildIterator(aParent), mXBLInvolved(false)
+ explicit FlattenedChildIterator(nsIContent* aParent, bool aStartAtBeginning = true)
+ : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
{
Init(false);
}
FlattenedChildIterator(FlattenedChildIterator&& aOther)
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
FlattenedChildIterator(const FlattenedChildIterator& aOther)
@@ -140,40 +142,43 @@ public:
bool XBLInvolved() { return mXBLInvolved; }
protected:
/**
* This constructor is a hack to help AllChildrenIterator which sometimes
* doesn't want to consider XBL.
*/
- FlattenedChildIterator(nsIContent* aParent, bool aIgnoreXBL)
- : ExplicitChildIterator(aParent), mXBLInvolved(false)
+ FlattenedChildIterator(nsIContent* aParent, uint32_t aFlags, bool aStartAtBeginning = true)
+ : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
{
- Init(aIgnoreXBL);
+ bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
+ Init(ignoreXBL);
}
void Init(bool aIgnoreXBL);
// For certain optimizations, nsCSSFrameConstructor needs to know if the
// child list of the element that we're iterating matches its .childNodes.
bool mXBLInvolved;
};
/**
* AllChildrenIterator returns the children of a element including before /
* after content and optionally XBL children. It assumes that no mutation of
* the DOM or frame tree takes place during iteration, and will break horribly
- * if that is not true.
+ * if that is not true. The iterator can be initialized to start at the end by
+ * providing false for aStartAtBeginning in order to start iterating in reverse
+ * from the last child.
*/
class AllChildrenIterator : private FlattenedChildIterator
{
public:
- AllChildrenIterator(nsIContent* aNode, uint32_t aFlags) :
- FlattenedChildIterator(aNode, (aFlags & nsIContent::eAllButXBL)),
+ AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) :
+ FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mOriginalContent(aNode), mFlags(aFlags),
mPhase(eNeedBeforeKid) {}
AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mFlags(aOther.mFlags),
mPhase(aOther.mPhase)
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -2934,31 +2934,36 @@ void
Element::MozRequestPointerLock()
{
OwnerDoc()->RequestPointerLock(this);
}
void
Element::GetAnimationPlayers(nsTArray<nsRefPtr<AnimationPlayer> >& aPlayers)
{
+ nsIDocument* doc = GetComposedDoc();
+ if (doc) {
+ doc->FlushPendingNotifications(Flush_Style);
+ }
+
nsIAtom* properties[] = { nsGkAtoms::transitionsProperty,
nsGkAtoms::animationsProperty };
for (size_t propIdx = 0; propIdx < MOZ_ARRAY_LENGTH(properties);
propIdx++) {
AnimationPlayerCollection* collection =
static_cast<AnimationPlayerCollection*>(
GetProperty(properties[propIdx]));
if (!collection) {
continue;
}
for (size_t playerIdx = 0;
playerIdx < collection->mPlayers.Length();
playerIdx++) {
AnimationPlayer* player = collection->mPlayers[playerIdx];
- if (player->IsCurrent()) {
+ if (player->HasCurrentSource() || player->HasInEffectSource()) {
aPlayers.AppendElement(player);
}
}
}
}
NS_IMETHODIMP
Element::GetInnerHTML(nsAString& aInnerHTML)
--- a/content/base/src/nsCSPUtils.cpp
+++ b/content/base/src/nsCSPUtils.cpp
@@ -293,62 +293,62 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
#ifdef PR_LOGGING
{
nsAutoCString spec;
aUri->GetSpec(spec);
CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s", spec.get()));
}
#endif
- // If the host is defined as a "*", and:
- // a) no scheme, and
- // b) no port is defined, allow the load.
- // http://www.w3.org/TR/CSP11/#matching
- if (mHost.EqualsASCII("*") &&
- mScheme.IsEmpty() &&
- mPort.IsEmpty()) {
- return true;
- }
+ // we are following the enforcement rules from the spec, see:
+ // http://www.w3.org/TR/CSP11/#match-source-expression
- // Check if the scheme matches.
+ // 4.3) scheme matching: Check if the scheme matches.
nsAutoCString scheme;
nsresult rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, false);
- if (!mScheme.EqualsASCII(scheme.get())) {
+ if (!mScheme.IsEmpty() &&
+ !mScheme.EqualsASCII(scheme.get())) {
return false;
}
// The host in nsCSpHostSrc should never be empty. In case we are enforcing
// just a specific scheme, the parser should generate a nsCSPSchemeSource.
NS_ASSERTION((!mHost.IsEmpty()), "host can not be the empty string");
- // Extract the host part from aUri.
+ // 2) host matching: Enforce a single *
+ if (mHost.EqualsASCII("*")) {
+ return true;
+ }
+
+ // Before we can check if the host matches, we have to
+ // extract the host part from aUri.
nsAutoCString uriHost;
rv = aUri->GetHost(uriHost);
NS_ENSURE_SUCCESS(rv, false);
- // Check it the allowed host starts with a wilcard.
+ // 4.5) host matching: Check if the allowed host starts with a wilcard.
if (mHost.First() == '*') {
NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'");
// Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking
- // if the remaining characters match: see http://www.w3.org/TR/CSP11/#matching
+ // if the remaining characters match
nsString wildCardHost = mHost;
wildCardHost = Substring(wildCardHost, 1, wildCardHost.Length() - 1);
if (!StringEndsWith(NS_ConvertUTF8toUTF16(uriHost), wildCardHost)) {
return false;
}
}
- // Check if hosts match.
+ // 4.6) host matching: Check if hosts match.
else if (!mHost.Equals(NS_ConvertUTF8toUTF16(uriHost))) {
return false;
}
- // If there is a path, we have to enforce path-level matching,
- // unless the channel got redirected, see:
+ // 4.9) Path matching: If there is a path, we have to enforce
+ // path-level matching, unless the channel got redirected, see:
// http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
if (!aWasRedirected && !mPath.IsEmpty()) {
// cloning uri so we can ignore the ref
nsCOMPtr<nsIURI> uri;
aUri->CloneIgnoringRef(getter_AddRefs(uri));
nsAutoCString uriPath;
rv = uri->GetPath(uriPath);
@@ -365,35 +365,36 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
// check if the loading resource matches that whitelisted file.
else {
if (!mPath.Equals(NS_ConvertUTF8toUTF16(uriPath))) {
return false;
}
}
}
- // If port uses wildcard, allow the load.
+ // 4.8) Port matching: If port uses wildcard, allow the load.
if (mPort.EqualsASCII("*")) {
return true;
}
- // Check if ports match
+ // Before we can check if the port matches, we have to
+ // query the port from aUri.
int32_t uriPort;
rv = aUri->GetPort(&uriPort);
NS_ENSURE_SUCCESS(rv, false);
uriPort = (uriPort > 0) ? uriPort : NS_GetDefaultPort(scheme.get());
- // If mPort is empty, we have to compare default ports.
+ // 4.7) Default port matching: If mPort is empty, we have to compare default ports.
if (mPort.IsEmpty()) {
int32_t port = NS_GetDefaultPort(NS_ConvertUTF16toUTF8(mScheme).get());
if (port != uriPort) {
return false;
}
}
- // Otherwise compare the ports
+ // 4.7) Port matching: Compare the ports.
else {
nsString portStr;
portStr.AppendInt(uriPort);
if (!mPort.Equals(portStr)) {
return false;
}
}
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -2020,16 +2020,20 @@ nsContentUtils::LookupBindingMember(JSCo
// static
nsINode*
nsContentUtils::GetCrossDocParentNode(nsINode* aChild)
{
NS_PRECONDITION(aChild, "The child is null!");
nsINode* parent = aChild->GetParentNode();
+ if (parent && parent->IsContent() && aChild->IsContent()) {
+ parent = aChild->AsContent()->GetFlattenedTreeParent();
+ }
+
if (parent || !aChild->IsNodeOfType(nsINode::eDOCUMENT))
return parent;
nsIDocument* doc = static_cast<nsIDocument*>(aChild);
nsIDocument* parentDoc = doc->GetParentDocument();
return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nullptr;
}
@@ -2078,22 +2082,16 @@ nsContentUtils::ContentIsCrossDocDescend
{
NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
do {
if (aPossibleDescendant == aPossibleAncestor)
return true;
- // Step over shadow root to the host node.
- ShadowRoot* shadowRoot = ShadowRoot::FromNode(aPossibleDescendant);
- if (shadowRoot) {
- aPossibleDescendant = shadowRoot->GetHost();
- }
-
aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant);
} while (aPossibleDescendant);
return false;
}
// static
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -218,16 +218,17 @@
#include "nsIDocumentEncoder.h"
#include "nsIDocumentActivity.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/DOMStringList.h"
#include "nsWindowMemoryReporter.h"
#include "nsLocation.h"
+#include "mozilla/dom/FontFaceSet.h"
#ifdef MOZ_MEDIA_NAVIGATOR
#include "mozilla/MediaManager.h"
#endif // MOZ_MEDIA_NAVIGATOR
#ifdef MOZ_WEBRTC
#include "IPeerConnection.h"
#endif // MOZ_WEBRTC
@@ -12410,8 +12411,25 @@ nsAutoSyncOperation::nsAutoSyncOperation
nsAutoSyncOperation::~nsAutoSyncOperation()
{
for (int32_t i = 0; i < mDocuments.Count(); ++i) {
mDocuments[i]->SetIsInSyncOperation(false);
}
nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel);
}
+FontFaceSet*
+nsIDocument::GetFonts(ErrorResult& aRv)
+{
+ nsIPresShell* shell = GetShell();
+ if (!shell) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ nsPresContext* presContext = shell->GetPresContext();
+ if (!presContext) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ return presContext->Fonts();
+}
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -770,16 +770,19 @@ GK_ATOM(oninstall, "oninstall")
GK_ATOM(oninvalid, "oninvalid")
GK_ATOM(onkeydown, "onkeydown")
GK_ATOM(onkeypress, "onkeypress")
GK_ATOM(onkeyup, "onkeyup")
GK_ATOM(onlanguagechange, "onlanguagechange")
GK_ATOM(onlevelchange, "onlevelchange")
GK_ATOM(onLoad, "onLoad")
GK_ATOM(onload, "onload")
+GK_ATOM(onloading, "onloading")
+GK_ATOM(onloadingdone, "onloadingdone")
+GK_ATOM(onloadingerror, "onloadingerror")
GK_ATOM(onpopstate, "onpopstate")
GK_ATOM(only, "only") // this one is not an event
GK_ATOM(onmessage, "onmessage")
GK_ATOM(onmousedown, "onmousedown")
GK_ATOM(onmouseenter, "onmouseenter")
GK_ATOM(onmouseleave, "onmouseleave")
GK_ATOM(onmousemove, "onmousemove")
GK_ATOM(onmouseout, "onmouseout")
--- a/content/base/test/TestCSPParser.cpp
+++ b/content/base/test/TestCSPParser.cpp
@@ -371,16 +371,18 @@ nsresult TestIgnorePaths() {
nsresult TestSimplePolicies() {
static const PolicyTest policies[] =
{
{ "default-src *",
"default-src *" },
{ "default-src https:",
"default-src https:" },
+ { "default-src https://*",
+ "default-src https://*" },
{ "default-src *:*",
"default-src http://*:*" },
{ "default-src *:80",
"default-src http://*:80" },
{ "default-src http://*:80",
"default-src http://*:80" },
{ "default-src javascript:",
"default-src javascript:" },
--- a/content/base/test/csp/test_csp_path_matching.html
+++ b/content/base/test/csp/test_csp_path_matching.html
@@ -19,16 +19,17 @@ SimpleTest.waitForExplicitFinish();
/* Description of the test:
* We are loading the following url (including a fragment portion):
* http://test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js#foo
* using different policies and verify that the applied policy is accurately enforced.
*/
var policies = [
["allowed", "*"],
+ ["allowed", "http://*"], // test for bug 1075230, enforcing scheme and wildcard
["allowed", "test1.example.com"],
["allowed", "test1.example.com/"],
["allowed", "test1.example.com/tests/content/base/test/csp/"],
["allowed", "test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js"],
["allowed", "test1.example.com?foo=val"],
["allowed", "test1.example.com/?foo=val"],
["allowed", "test1.example.com/tests/content/base/test/csp/?foo=val"],
--- a/content/html/content/test/test_video_wakelock.html
+++ b/content/html/content/test/test_video_wakelock.html
@@ -37,17 +37,17 @@ function testVideoPlayPause() {
startDate = new Date();
// The next step is to unlock the resource.
lockState_cpu = false;
lockState_screen = false;
video.pause();
});
- navigator.mozPower.addWakeLockListener(function testVideoPlayPauseListener(topic, state) {
+ function testVideoPlayPauseListener(topic, state) {
var locked = state == "locked-foreground" ||
state == "locked-background";
if (topic == "cpu") {
is(locked, lockState_cpu, "Video element locked the cpu - paused");
count_cpu++;
} else if (topic == "screen") {
is(locked, lockState_screen, "Video element locked the screen - paused");
@@ -57,18 +57,19 @@ function testVideoPlayPause() {
if (count_cpu == 2 && count_screen == 2) {
var diffDate = (new Date() - startDate);
ok(diffDate > 200, "There was at least 200 milliseconds between the stop and the wakelock release");
content.removeChild(video);
navigator.mozPower.removeWakeLockListener(testVideoPlayPauseListener);
runTests();
}
- });
+ }
+ navigator.mozPower.addWakeLockListener(testVideoPlayPauseListener);
video.play();
}
function testVideoPlay() {
var lockState_cpu = true;
var lockState_screen = true;
var count_cpu = 0;
var count_screen = 0;
@@ -79,17 +80,17 @@ function testVideoPlay() {
video.src = "wakelock.ogv";
content.appendChild(video);
var startDate;
video.addEventListener('progress', function() {
startDate = new Date();
});
- navigator.mozPower.addWakeLockListener(function testVideoPlayListener(topic, state) {
+ function testVideoPlayListener(topic, state) {
var locked = state == "locked-foreground" ||
state == "locked-background";
if (topic == "cpu") {
is(locked, lockState_cpu, "Video element locked the cpu - paused");
count_cpu++;
} else if (topic == "screen") {
is(locked, lockState_screen, "Video element locked the screen - paused");
@@ -103,33 +104,37 @@ function testVideoPlay() {
} else if (count_cpu == 2 && count_screen == 2) {
var diffDate = (new Date() - startDate);
ok(diffDate > 200, "There was at least milliseconds between the stop and the wakelock release");
content.removeChild(video);
navigator.mozPower.removeWakeLockListener(testVideoPlayListener);
runTests();
}
- });
+ }
+ navigator.mozPower.addWakeLockListener(testVideoPlayListener);
video.play();
}
var tests = [ testVideoPlayPause, testVideoPlay ];
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.pop();
test();
};
-SpecialPowers.addPermission("power", true, document);
-SpecialPowers.pushPrefEnv({"set": [["media.wakelock_timeout", 500]]}, runTests);
+SpecialPowers.pushPermissions(
+ [{'type': 'power', 'allow': true, 'context': document}],
+ function() {
+ SpecialPowers.pushPrefEnv({"set": [["media.wakelock_timeout", 500]]}, runTests);
+ });
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>
--- a/content/media/TrackUnionStream.h
+++ b/content/media/TrackUnionStream.h
@@ -243,21 +243,20 @@ protected:
MediaStream* source = map->mInputPort->GetSource();
GraphTime next;
*aOutputTrackFinished = false;
for (GraphTime t = aFrom; t < aTo; t = next) {
MediaInputPort::InputInterval interval = map->mInputPort->GetNextInputInterval(t);
interval.mEnd = std::min(interval.mEnd, aTo);
StreamTime inputEnd = source->GraphTimeToStreamTime(interval.mEnd);
- TrackTicks inputTrackEndPoint = TRACK_TICKS_MAX;
+ TrackTicks inputTrackEndPoint = aInputTrack->GetEnd();
if (aInputTrack->IsEnded() &&
aInputTrack->GetEndTimeRoundDown() <= inputEnd) {
- inputTrackEndPoint = aInputTrack->GetEnd();
*aOutputTrackFinished = true;
}
if (interval.mStart >= interval.mEnd)
break;
next = interval.mEnd;
// Ticks >= startTicks and < endTicks are in the interval
@@ -320,35 +319,46 @@ protected:
// <= TimeToTicksRoundDown(rate, originalInputStart) - 1 + TimeToTicksRoundDown(rate, inputEnd) - TimeToTicksRoundDown(rate, originalInputStart) + 1
// = TimeToTicksRoundDown(rate, inputEnd)
// <= inputEnd/rate
// (now using the fact that inputEnd <= track->GetEndTimeRoundDown() for a non-ended track)
// <= TicksToTimeRoundDown(rate, aInputTrack->GetSegment()->GetDuration())/rate
// <= rate*aInputTrack->GetSegment()->GetDuration()/rate
// = aInputTrack->GetSegment()->GetDuration()
// as required.
+ // Note that while the above proof appears to be generally right, if we are suffering
+ // from a lot of underrun, then in rare cases inputStartTicks >> inputTrackEndPoint.
+ // As such, we still need to verify the sanity of property #2 and use null data as
+ // appropriate.
if (inputStartTicks < 0) {
// Data before the start of the track is just null.
// We have to add a small amount of delay to ensure that there is
// always a sample available if we see an interval that contains a
// tick boundary on the output stream's timeline but does not contain
// a tick boundary on the input stream's timeline. 1 tick delay is
// necessary and sufficient.
segment->AppendNullData(-inputStartTicks);
inputStartTicks = 0;
}
if (inputEndTicks > inputStartTicks) {
- segment->AppendSlice(*aInputTrack->GetSegment(),
- std::min(inputTrackEndPoint, inputStartTicks),
- std::min(inputTrackEndPoint, inputEndTicks));
+ if (inputEndTicks <= inputTrackEndPoint) {
+ segment->AppendSlice(*aInputTrack->GetSegment(), inputStartTicks, inputEndTicks);
+ STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
+ this, ticks, outputTrack->GetID()));
+ } else {
+ if (inputStartTicks < inputTrackEndPoint) {
+ segment->AppendSlice(*aInputTrack->GetSegment(), inputStartTicks, inputTrackEndPoint);
+ ticks -= inputTrackEndPoint - inputStartTicks;
+ }
+ segment->AppendNullData(ticks);
+ STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data and %lld of null data to track %d",
+ this, inputTrackEndPoint - inputStartTicks, ticks, outputTrack->GetID()));
+ }
}
- STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
- this, (long long)(std::min(inputTrackEndPoint, inputEndTicks) - std::min(inputTrackEndPoint, inputStartTicks)),
- outputTrack->GetID()));
}
ApplyTrackDisabling(outputTrack->GetID(), segment);
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(),
outputTrack->GetRate(), startTicks, 0,
*segment);
}
--- a/content/media/gmp/GMPSharedMemManager.cpp
+++ b/content/media/gmp/GMPSharedMemManager.cpp
@@ -35,29 +35,43 @@ GMPSharedMemManager::MgrAllocShmem(GMPSh
return true;
}
}
// Didn't find a buffer free with enough space; allocate one
size_t pagesize = ipc::SharedMemory::SystemPageSize();
aSize = (aSize + (pagesize-1)) & ~(pagesize-1); // round up to page size
bool retval = Alloc(aSize, aType, aMem);
+ // The allocator (or NeedsShmem call) should never return less than we ask for...
+ MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
if (retval) {
mData->mGmpAllocated[aClass]++;
}
return retval;
}
bool
GMPSharedMemManager::MgrDeallocShmem(GMPSharedMem::GMPMemoryClasses aClass, ipc::Shmem& aMem)
{
mData->CheckThread();
size_t size = aMem.Size<uint8_t>();
size_t total = 0;
+
+ // XXX Bug NNNNNNN Until we put better guards on ipc::shmem, verify we
+ // weren't fed an shmem we already had.
+ for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
+ if (NS_WARN_IF(aMem == GetGmpFreelist(aClass)[i])) {
+ // Safest to crash in this case; should never happen in normal
+ // operation.
+ MOZ_CRASH("Deallocating Shmem we already have in our cache!");
+ //return true;
+ }
+ }
+
// XXX This works; there are better pool algorithms. We need to avoid
// "falling off a cliff" with too low a number
if (GetGmpFreelist(aClass).Length() > 10) {
Dealloc(GetGmpFreelist(aClass)[0]);
GetGmpFreelist(aClass).RemoveElementAt(0);
// The allocation numbers will be fubar on the Child!
mData->mGmpAllocated[aClass]--;
}
--- a/content/media/gmp/GMPVideoDecoderParent.cpp
+++ b/content/media/gmp/GMPVideoDecoderParent.cpp
@@ -223,16 +223,20 @@ GMPVideoDecoderParent::ActorDestroy(Acto
bool
GMPVideoDecoderParent::RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame)
{
if (!mCallback) {
return false;
}
+ if (!GMPVideoi420FrameImpl::CheckFrameData(aDecodedFrame)) {
+ LOG(PR_LOG_ERROR, ("%s: Decoded frame corrupt, ignoring", __FUNCTION__));
+ return false;
+ }
auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost);
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->Decoded(f);
return true;
}
--- a/content/media/gmp/GMPVideoi420FrameImpl.cpp
+++ b/content/media/gmp/GMPVideoi420FrameImpl.cpp
@@ -58,16 +58,41 @@ GMPVideoi420FrameImpl::GetFrameFormat()
}
void
GMPVideoi420FrameImpl::Destroy()
{
delete this;
}
+/* static */ bool
+GMPVideoi420FrameImpl::CheckFrameData(const GMPVideoi420FrameData& aFrameData)
+{
+ // We may be passed the "wrong" shmem (one smaller than the actual size).
+ // This implies a bug or serious error on the child size. Ignore this frame if so.
+ // Note: Size() greater than expected is also an error, but with no negative consequences
+ int32_t half_width = (aFrameData.mWidth() + 1) / 2;
+ if ((aFrameData.mYPlane().mStride() <= 0) || (aFrameData.mYPlane().mSize() <= 0) ||
+ (aFrameData.mUPlane().mStride() <= 0) || (aFrameData.mUPlane().mSize() <= 0) ||
+ (aFrameData.mVPlane().mStride() <= 0) || (aFrameData.mVPlane().mSize() <= 0) ||
+ (aFrameData.mYPlane().mSize() > (int32_t) aFrameData.mYPlane().mBuffer().Size<uint8_t>()) ||
+ (aFrameData.mUPlane().mSize() > (int32_t) aFrameData.mUPlane().mBuffer().Size<uint8_t>()) ||
+ (aFrameData.mVPlane().mSize() > (int32_t) aFrameData.mVPlane().mBuffer().Size<uint8_t>()) ||
+ (aFrameData.mYPlane().mStride() < aFrameData.mWidth()) ||
+ (aFrameData.mUPlane().mStride() < half_width) ||
+ (aFrameData.mVPlane().mStride() < half_width) ||
+ (aFrameData.mYPlane().mSize() < aFrameData.mYPlane().mStride() * aFrameData.mHeight()) ||
+ (aFrameData.mUPlane().mSize() < aFrameData.mUPlane().mStride() * ((aFrameData.mHeight()+1)/2)) ||
+ (aFrameData.mVPlane().mSize() < aFrameData.mVPlane().mStride() * ((aFrameData.mHeight()+1)/2)))
+ {
+ return false;
+ }
+ return true;
+}
+
bool
GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
{
int32_t half_width = (aWidth + 1) / 2;
if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth ||
aStride_u < half_width ||
aStride_v < half_width) {
--- a/content/media/gmp/GMPVideoi420FrameImpl.h
+++ b/content/media/gmp/GMPVideoi420FrameImpl.h
@@ -19,16 +19,18 @@ class GMPVideoi420FrameData;
class GMPVideoi420FrameImpl : public GMPVideoi420Frame
{
friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoi420FrameImpl>;
public:
explicit GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost);
GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData, GMPVideoHostImpl* aHost);
virtual ~GMPVideoi420FrameImpl();
+ static bool CheckFrameData(const GMPVideoi420FrameData& aFrameData);
+
bool InitFrameData(GMPVideoi420FrameData& aFrameData);
const GMPPlaneImpl* GetPlane(GMPPlaneType aType) const;
GMPPlaneImpl* GetPlane(GMPPlaneType aType);
// GMPVideoFrame
virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
virtual void Destroy() MOZ_OVERRIDE;
--- a/content/media/webaudio/OscillatorNode.cpp
+++ b/content/media/webaudio/OscillatorNode.cpp
@@ -368,46 +368,54 @@ public:
void ComputeCustom(float* aOutput,
TrackTicks ticks,
uint32_t aStart,
uint32_t aEnd)
{
MOZ_ASSERT(mPeriodicWave, "No custom waveform data");
uint32_t periodicWaveSize = mPeriodicWave->periodicWaveSize();
+ // Mask to wrap wave data indices into the range [0,periodicWaveSize).
+ uint32_t indexMask = periodicWaveSize - 1;
+ MOZ_ASSERT(periodicWaveSize && (periodicWaveSize & indexMask) == 0,
+ "periodicWaveSize must be power of 2");
float* higherWaveData = nullptr;
float* lowerWaveData = nullptr;
float tableInterpolationFactor;
// Phase increment at frequency of 1 Hz.
// mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI).
float basePhaseIncrement =
static_cast<float>(periodicWaveSize) / mSource->SampleRate();
for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateParametersIfNeeded(ticks, i);
mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
lowerWaveData,
higherWaveData,
tableInterpolationFactor);
- mPhase = fmod(mPhase, periodicWaveSize);
// Bilinear interpolation between adjacent samples in each table.
- uint32_t j1 = floor(mPhase);
+ float floorPhase = floorf(mPhase);
+ uint32_t j1 = floorPhase;
+ j1 &= indexMask;
uint32_t j2 = j1 + 1;
- if (j2 >= periodicWaveSize) {
- j2 -= periodicWaveSize;
- }
- float sampleInterpolationFactor = mPhase - j1;
+ j2 &= indexMask;
+
+ float sampleInterpolationFactor = mPhase - floorPhase;
+
float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
sampleInterpolationFactor * lowerWaveData[j2];
float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
sampleInterpolationFactor * higherWaveData[j2];
aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
tableInterpolationFactor * higher;
- mPhase += basePhaseIncrement * mFinalFrequency;
+ // Calculate next phase position from wrapped value j1 to avoid loss of
+ // precision at large values.
+ mPhase =
+ j1 + sampleInterpolationFactor + basePhaseIncrement * mFinalFrequency;
}
}
void ComputeSilence(AudioChunk *aOutput)
{
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
}
--- a/content/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognition.cpp
@@ -703,18 +703,17 @@ SpeechRecognition::Start(const Optional<
MediaStreamConstraints constraints;
constraints.mAudio.SetAsBoolean() = true;
if (aStream.WasPassed()) {
StartRecording(&aStream.Value());
} else {
MediaManager* manager = MediaManager::Get();
- manager->GetUserMedia(false,
- GetOwner(),
+ manager->GetUserMedia(GetOwner(),
constraints,
new GetUserMediaSuccessCallback(this),
new GetUserMediaErrorCallback(this));
}
nsRefPtr<SpeechEvent> event = new SpeechEvent(this, EVENT_START);
NS_DispatchToMainThread(event);
}
--- a/content/svg/content/src/DOMSVGLength.cpp
+++ b/content/svg/content/src/DOMSVGLength.cpp
@@ -9,16 +9,17 @@
#include "SVGLength.h"
#include "SVGAnimatedLengthList.h"
#include "nsSVGElement.h"
#include "nsSVGLength2.h"
#include "nsIDOMSVGLength.h"
#include "nsError.h"
#include "nsMathUtils.h"
#include "mozilla/dom/SVGLengthBinding.h"
+#include "mozilla/FloatingPoint.h"
#include "nsSVGAttrTearoffTable.h"
// See the architecture comment in DOMSVGAnimatedLengthList.h.
namespace mozilla {
static nsSVGAttrTearoffTable<nsSVGLength2, DOMSVGLength>
sBaseSVGLengthTearOffTable,
@@ -223,17 +224,17 @@ DOMSVGLength::GetValue(ErrorResult& aRv)
return mVal->GetBaseValue(mSVGElement);
}
if (mIsAnimValItem && HasOwner()) {
Element()->FlushAnimations(); // May make HasOwner() == false
}
if (HasOwner()) {
float value = InternalItem().GetValueInUserUnits(Element(), Axis());
- if (!NS_finite(value)) {
+ if (!IsFinite(value)) {
aRv.Throw(NS_ERROR_FAILURE);
}
return value;
} else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
return mValue;
}
// else [SVGWG issue] Can't convert this length's value to user units
@@ -271,17 +272,17 @@ DOMSVGLength::SetValue(float aUserUnitVa
if (HasOwner()) {
if (InternalItem().GetValueInUserUnits(Element(), Axis()) ==
aUserUnitValue) {
return;
}
float uuPerUnit = InternalItem().GetUserUnitsPerUnit(Element(), Axis());
if (uuPerUnit > 0) {
float newValue = aUserUnitValue / uuPerUnit;
- if (NS_finite(newValue)) {
+ if (IsFinite(newValue)) {
AutoChangeLengthNotifier notifier(this);
InternalItem().SetValueAndUnit(newValue, InternalItem().GetUnit());
return;
}
}
} else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
mValue = aUserUnitValue;
@@ -290,17 +291,17 @@ DOMSVGLength::SetValue(float aUserUnitVa
// else [SVGWG issue] Can't convert user unit value to this length's unit
// ReportToConsole
aRv.Throw(NS_ERROR_FAILURE);
}
NS_IMETHODIMP
DOMSVGLength::SetValue(float aUserUnitValue)
{
- if (!NS_finite(aUserUnitValue)) {
+ if (!IsFinite(aUserUnitValue)) {
return NS_ERROR_ILLEGAL_VALUE;
}
ErrorResult rv;
SetValue(aUserUnitValue, rv);
return rv.ErrorCode();
}
@@ -350,17 +351,17 @@ DOMSVGLength::SetValueInSpecifiedUnits(f
return;
}
mValue = aValue;
}
NS_IMETHODIMP
DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
{
- if (!NS_finite(aValue)) {
+ if (!IsFinite(aValue)) {
return NS_ERROR_ILLEGAL_VALUE;
}
ErrorResult rv;
SetValueInSpecifiedUnits(aValue, rv);
return rv.ErrorCode();
}
@@ -455,17 +456,17 @@ DOMSVGLength::NewValueSpecifiedUnits(uin
}
mUnit = uint8_t(aUnit);
mValue = aValue;
}
NS_IMETHODIMP
DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue)
{
- if (!NS_finite(aValue)) {
+ if (!IsFinite(aValue)) {
return NS_ERROR_ILLEGAL_VALUE;
}
ErrorResult rv;
NewValueSpecifiedUnits(aUnit, aValue, rv);
return rv.ErrorCode();
}
@@ -487,25 +488,25 @@ DOMSVGLength::ConvertToSpecifiedUnits(ui
return;
}
if (HasOwner()) {
if (InternalItem().GetUnit() == aUnit) {
return;
}
float val = InternalItem().GetValueInSpecifiedUnit(
aUnit, Element(), Axis());
- if (NS_finite(val)) {
+ if (IsFinite(val)) {
AutoChangeLengthNotifier notifier(this);
InternalItem().SetValueAndUnit(val, aUnit);
return;
}
} else {
SVGLength len(mValue, mUnit);
float val = len.GetValueInSpecifiedUnit(aUnit, nullptr, 0);
- if (NS_finite(val)) {
+ if (IsFinite(val)) {
mValue = val;
mUnit = aUnit;
return;
}
}
// else [SVGWG issue] Can't convert unit
// ReportToConsole
aRv.Throw(NS_ERROR_FAILURE);
--- a/content/svg/content/src/DOMSVGPoint.h
+++ b/content/svg/content/src/DOMSVGPoint.h
@@ -8,16 +8,17 @@
#include "DOMSVGPointList.h"
#include "mozilla/gfx/2D.h"
#include "nsAutoPtr.h"
#include "nsDebug.h"
#include "nsISVGPoint.h"
#include "SVGPoint.h"
#include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
class nsSVGElement;
namespace mozilla {
namespace dom {
class SVGMatrix;
}
@@ -77,17 +78,17 @@ public:
mPt.mY = aY;
}
explicit DOMSVGPoint(const Point& aPt)
: nsISVGPoint()
{
mPt.mX = aPt.x;
mPt.mY = aPt.y;
- NS_ASSERTION(NS_finite(mPt.mX) && NS_finite(mPt.mX),
+ NS_ASSERTION(IsFinite(mPt.mX) && IsFinite(mPt.mX),
"DOMSVGPoint coords are not finite");
}
// WebIDL
virtual float X();
virtual void SetX(float aX, ErrorResult& rv);
virtual float Y();
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -20,16 +20,17 @@
#include "nsIFrame.h"
#include "nsIScriptError.h"
#include "nsLayoutUtils.h"
#include "SVGAnimationElement.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "nsContentUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
+#include "mozilla/FloatingPoint.h"
#include "nsStyleContext.h"
#include "nsSVGPathDataParser.h"
#include "SVGPathData.h"
#include "SVGPathElement.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
@@ -659,17 +660,17 @@ SVGContentUtils::ParseNumber(RangedPtr<c
{
RangedPtr<const char16_t> iter(aIter);
double value;
if (!::ParseNumber(iter, aEnd, value)) {
return false;
}
floatType floatValue = floatType(value);
- if (!NS_finite(floatValue)) {
+ if (!IsFinite(floatValue)) {
return false;
}
aValue = floatValue;
aIter = iter;
return true;
}
template bool
--- a/content/svg/content/src/SVGLength.cpp
+++ b/content/svg/content/src/SVGLength.cpp
@@ -119,27 +119,27 @@ SVGLength::GetValueInSpecifiedUnit(uint8
// succeed if aElement is non-null (although that's not sufficent to
// guarantee success).
float userUnitsPerCurrentUnit = GetUserUnitsPerUnit(aElement, aAxis);
float userUnitsPerNewUnit =
SVGLength(0.0f, aUnit).GetUserUnitsPerUnit(aElement, aAxis);
NS_ASSERTION(userUnitsPerCurrentUnit >= 0 ||
- !NS_finite(userUnitsPerCurrentUnit),
+ !IsFinite(userUnitsPerCurrentUnit),
"bad userUnitsPerCurrentUnit");
NS_ASSERTION(userUnitsPerNewUnit >= 0 ||
- !NS_finite(userUnitsPerNewUnit),
+ !IsFinite(userUnitsPerNewUnit),
"bad userUnitsPerNewUnit");
float value = mValue * userUnitsPerCurrentUnit / userUnitsPerNewUnit;
// userUnitsPerCurrentUnit could be infinity, or userUnitsPerNewUnit could
// be zero.
- if (NS_finite(value)) {
+ if (IsFinite(value)) {
return value;
}
return std::numeric_limits<float>::quiet_NaN();
}
#define INCHES_PER_MM_FLOAT float(0.0393700787)
#define INCHES_PER_CM_FLOAT float(0.393700787)
--- a/content/svg/content/src/SVGLength.h
+++ b/content/svg/content/src/SVGLength.h
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_SVGLENGTH_H__
#define MOZILLA_SVGLENGTH_H__
#include "nsDebug.h"
#include "nsIDOMSVGLength.h"
#include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
class nsSVGElement;
namespace mozilla {
/**
* This SVGLength class is currently used for SVGLength *list* attributes only.
* The class that is currently used for <length> attributes is nsSVGLength2.
@@ -134,17 +135,17 @@ public:
* the comments for GetUserUnitsPerInch and GetUserUnitsPerPercent).
*/
float GetUserUnitsPerUnit(const nsSVGElement *aElement, uint8_t aAxis) const;
private:
#ifdef DEBUG
bool IsValid() const {
- return NS_finite(mValue) && IsValidUnitType(mUnit);
+ return IsFinite(mValue) && IsValidUnitType(mUnit);
}
#endif
/**
* The conversion factor between user units (CSS px) and CSS inches is
* constant: 96 px per inch.
*/
static float GetUserUnitsPerInch()
--- a/content/svg/content/src/SVGLengthListSMILType.cpp
+++ b/content/svg/content/src/SVGLengthListSMILType.cpp
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SVGLengthListSMILType.h"
#include "nsSMILValue.h"
#include "SVGLengthList.h"
#include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
#include <math.h>
#include <algorithm>
namespace mozilla {
/*static*/ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
//----------------------------------------------------------------------
@@ -211,17 +212,17 @@ SVGLengthListSMILType::ComputeDistance(c
total += f * f;
}
for (; i < to.Length(); ++i) {
double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
total += t * t;
}
float distance = sqrt(total);
- if (!NS_finite(distance)) {
+ if (!IsFinite(distance)) {
return NS_ERROR_FAILURE;
}
aDistance = distance;
return NS_OK;
}
nsresult
SVGLengthListSMILType::Interpolate(const nsSMILValue& aStartVal,
--- a/content/svg/content/src/SVGMarkerElement.cpp
+++ b/content/svg/content/src/SVGMarkerElement.cpp
@@ -9,16 +9,17 @@
#include "nsCOMPtr.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "nsError.h"
#include "mozilla/dom/SVGAngle.h"
#include "mozilla/dom/SVGMarkerElement.h"
#include "mozilla/dom/SVGMarkerElementBinding.h"
#include "mozilla/Preferences.h"
#include "mozilla/gfx/Matrix.h"
+#include "mozilla/FloatingPoint.h"
#include "SVGContentUtils.h"
using namespace mozilla::gfx;
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Marker)
namespace mozilla {
namespace dom {
@@ -168,17 +169,17 @@ void SVGMarkerElement::SetOrientToAuto()
SetAttr(kNameSpaceID_None, nsGkAtoms::orient, nullptr,
NS_LITERAL_STRING("auto"), true);
}
void
SVGMarkerElement::SetOrientToAngle(SVGAngle& angle, ErrorResult& rv)
{
float f = angle.Value();
- if (!NS_finite(f)) {
+ if (!IsFinite(f)) {
rv.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
return;
}
mAngleAttributes[ORIENT].SetBaseValue(f, this, true);
}
//----------------------------------------------------------------------
// nsIContent methods
--- a/content/svg/content/src/SVGMatrix.cpp
+++ b/content/svg/content/src/SVGMatrix.cpp
@@ -3,16 +3,17 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGMatrix.h"
#include "nsError.h"
#include <math.h>
#include "mozilla/dom/SVGMatrixBinding.h"
+#include "mozilla/FloatingPoint.h"
const double radPerDegree = 2.0 * M_PI / 360.0;
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix, mTransform)
@@ -189,34 +190,34 @@ SVGMatrix::FlipY()
new SVGMatrix(gfxMatrix(mx._11, mx._12, -mx._21, -mx._22, mx._31, mx._32));
return matrix.forget();
}
already_AddRefed<SVGMatrix>
SVGMatrix::SkewX(float angle, ErrorResult& rv)
{
double ta = tan( angle*radPerDegree );
- if (!NS_finite(ta)) {
+ if (!IsFinite(ta)) {
rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
const gfxMatrix& mx = GetMatrix();
gfxMatrix skewMx(mx._11, mx._12,
(float) (mx._21 + mx._11*ta), (float) (mx._22 + mx._12*ta),
mx._31, mx._32);
nsRefPtr<SVGMatrix> matrix = new SVGMatrix(skewMx);
return matrix.forget();
}
already_AddRefed<SVGMatrix>
SVGMatrix::SkewY(float angle, ErrorResult& rv)
{
double ta = tan( angle*radPerDegree );
- if (!NS_finite(ta)) {
+ if (!IsFinite(ta)) {
rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
const gfxMatrix& mx = GetMatrix();
gfxMatrix skewMx((float) (mx._11 + mx._21*ta), (float) (mx._12 + mx._22*ta),
mx._21, mx._22,
mx._31, mx._32);
--- a/content/svg/content/src/SVGNumberListSMILType.cpp
+++ b/content/svg/content/src/SVGNumberListSMILType.cpp
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SVGNumberListSMILType.h"
#include "nsSMILValue.h"
#include "SVGNumberList.h"
#include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
#include <math.h>
/* The "identity" number list for a given number list attribute (the effective
* number list that is used if an attribute value is not specified) varies
* widely for different number list attributes, and can depend on the value of
* other attributes on the same element:
*
* http://www.w3.org/TR/SVG11/filters.html#feColorMatrixValuesAttribute
@@ -150,17 +151,17 @@ SVGNumberListSMILType::ComputeDistance(c
double total = 0.0;
for (uint32_t i = 0; i < to.Length(); ++i) {
double delta = to[i] - from[i];
total += delta * delta;
}
double distance = sqrt(total);
- if (!NS_finite(distance)) {
+ if (!IsFinite(distance)) {
return NS_ERROR_FAILURE;
}
aDistance = distance;
return NS_OK;
}
nsresult
--- a/content/svg/content/src/SVGPoint.h
+++ b/content/svg/content/src/SVGPoint.h
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_SVGPOINT_H__
#define MOZILLA_SVGPOINT_H__
#include "nsDebug.h"
#include "gfxPoint.h"
#include "mozilla/gfx/Point.h"
+#include "mozilla/FloatingPoint.h"
namespace mozilla {
/**
* This class is currently used for point list attributes.
*
* The DOM wrapper class for this class is DOMSVGPoint.
*/
@@ -61,17 +62,17 @@ public:
}
operator Point() const {
return Point(mX, mY);
}
#ifdef DEBUG
bool IsValid() const {
- return NS_finite(mX) && NS_finite(mY);
+ return IsFinite(mX) && IsFinite(mY);
}
#endif
void SetX(float aX)
{ mX = aX; }
void SetY(float aY)
{ mY = aY; }
float GetX() const
--- a/content/svg/content/src/SVGPointListSMILType.cpp
+++ b/content/svg/content/src/SVGPointListSMILType.cpp
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SVGPointListSMILType.h"
#include "nsSMILValue.h"
#include "SVGPointList.h"
#include "nsMathUtils.h"
+#include "mozilla/FloatingPoint.h"
#include <math.h>
namespace mozilla {
/*static*/ SVGPointListSMILType SVGPointListSMILType::sSingleton;
//----------------------------------------------------------------------
// nsISMILType implementation
@@ -130,17 +131,17 @@ SVGPointListSMILType::ComputeDistance(co
double total = 0.0;
for (uint32_t i = 0; i < to.Length(); ++i) {
double dx = to[i].mX - from[i].mX;
double dy = to[i].mY - from[i].mY;
total += dx * dx + dy * dy;
}
double distance = sqrt(total);
- if (!NS_finite(distance)) {
+ if (!IsFinite(distance)) {
return NS_ERROR_FAILURE;
}
aDistance = distance;
return NS_OK;
}
nsresult
--- a/content/svg/content/src/SVGTransform.cpp
+++ b/content/svg/content/src/SVGTransform.cpp
@@ -8,16 +8,17 @@
#include "mozilla/dom/SVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGTransformBinding.h"
#include "nsError.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/DebugOnly.h"
+#include "mozilla/FloatingPoint.h"
namespace {
const double kRadPerDegree = 2.0 * M_PI / 360.0;
}
namespace mozilla {
namespace dom {
@@ -258,17 +259,17 @@ SVGTransform::SetSkewX(float angle, Erro
return;
}
if (Transform().Type() == SVG_TRANSFORM_SKEWX &&
Transform().Angle() == angle) {
return;
}
- if (!NS_finite(tan(angle * kRadPerDegree))) {
+ if (!IsFinite(tan(angle * kRadPerDegree))) {
rv.Throw(NS_ERROR_RANGE_ERR);
return;
}
AutoChangeTransformNotifier notifier(this);
DebugOnly<nsresult> result = Transform().SetSkewX(angle);
MOZ_ASSERT(NS_SUCCEEDED(result), "SetSkewX unexpectedly failed");
}
@@ -281,17 +282,17 @@ SVGTransform::SetSkewY(float angle, Erro
return;
}
if (Transform().Type() == SVG_TRANSFORM_SKEWY &&
Transform().Angle() == angle) {
return;
}
- if (!NS_finite(tan(angle * kRadPerDegree))) {
+ if (!IsFinite(tan(angle * kRadPerDegree))) {
rv.Throw(NS_ERROR_RANGE_ERR);
return;
}
AutoChangeTransformNotifier notifier(this);
DebugOnly<nsresult> result = Transform().SetSkewY(angle);
MOZ_ASSERT(NS_SUCCEEDED(result), "SetSkewY unexpectedly failed");
}
--- a/content/svg/content/src/nsSVGNumber2.h
+++ b/content/svg/content/src/nsSVGNumber2.h
@@ -8,16 +8,17 @@
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsError.h"
#include "nsISMILAttr.h"
#include "nsMathUtils.h"
#include "nsSVGElement.h"
#include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
#include "mozilla/dom/SVGAnimatedNumber.h"
class nsSMILValue;
namespace mozilla {
namespace dom {
class SVGAnimationElement;
}
@@ -78,17 +79,17 @@ public:
nsSVGNumber2* mVal; // kept alive because it belongs to content
virtual float BaseVal() MOZ_OVERRIDE
{
return mVal->GetBaseValue();
}
virtual void SetBaseVal(float aValue) MOZ_OVERRIDE
{
- MOZ_ASSERT(NS_finite(aValue));
+ MOZ_ASSERT(mozilla::IsFinite(aValue));
mVal->SetBaseValue(aValue, mSVGElement);
}
// Script may have modified animation parameters or timeline -- DOM getters
// need to flush any resample requests to reflect these modifications.
virtual float AnimVal() MOZ_OVERRIDE
{
mSVGElement->FlushAnimations();
--- a/content/svg/content/src/nsSVGNumberPair.h
+++ b/content/svg/content/src/nsSVGNumberPair.h
@@ -9,16 +9,18 @@
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsError.h"
#include "nsISMILAttr.h"
#include "nsMathUtils.h"
#include "nsSVGElement.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/SVGAnimatedNumber.h"
+#include "mozilla/FloatingPoint.h"
+
class nsSMILValue;
namespace mozilla {
namespace dom {
class SVGAnimationElement;
}
}
@@ -88,17 +90,17 @@ public:
PairIndex mIndex; // are we the first or second number
virtual float BaseVal() MOZ_OVERRIDE
{
return mVal->GetBaseValue(mIndex);
}
virtual void SetBaseVal(float aValue) MOZ_OVERRIDE
{
- MOZ_ASSERT(NS_finite(aValue));
+ MOZ_ASSERT(mozilla::IsFinite(aValue));
mVal->SetBaseValue(aValue, mIndex, mSVGElement);
}
// Script may have modified animation parameters or timeline -- DOM getters
// need to flush any resample requests to reflect these modifications.
virtual float AnimVal() MOZ_OVERRIDE
{
mSVGElement->FlushAnimations();
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -53,17 +53,17 @@ ComputedTimingFunction::GetValue(double
}
// In the Web Animations model, the time fraction can be outside the range
// [0.0, 1.0] but it shouldn't be Infinity.
const double ComputedTiming::kNullTimeFraction = PositiveInfinity<double>();
namespace dom {
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mDocument)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mDocument, mTarget)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Animation, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Animation, Release)
JSObject*
Animation::WrapObject(JSContext* aCx)
{
return AnimationBinding::Wrap(aCx, this);
@@ -223,16 +223,39 @@ Animation::ActiveDuration(const Animatio
? zeroDuration
: StickyTimeDuration::Forever();
}
return StickyTimeDuration(
aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount));
}
bool
+Animation::IsCurrent() const
+{
+ if (IsFinishedTransition()) {
+ return false;
+ }
+
+ ComputedTiming computedTiming = GetComputedTiming();
+ return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
+ computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
+}
+
+bool
+Animation::IsInEffect() const
+{
+ if (IsFinishedTransition()) {
+ return false;
+ }
+
+ ComputedTiming computedTiming = GetComputedTiming();
+ return computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction;
+}
+
+bool
Animation::HasAnimationOfProperty(nsCSSProperty aProperty) const
{
for (size_t propIdx = 0, propEnd = mProperties.Length();
propIdx != propEnd; ++propIdx) {
if (aProperty == mProperties[propIdx].mProperty) {
return true;
}
}
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -3,22 +3,24 @@
* 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_Animation_h
#define mozilla_dom_Animation_h
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
+#include "nsCSSPseudoElements.h"
#include "nsIDocument.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
#include "mozilla/StickyTimeDuration.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimeStamp.h"
+#include "mozilla/dom/Element.h"
#include "mozilla/dom/Nullable.h"
#include "nsSMILKeySpline.h"
#include "nsStyleStruct.h" // for nsTimingFunction
struct JSContext;
namespace mozilla {
@@ -123,24 +125,29 @@ struct ElementPropertyTransition;
namespace dom {
class AnimationEffect;
class Animation : public nsWrapperCache
{
public:
Animation(nsIDocument* aDocument,
+ Element* aTarget,
+ nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming,
const nsSubstring& aName)
: mDocument(aDocument)
+ , mTarget(aTarget)
, mTiming(aTiming)
, mName(aName)
, mIsFinishedTransition(false)
, mLastNotification(LAST_NOTIFICATION_NONE)
+ , mPseudoType(aPseudoType)
{
+ MOZ_ASSERT(aTarget, "null animation target is not yet supported");
SetIsDOMBinding();
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
nsIDocument* GetParentObject() const { return mDocument; }
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
@@ -152,16 +159,25 @@ public:
virtual const ElementPropertyTransition* AsTransition() const {
return nullptr;
}
// Animation interface
// This currently returns a new object each time when used from C++ but is
// cached when used from JS.
already_AddRefed<AnimationEffect> GetEffect();
+ Element* GetTarget() const {
+ // Currently we only implement Element.getAnimationPlayers() which only
+ // returns animations targetting Elements so we should this should never
+ // be called for an animation that targets a pseudo-element.
+ MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
+ "Requesting the target of an Animation that targets a"
+ " pseudo-element is not yet supported.");
+ return mTarget;
+ }
void SetParentTime(Nullable<TimeDuration> aParentTime);
const AnimationTiming& Timing() const {
return mTiming;
}
AnimationTiming& Timing() {
return mTiming;
@@ -219,25 +235,18 @@ public:
}
void SetIsFinishedTransition() {
MOZ_ASSERT(AsTransition(),
"Calling SetIsFinishedTransition but it's not a transition");
mIsFinishedTransition = true;
}
- bool IsCurrent() const {
- if (IsFinishedTransition()) {
- return false;
- }
-
- ComputedTiming computedTiming = GetComputedTiming();
- return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
- computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
- }
+ bool IsCurrent() const;
+ bool IsInEffect() const;
enum {
LAST_NOTIFICATION_NONE = uint64_t(-1),
LAST_NOTIFICATION_END = uint64_t(-2)
};
uint64_t LastNotification() const { return mLastNotification; }
void SetLastNotification(uint64_t aLastNotification) {
mLastNotification = aLastNotification;
@@ -251,27 +260,29 @@ public:
return mProperties;
}
protected:
virtual ~Animation() { }
// We use a document for a parent object since the other likely candidate,
// the target element, can be empty.
- nsRefPtr<nsIDocument> mDocument;
+ nsCOMPtr<nsIDocument> mDocument;
+ nsCOMPtr<Element> mTarget;
Nullable<TimeDuration> mParentTime;
AnimationTiming mTiming;
nsString mName;
// A flag to mark transitions that have finished and are due to
// be removed on the next throttle-able cycle.
bool mIsFinishedTransition;
// One of the LAST_NOTIFICATION_* constants, or an integer for the iteration
// whose start we last notified on.
uint64_t mLastNotification;
+ nsCSSPseudoElements::Type mPseudoType;
InfallibleTArray<AnimationProperty> mProperties;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Animation_h
--- a/dom/animation/AnimationPlayer.cpp
+++ b/dom/animation/AnimationPlayer.cpp
@@ -59,22 +59,16 @@ AnimationPlayer::IsRunning() const
if (IsPaused() || !GetSource() || GetSource()->IsFinishedTransition()) {
return false;
}
ComputedTiming computedTiming = GetSource()->GetComputedTiming();
return computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
}
-bool
-AnimationPlayer::IsCurrent() const
-{
- return GetSource() && GetSource()->IsCurrent();
-}
-
Nullable<TimeDuration>
AnimationPlayer::GetCurrentTimeDuration() const
{
Nullable<TimeDuration> result;
if (!mHoldTime.IsNull()) {
result = mHoldTime;
} else {
Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTimeDuration();
--- a/dom/animation/AnimationPlayer.h
+++ b/dom/animation/AnimationPlayer.h
@@ -59,17 +59,23 @@ public:
return mSource ? mSource->Name() : EmptyString();
}
bool IsPaused() const {
return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
}
bool IsRunning() const;
- bool IsCurrent() const;
+
+ bool HasCurrentSource() const {
+ return GetSource() && GetSource()->IsCurrent();
+ }
+ bool HasInEffectSource() const {
+ return GetSource() && GetSource()->IsInEffect();
+ }
// Return the duration since the start time of the player, taking into
// account the pause state. May be negative or null.
Nullable<TimeDuration> GetCurrentTimeDuration() const;
// The beginning of the delay period.
Nullable<TimeDuration> mStartTime;
Nullable<TimeDuration> mHoldTime;
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -37,17 +37,16 @@ var div = document.querySelector('div.ta
const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
SpecialPowers.getBoolPref(OMTAPrefKey);
// FIXME: When we implement Element.animate, use that here instead of CSS
// so that we remove any dependency on the CSS mapping.
div.style.animation = 'anim 100s';
-window.getComputedStyle(div).animationName;
var player = div.getAnimationPlayers()[0];
// Wait so that animation can be set up.
// FIXME: When we implement the AnimationPlayer.ready promise we should wait
// on that here.
window.requestAnimationFrame(function() {
is(player.isRunningOnCompositor, omtaEnabled,
'AnimationPlayer reports that it is running on the compositor'
--- a/dom/animation/test/css-integration/test_animation-effect-name.html
+++ b/dom/animation/test/css-integration/test_animation-effect-name.html
@@ -15,51 +15,44 @@ function addDiv() {
var div = document.createElement('div');
document.body.appendChild(div);
return div;
}
test(function() {
var div = addDiv();
div.style.animation = 'xyz 100s';
- window.getComputedStyle(div).animationName;
-
assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
'Animation effect name matches keyframes rule name');
div.remove();
}, 'Effect name makes keyframe rule');
test(function() {
var div = addDiv();
div.style.animation = 'x\\yz 100s';
- dump(window.getComputedStyle(div).animationName + "\n");
-
assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
'Escaped animation effect name matches keyframes rule name');
div.remove();
}, 'Escaped animation name');
test(function() {
var div = addDiv();
div.style.animation = 'x\\79 z 100s';
- window.getComputedStyle(div).animationName;
-
assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
'Hex-escaped animation effect name matches keyframes rule'
+ ' name');
div.remove();
}, 'Animation name with hex-escape');
test(function() {
var div = addDiv();
// Add a transition
div.style.left = '0px';
window.getComputedStyle(div).transitionProperty;
div.style.transition = 'all 100s';
div.style.left = '100px';
- window.getComputedStyle(div).left;
assert_equals(div.getAnimationPlayers()[0].source.effect.name, '',
'Animation effects for transitions have an empty name');
div.remove();
}, 'Effect name for transitions');
</script>
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/css-integration/test_animation-target.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<style>
+@keyframes anim { }
+</style>
+<script>
+'use strict';
+
+function addDiv() {
+ var div = document.createElement('div');
+ document.body.appendChild(div);
+ return div;
+}
+
+test(function() {
+ var div = addDiv();
+ div.style.animation = 'anim 100s';
+ var players = div.getAnimationPlayers();
+ assert_equals(players[0].source.target, div,
+ 'Animation.target is the animatable div');
+ div.remove();
+}, 'Returned CSS animations have the correct Animation.target');
+
+test(function() {
+ var div = addDiv();
+
+ div.style.left = '0px';
+ window.getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ var players = div.getAnimationPlayers();
+ assert_equals(players[0].source.target, div,
+ 'Animation.target is the animatable div');
+ div.remove();
+}, 'Returned CSS transitions have the correct Animation.target');
+
+</script>
--- a/dom/animation/test/css-integration/test_animations-dynamic-changes.html
+++ b/dom/animation/test/css-integration/test_animations-dynamic-changes.html
@@ -16,27 +16,25 @@ function addDiv() {
var div = document.createElement('div');
document.body.appendChild(div);
return div;
}
async_test(function(t) {
var div = addDiv();
div.style.animation = 'anim1 100s';
- window.getComputedStyle(div).animationName;
var originalPlayer = div.getAnimationPlayers()[0];
var originalStartTime = originalPlayer.startTime;
var originalCurrentTime = originalPlayer.currentTime;
// Wait a moment so we can confirm the startTime doesn't change (and doesn't
// simply reflect the current time).
window.requestAnimationFrame(t.step_func(function() {
div.style.animationDuration = '200s';
- window.getComputedStyle(div).animationDuration;
var player = div.getAnimationPlayers()[0];
assert_equals(player, originalPlayer,
'The same AnimationPlayer is returned after updating'
+ ' animation duration');
assert_equals(player.startTime, originalStartTime,
'AnimationPlayers returned by getAnimationPlayers preserve'
+ ' their startTime even when they are updated');
// Sanity check
@@ -46,49 +44,45 @@ async_test(function(t) {
div.remove();
t.done();
}));
}, 'AnimationPlayers preserve their startTime when changed');
test(function() {
var div = addDiv();
div.style.animation = 'anim1 100s, anim1 100s';
- window.getComputedStyle(div).animationName;
// Store original state
var players = div.getAnimationPlayers();
var player1 = players[0];
var player2 = players[1];
// Update first in list
div.style.animationDuration = '200s, 100s';
- window.getComputedStyle(div).animationDuration;
players = div.getAnimationPlayers();
assert_equals(players[0], player1,
'First player is in same position after update');
assert_equals(players[1], player2,
'Second player is in same position after update');
}, 'Updated AnimationPlayers maintain their order in the list');
async_test(function(t) {
var div = addDiv();
div.style.animation = 'anim1 200s, anim1 100s';
- window.getComputedStyle(div).animationName;
// Store original state
var players = div.getAnimationPlayers();
var player1 = players[0];
var player2 = players[1];
// Wait before continuing so we can compare start times
window.requestAnimationFrame(t.step_func(function() {
// Swap duration of first and second in list and prepend animation at the
// same time
div.style.animation = 'anim1 100s, anim1 100s, anim1 200s';
- window.getComputedStyle(div).animationName;
players = div.getAnimationPlayers();
assert_true(players[0] !== player1 && players[0] !== player2,
'New player is prepended to start of list');
assert_equals(players[1], player1,
'First player is in second position after update');
assert_equals(players[2], player2,
'Second player is in third position after update');
assert_equals(players[1].startTime, players[2].startTime,
@@ -98,53 +92,47 @@ async_test(function(t) {
div.remove();
t.done();
}));
}, 'Only the startTimes of existing animations are preserved');
async_test(function(t) {
var div = addDiv();
div.style.animation = 'anim1 100s, anim1 100s';
- window.getComputedStyle(div).animationName;
-
var secondPlayer = div.getAnimationPlayers()[1];
// Wait before continuing so we can compare start times
window.requestAnimationFrame(t.step_func(function() {
// Trim list of animations
div.style.animationName = 'anim1';
- window.getComputedStyle(div).animationName;
var players = div.getAnimationPlayers();
assert_equals(players.length, 1, 'List of players was trimmed');
assert_equals(players[0], secondPlayer,
'Remaining player is the second one in the list');
assert_true(players[0].startTime < players[0].timeline.currentTime,
'Remaining player preserves startTime');
div.remove();
t.done();
}));
}, 'Animations are removed from the start of the list while preserving'
+ ' the state of existing players');
async_test(function(t) {
var div = addDiv();
div.style.animation = 'anim1 100s';
- window.getComputedStyle(div).animationName;
var firstAddedPlayer = div.getAnimationPlayers()[0];
// Wait and add second player
window.requestAnimationFrame(t.step_func(function() {
div.style.animation = 'anim1 100s, anim1 100s';
- window.getComputedStyle(div).animationName;
var secondAddedPlayer = div.getAnimationPlayers()[0];
// Wait again and add another player
window.requestAnimationFrame(t.step_func(function() {
div.style.animation = 'anim1 100s, anim2 100s, anim1 100s';
- window.getComputedStyle(div).animationName;
var players = div.getAnimationPlayers();
assert_not_equals(firstAddedPlayer, secondAddedPlayer,
'New players are added to start of the list');
assert_equals(players[0], secondAddedPlayer,
'Second player remains in same position after'
+ ' interleaving');
assert_equals(players[2], firstAddedPlayer,
'First player remains in same position after'
--- a/dom/animation/test/css-integration/test_element-get-animation-players.html
+++ b/dom/animation/test/css-integration/test_element-get-animation-players.html
@@ -32,31 +32,29 @@ test(function() {
div.remove();
}, 'getAnimationPlayers for non-animated content');
async_test(function(t) {
var div = addDiv();
// Add an animation
div.style.animation = 'anim1 100s';
- window.getComputedStyle(div).animationName;
var players = div.getAnimationPlayers();
assert_equals(players.length, 1,
'getAnimationPlayers returns a player running CSS Animations');
var startTime = players[0].startTime;
assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
'CSS animation has a sensible start time');
// Wait a moment then add a second animation.
//
// We wait for the next frame so that we can test that the start times of
// the animations differ.
window.requestAnimationFrame(t.step_func(function() {
div.style.animation = 'anim1 100s, anim2 100s';
- window.getComputedStyle(div).animationName;
players = div.getAnimationPlayers();
assert_equals(players.length, 2,
'getAnimationPlayers returns one player for each value of'
+ ' animation-name');
assert_true(players[0].startTime < players[1].startTime,
'Additional players for CSS animations start after the original'
+ ' animation and appear later in the list');
div.remove();
@@ -64,48 +62,46 @@ async_test(function(t) {
}));
}, 'getAnimationPlayers for CSS Animations');
test(function() {
var div = addDiv();
// Add an animation that targets multiple properties
div.style.animation = 'multiPropAnim 100s';
- window.getComputedStyle(div).animationName;
assert_equals(div.getAnimationPlayers().length, 1,
'getAnimationPlayers returns only one player for a CSS Animation'
+ ' that targets multiple properties');
div.remove();
}, 'getAnimationPlayers for multi-property animations');
async_test(function(t) {
var div = addDiv();
// Add a couple of transitions
div.style.left = '0px';
div.style.top = '0px';
window.getComputedStyle(div).transitionProperty;
+
div.style.transition = 'all 100s';
div.style.left = '100px';
div.style.top = '100px';
- window.getComputedStyle(div).left;
var players = div.getAnimationPlayers();
assert_equals(players.length, 2,
'getAnimationPlayers() returns one player per transitioning property');
var startTime = players[0].startTime;
assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
'CSS transitions have sensible start times');
assert_equals(players[0].startTime, players[1].startTime,
'CSS transitions started together have the same start time');
// Wait a moment then add a third transition
window.requestAnimationFrame(t.step_func(function() {
div.style.backgroundColor = 'green';
- window.getComputedStyle(div).backgroundColor;
players = div.getAnimationPlayers();
assert_equals(players.length, 3,
'getAnimationPlayers returns players for all running CSS Transitions');
assert_true(players[1].startTime < players[2].startTime,
'Player for additional CSS transition starts after the original'
+ ' transitions and appears later in the list');
div.remove();
t.done();
@@ -119,17 +115,16 @@ async_test(function(t) {
div.style.backgroundColor = 'red';
div.style.animation = 'anim1 100s';
window.getComputedStyle(div).backgroundColor;
// Wait a moment then add a transition
window.requestAnimationFrame(t.step_func(function() {
div.style.transition = 'all 100s';
div.style.backgroundColor = 'green';
- window.getComputedStyle(div).backgroundColor;
var players = div.getAnimationPlayers();
assert_equals(players.length, 2,
'getAnimationPlayers returns players for both animations and '
+ ' transitions that run simultaneously');
assert_true(players[0].startTime > players[1].startTime,
'players for transitions appear before animations even if they '
+ ' start later');
@@ -147,205 +142,200 @@ async_test(function(t) {
'getAnimationPlayers does not return players for finished '
+ ' (and non-forwards-filling) CSS Animations');
div.remove();
t.done();
}));
// Add a very short animation
div.style.animation = 'anim1 0.01s';
- window.getComputedStyle(div).animationName;
}, 'getAnimationPlayers for CSS Animations that have finished');
async_test(function(t) {
var div = addDiv();
// Set up event listener
+ div.addEventListener('animationend', t.step_func(function() {
+ assert_equals(div.getAnimationPlayers().length, 1,
+ 'getAnimationPlayers returns players for CSS Animations that have'
+ + ' finished but are filling forwards');
+ div.remove();
+ t.done();
+ }));
+
+ // Add a very short animation
+ div.style.animation = 'anim1 0.01s forwards';
+}, 'getAnimationPlayers for CSS Animations that have finished but are'
+ + ' forwards filling');
+
+async_test(function(t) {
+ var div = addDiv();
+
+ // Set up event listener
div.addEventListener('transitionend', t.step_func(function() {
assert_equals(div.getAnimationPlayers().length, 0,
'getAnimationPlayers does not return finished CSS Transitions');
div.remove();
t.done();
}));
// Add a very short transition
div.style.left = '0px';
window.getComputedStyle(div).left;
+
div.style.transition = 'all 0.01s';
div.style.left = '100px';
window.getComputedStyle(div).left;
}, 'getAnimationPlayers for CSS Transitions that have finished');
test(function() {
var div = addDiv();
div.style.animation = 'none 100s';
- window.getComputedStyle(div).animationName;
var players = div.getAnimationPlayers();
assert_equals(players.length, 0,
'getAnimationPlayers returns an empty sequence for an element'
+ ' with animation-name: none');
div.style.animation = 'none 100s, anim1 100s';
- window.getComputedStyle(div).animationName;
players = div.getAnimationPlayers();
assert_equals(players.length, 1,
'getAnimationPlayers returns players only for those CSS Animations whose'
+ ' animation-name is not none');
div.remove();
}, 'getAnimationPlayers for CSS Animations with animation-name: none');
test(function() {
var div = addDiv();
div.style.animation = 'missing 100s';
- window.getComputedStyle(div).animationName;
-
var players = div.getAnimationPlayers();
assert_equals(players.length, 0,
'getAnimationPlayers returns an empty sequence for an element'
+ ' with animation-name: missing');
div.style.animation = 'anim1 100s, missing 100s';
- window.getComputedStyle(div).animationName;
players = div.getAnimationPlayers();
assert_equals(players.length, 1,
'getAnimationPlayers returns players only for those CSS Animations whose'
+ ' animation-name is found');
div.remove();
}, 'getAnimationPlayers for CSS Animations with animation-name: missing');
async_test(function(t) {
var div = addDiv();
div.style.animation = 'anim1 100s, notyet 100s';
- window.getComputedStyle(div).animationName;
-
var players = div.getAnimationPlayers();
assert_equals(players.length, 1,
'getAnimationPlayers initally only returns players for CSS Animations whose'
+ ' animation-name is found');
window.requestAnimationFrame(t.step_func(function() {
var keyframes = '@keyframes notyet { to { left: 100px; } }';
document.styleSheets[0].insertRule(keyframes, 0);
- window.getComputedStyle(div).animationName;
-
players = div.getAnimationPlayers();
assert_equals(players.length, 2,
'getAnimationPlayers includes player when @keyframes rule is added'
+ ' later');
assert_true(players[0].startTime < players[1].startTime,
'Newly added player has a later start time');
document.styleSheets[0].deleteRule(0);
div.remove();
t.done();
}));
}, 'getAnimationPlayers for CSS Animations where the @keyframes rule is added'
+ ' later');
test(function() {
var div = addDiv();
div.style.animation = 'anim1 100s, anim1 100s';
- window.getComputedStyle(div).animationName;
-
assert_equals(div.getAnimationPlayers().length, 2,
'getAnimationPlayers returns one player for each CSS animation-name'
+ ' even if the names are duplicated');
div.remove();
}, 'getAnimationPlayers for CSS Animations with duplicated animation-name');
test(function() {
var div = addDiv();
div.style.animation = 'empty 100s';
- window.getComputedStyle(div).animationName;
-
assert_equals(div.getAnimationPlayers().length, 1,
'getAnimationPlayers returns players for CSS animations with an'
+ ' empty keyframes rule');
div.remove();
}, 'getAnimationPlayers for CSS Animations with empty keyframes rule');
test(function() {
var div = addDiv();
div.style.animation = 'anim1 100s 100s';
- window.getComputedStyle(div).animationName;
-
var players = div.getAnimationPlayers();
assert_equals(players.length, 1,
'getAnimationPlayers returns animations for CSS animations whose'
+ ' delay makes them start later');
assert_true(players[0].startTime <= document.timeline.currentTime,
'For CSS Animations in delay phase, the start time of the player is'
+ ' not in the future');
div.remove();
}, 'getAnimationPlayers for CSS animations in delay phase');
test(function() {
var div = addDiv();
div.style.animation = 'anim1 0s 100s';
- window.getComputedStyle(div).animationName;
-
assert_equals(div.getAnimationPlayers().length, 1,
'getAnimationPlayers returns animations for CSS animations whose'
+ ' duration is zero');
div.remove();
}, 'getAnimationPlayers for zero-duration CSS Animations');
test(function() {
var div = addDiv();
// Try to transition non-animatable property animation-duration
div.style.animationDuration = '10s';
window.getComputedStyle(div).animationDuration;
+
div.style.transition = 'all 100s';
div.style.animationDuration = '100s';
- window.getComputedStyle(div).left;
assert_equals(div.getAnimationPlayers().length, 0,
'getAnimationPlayers returns an empty sequence for a transition'
+ ' of a non-animatable property');
div.remove();
}, 'getAnimationPlayers for transition on non-animatable property');
test(function() {
var div = addDiv();
div.style.setProperty('-vendor-unsupported', '0px', '');
window.getComputedStyle(div).transitionProperty;
div.style.transition = 'all 100s';
div.style.setProperty('-vendor-unsupported', '100px', '');
- window.getComputedStyle(div).getPropertyValue('-vendor-unsupported');
assert_equals(div.getAnimationPlayers().length, 0,
'getAnimationPlayers returns an empty sequence for a transition'
+ ' of an unsupported property');
div.remove();
}, 'getAnimationPlayers for transition on unsupported property');
test(function() {
var div = addDiv();
div.style.animation = 'anim1 100s';
- window.getComputedStyle(div).animationName;
-
var originalPlayer = div.getAnimationPlayers()[0];
// Update pause state (an AnimationPlayer change)
div.style.animationPlayState = 'paused';
- window.getComputedStyle(div).animationPlayState;
var pausedPlayer = div.getAnimationPlayers()[0];
// FIXME: Check pausedPlayer.playState has changed once the API is available
// (bug 1037321)
assert_equals(originalPlayer, pausedPlayer,
'getAnimationPlayers returns the same objects even when their'
+ ' play state changes');
// Update duration (an Animation change)
div.style.animationDuration = '200s';
- window.getComputedStyle(div).animationDuration
var extendedPlayer = div.getAnimationPlayers()[0];
// FIXME: Check extendedPlayer.source.timing.duration has changed once the
// API is available
assert_equals(originalPlayer, extendedPlayer,
'getAnimationPlayers returns the same objects even when their'
+ ' duration changes');
div.remove();
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,6 +1,7 @@
[animation-timeline/test_animation-timeline.html]
skip-if = buildapp == 'mulet'
[css-integration/test_element-get-animation-players.html]
skip-if = buildapp == 'mulet'
[css-integration/test_animations-dynamic-changes.html]
[css-integration/test_animation-effect-name.html]
+[css-integration/test_animation-target.html]
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -627,21 +627,28 @@ this.DOMApplicationRegistry = {
// Create a new localId.
this.webapps[id].localId = this._nextLocalId();
// Core apps are not removable.
if (this.webapps[id].removable === undefined) {
this.webapps[id].removable = false;
}
} else {
+ // Fields that we must not update. Confere bug 993011 comment 10.
+ let fieldsBlacklist = ["basePath", "id", "installerAppId",
+ "installerIsBrowser", "localId", "receipts", "storeId",
+ "storeVersion"];
// we fall into this case if the app is present in /system/b2g/webapps/webapps.json
// and in /data/local/webapps/webapps.json: this happens when updating gaia apps
// Confere bug 989876
- this.webapps[id].updateTime = data[id].updateTime;
- this.webapps[id].lastUpdateCheck = data[id].updateTime;
+ for (let field in data[id]) {
+ if (fieldsBlacklist.indexOf(field) === -1) {
+ this.webapps[id][field] = data[id][field];
+ }
+ }
}
}
}.bind(this)).then(null, Cu.reportError);
},
loadAndUpdateApps: function() {
return Task.spawn(function() {
let runUpdate = AppsUtils.isFirstRun(Services.prefs);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1246,21 +1246,18 @@ Navigator::MozGetUserMedia(const MediaSt
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
if (!mWindow || !mWindow->GetOuterWindow() ||
mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return;
}
- bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
-
MediaManager* manager = MediaManager::Get();
- aRv = manager->GetUserMedia(privileged, mWindow, aConstraints,
- onsuccess, onerror);
+ aRv = manager->GetUserMedia(mWindow, aConstraints, onsuccess, onerror);
}
void
Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
uint64_t aInnerWindowID,
ErrorResult& aRv)
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2058,46 +2058,47 @@ ConstructJSImplementation(JSContext* aCx
{
// Make sure to divorce ourselves from the calling JS while creating and
// initializing the object, so exceptions from that will get reported
// properly, since those are never exceptions that a spec wants to be thrown.
{
AutoNoJSAPI nojsapi;
// Get the XPCOM component containing the JS implementation.
- nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId);
+ nsresult rv;
+ nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
if (!implISupports) {
NS_WARNING("Failed to get JS implementation for contract");
- aRv.Throw(NS_ERROR_FAILURE);
+ aRv.Throw(rv);
return;
}
// Initialize the object, if it implements nsIDOMGlobalPropertyInitializer.
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
do_QueryInterface(implISupports);
if (gpi) {
JS::Rooted<JS::Value> initReturn(aCx);
- nsresult rv = gpi->Init(aWindow, &initReturn);
+ rv = gpi->Init(aWindow, &initReturn);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
}
// With JS-implemented WebIDL, the return value of init() is not used to determine
// if init() failed, so init() should only return undefined. Any kind of permission
// or pref checking must happen by adding an attribute to the WebIDL interface.
if (!initReturn.isUndefined()) {
MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
MOZ_CRASH();
}
}
// Extract the JS implementation from the XPCOM object.
nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
- do_QueryInterface(implISupports);
+ do_QueryInterface(implISupports, &rv);
MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
if (!implWrapped) {
- aRv.Throw(NS_ERROR_FAILURE);
+ aRv.Throw(rv);
return;
}
aObject.set(implWrapped->GetJSObject());
if (!aObject) {
aRv.Throw(NS_ERROR_FAILURE);
}
}
}
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -95,16 +95,17 @@
#include "nsWrapperCacheInlines.h"
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/TextMetrics.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/dom/SVGMatrix.h"
+#include "mozilla/FloatingPoint.h"
#include "nsGlobalWindow.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "SVGContentUtils.h"
#include "SVGImageContext.h"
#include "nsIScreenManager.h"
#include "nsFilterInstance.h"
#include "nsSVGLength2.h"
@@ -4349,18 +4350,18 @@ CanvasRenderingContext2D::GetImageData(J
if (mCanvasElement && mCanvasElement->IsWriteOnly() &&
!nsContentUtils::IsCallerChrome())
{
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
error.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
- if (!NS_finite(aSx) || !NS_finite(aSy) ||
- !NS_finite(aSw) || !NS_finite(aSh)) {
+ if (!IsFinite(aSx) || !IsFinite(aSy) ||
+ !IsFinite(aSw) || !IsFinite(aSh)) {
error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
if (!aSw || !aSh) {
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
--- a/dom/canvas/CanvasUtils.h
+++ b/dom/canvas/CanvasUtils.h
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _CANVASUTILS_H_
#define _CANVASUTILS_H_
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ToJSValue.h"
#include "jsapi.h"
+#include "mozilla/FloatingPoint.h"
class nsIPrincipal;
namespace mozilla {
namespace gfx {
class Matrix;
}
@@ -48,17 +49,17 @@ void DoDrawImageSecurityCheck(dom::HTMLC
bool CORSUsed);
// Make a double out of |v|, treating undefined values as 0.0 (for
// the sake of sparse arrays). Return true iff coercion
// succeeded.
bool CoerceDouble(JS::Value v, double* d);
/* Float validation stuff */
-#define VALIDATE(_f) if (!NS_finite(_f)) return false
+#define VALIDATE(_f) if (!IsFinite(_f)) return false
inline bool FloatValidate (double f1) {
VALIDATE(f1);
return true;
}
inline bool FloatValidate (double f1, double f2) {
VALIDATE(f1); VALIDATE(f2);
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -222,16 +222,17 @@ WebGLContextOptions::WebGLContextOptions
{
// Set default alpha state based on preference.
if (Preferences::GetBool("webgl.default-no-alpha", false))
alpha = false;
}
WebGLContext::WebGLContext()
: gl(nullptr)
+ , mNeedsFakeNoAlpha(false)
{
SetIsDOMBinding();
mGeneration = 0;
mInvalidated = false;
mShouldPresent = true;
mResetLayer = true;
mOptionsFrozen = false;
@@ -921,16 +922,22 @@ WebGLContext::SetDimensions(int32_t sWid
MOZ_ASSERT(gl->Caps().color);
MOZ_ASSERT(gl->Caps().alpha == mOptions.alpha);
MOZ_ASSERT(gl->Caps().depth == mOptions.depth || !gl->Caps().depth);
MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil || !gl->Caps().stencil);
MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias || !gl->Caps().antialias);
MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
+ if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
+ if (!mOptions.alpha) {
+ mNeedsFakeNoAlpha = true;
+ }
+ }
+
AssertCachedBindings();
AssertCachedState();
reporter.SetSuccessful();
return NS_OK;
}
void
@@ -1335,17 +1342,22 @@ WebGLContext::ForceClearFramebufferWithD
}
// calling draw buffers can cause resolves on adreno drivers so
// we try to avoid calling it
if (shouldOverrideDrawBuffers)
gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
}
gl->fColorMask(1, 1, 1, 1);
- gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ if (mNeedsFakeNoAlpha) {
+ gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ } else {
+ gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ }
}
if (initializeDepthBuffer) {
gl->fDepthMask(1);
gl->fClearDepth(1.0f);
}
if (initializeStencilBuffer) {
@@ -1800,19 +1812,42 @@ bool WebGLContext::TexImageFromVideoElem
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, format, type, WebGLImageDataStatus::InitializedImageData);
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
}
srcImage = nullptr;
container->UnlockCurrentImage();
return ok;
}
-//
+////////////////////////////////////////////////////////////////////////////////
+
+
+WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
+ : mWebGL(webgl)
+ , mNeedsChange(NeedsChange(webgl))
+{
+ if (mNeedsChange) {
+ mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
+ mWebGL.mColorWriteMask[1],
+ mWebGL.mColorWriteMask[2],
+ false);
+ }
+}
+
+WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
+{
+ if (mNeedsChange) {
+ mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
+ mWebGL.mColorWriteMask[1],
+ mWebGL.mColorWriteMask[2],
+ mWebGL.mColorWriteMask[3]);
+ }
+}
+////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
-//
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mCanvasElement,
mExtensions,
mBound2DTextures,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1322,16 +1322,32 @@ protected:
int mAlreadyGeneratedWarnings;
int mMaxWarnings;
bool mAlreadyWarnedAboutFakeVertexAttrib0;
bool ShouldGenerateWarnings() const;
uint64_t mLastUseIndex;
+ bool mNeedsFakeNoAlpha;
+
+ struct ScopedMaskWorkaround {
+ WebGLContext& mWebGL;
+ const bool mNeedsChange;
+
+ static bool NeedsChange(WebGLContext& webgl) {
+ return webgl.mNeedsFakeNoAlpha &&
+ webgl.mColorWriteMask[3] != false;
+ }
+
+ ScopedMaskWorkaround(WebGLContext& webgl);
+
+ ~ScopedMaskWorkaround();
+ };
+
void LoseOldestWebGLContextIfLimitExceeded();
void UpdateLastUseIndex();
template <typename WebGLObjectType>
JS::Value WebGLObjectAsJSValue(JSContext *cx, const WebGLObjectType *, ErrorResult& rv) const;
template <typename WebGLObjectType>
JSObject* WebGLObjectAsJSObject(JSContext *cx, const WebGLObjectType *, ErrorResult& rv) const;
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -129,17 +129,21 @@ WebGLContext::DrawArrays(GLenum mode, GL
if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
return;
if (!DrawArrays_check(first, count, 1, "drawArrays"))
return;
RunContextLossTimer();
- gl->fDrawArrays(mode, first, count);
+
+ {
+ ScopedMaskWorkaround autoMask(*this);
+ gl->fDrawArrays(mode, first, count);
+ }
Draw_cleanup();
}
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
if (IsContextLost())
@@ -147,17 +151,21 @@ WebGLContext::DrawArraysInstanced(GLenum
if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
return;
if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
return;
RunContextLossTimer();
- gl->fDrawArraysInstanced(mode, first, count, primcount);
+
+ {
+ ScopedMaskWorkaround autoMask(*this);
+ gl->fDrawArraysInstanced(mode, first, count, primcount);
+ }
Draw_cleanup();
}
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount,
const char* info, GLuint* out_upperBound)
@@ -308,43 +316,56 @@ WebGLContext::DrawElements(GLenum mode,
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
&upperBound))
{
return;
}
RunContextLossTimer();
- if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
- gl->fDrawRangeElements(mode, 0, upperBound,
- count, type, reinterpret_cast<GLvoid*>(byteOffset));
- } else {
- gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
+ {
+ ScopedMaskWorkaround autoMask(*this);
+
+ if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
+ gl->fDrawRangeElements(mode, 0, upperBound, count, type,
+ reinterpret_cast<GLvoid*>(byteOffset));
+ } else {
+ gl->fDrawElements(mode, count, type,
+ reinterpret_cast<GLvoid*>(byteOffset));
+ }
}
Draw_cleanup();
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
return;
GLuint upperBound = 0;
- if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced",
- &upperBound))
+ if (!DrawElements_check(count, type, byteOffset, primcount,
+ "drawElementsInstanced", &upperBound))
+ {
return;
+ }
RunContextLossTimer();
- gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
+
+ {
+ ScopedMaskWorkaround autoMask(*this);
+ gl->fDrawElementsInstanced(mode, count, type,
+ reinterpret_cast<GLvoid*>(byteOffset),
+ primcount);
+ }
Draw_cleanup();
}
void WebGLContext::Draw_cleanup()
{
UndoFakeVertexAttrib0();
UnbindFakeBlackTextures();
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -35,18 +35,20 @@ WebGLContext::Clear(GLbitfield mask)
gl->fClear(mask);
return;
} else {
ClearBackbufferIfNeeded();
}
// Ok, we're clearing the default framebuffer/screen.
-
- gl->fClear(mask);
+ {
+ ScopedMaskWorkaround autoMask(*this);
+ gl->fClear(mask);
+ }
Invalidate();
mShouldPresent = true;
}
static GLclampf
GLClampFloat(GLclampf val)
{
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -97,16 +97,20 @@ const kEventConstructors = {
},
CompositionEvent: { create: function (aName, aProps) {
var e = document.createEvent("compositionevent");
e.initCompositionEvent(aName, aProps.bubbles, aProps.cancelable,
aProps.view, aProps.data, aProps.locale);
return e;
},
},
+ CSSFontFaceLoadEvent: { create: function (aName, aProps) {
+ return new CSSFontFaceLoadEvent(aName, aProps);
+ },
+ },
CustomEvent: { create: function (aName, aProps) {
return new CustomEvent(aName, aProps);
},
},
DataErrorEvent: { create: function (aName, aProps) {
return new DataErrorEvent(aName, aProps);
},
},
--- a/dom/imptests/failures/html/dom/test_historical.html.json
+++ b/dom/imptests/failures/html/dom/test_historical.html.json
@@ -3,11 +3,10 @@
"Historical DOM features must be removed: createCDATASection": true,
"Historical DOM features must be removed: createAttribute": true,
"Historical DOM features must be removed: createAttributeNS": true,
"Historical DOM features must be removed: inputEncoding": true,
"Historical DOM features must be removed: getAttributeNode": true,
"Historical DOM features must be removed: getAttributeNodeNS": true,
"Historical DOM features must be removed: setAttributeNode": true,
"Historical DOM features must be removed: removeAttributeNode": true,
- "DocumentType member must be nuked: internalSubset": true,
- "Node member must be nuked: hasAttributes": true
+ "DocumentType member must be nuked: internalSubset": true
}
--- a/dom/interfaces/core/nsIDOMAttr.idl
+++ b/dom/interfaces/core/nsIDOMAttr.idl
@@ -9,17 +9,17 @@
* The nsIDOMAttr interface represents an attribute in an "Element" object.
* Typically the allowable values for the attribute are defined in a document
* type definition.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
-[builtinclass, uuid(93bf61ba-9ffa-42b7-9594-2de803c9627c)]
+[builtinclass, uuid(7d0582bd-09a7-430e-969b-054abbea19fe)]
interface nsIDOMAttr : nsIDOMNode
{
readonly attribute DOMString name;
readonly attribute boolean specified;
attribute DOMString value;
// raises(DOMException) on setting
// Introduced in DOM Level 2:
--- a/dom/interfaces/core/nsIDOMCDATASection.idl
+++ b/dom/interfaces/core/nsIDOMCDATASection.idl
@@ -10,12 +10,12 @@
* that would otherwise be regarded as markup.
* Their primary purpose is for including material such as XML fragments,
* without needing to escape all the delimiters.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
-[uuid(864c4e6a-3933-4f8a-8dd8-3883be60ea10)]
+[uuid(4ac42d40-69b7-4506-b730-c41ec74b74bd)]
interface nsIDOMCDATASection : nsIDOMText
{
};
--- a/dom/interfaces/core/nsIDOMCharacterData.idl
+++ b/dom/interfaces/core/nsIDOMCharacterData.idl
@@ -8,17 +8,17 @@
/**
* The nsIDOMCharacterData interface extends nsIDOMNode with a set of
* attributes and methods for accessing character data in the DOM.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
-[uuid(7b1b8719-6669-4614-bf96-93ddf7966f64)]
+[uuid(844b8e7e-6d37-4fa1-8196-86e3afdfa0ca)]
interface nsIDOMCharacterData : nsIDOMNode
{
attribute DOMString data;
// raises(DOMException) on setting
// raises(DOMException) on retrieval
readonly attribute unsigned long length;
DOMString substringData(in unsigned long offset,
--- a/dom/interfaces/core/nsIDOMComment.idl
+++ b/dom/interfaces/core/nsIDOMComment.idl
@@ -9,12 +9,12 @@
* The nsIDOMComment interface inherits from nsIDOMCharacterData and represents
* the content of a comment, i.e., all the characters between the starting
* '<!--' and ending '-->'.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
-[uuid(8edde4d9-dc26-492c-8477-2be0f95088ad)]
+[uuid(c1a1d2ea-e106-4ee8-806d-2633468e8098)]
interface nsIDOMComment : nsIDOMCharacterData
{
};
--- a/dom/interfaces/core/nsIDOMDocument.idl
+++ b/dom/interfaces/core/nsIDOMDocument.idl
@@ -27,17 +27,17 @@ interface nsIDOMLocation;
* cannot exist outside the context of a Document, the nsIDOMDocument
* interface also contains the factory methods needed to create these
* objects.
*
* For more information on this interface please see
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
-[uuid(950ca868-e09f-4a7d-9b87-e4ec9aedb3e5)]
+[uuid(08c6400b-0b6d-4ce6-b88d-e7a15a9c7c03)]
interface nsIDOMDocument : nsIDOMNode
{
readonly attribute nsIDOMDocumentType doctype;
readonly attribute nsIDOMDOMImplementation implementation;
readonly attribute nsIDOMElement documentElement;
nsIDOMElement createElement([Null(Stringify)] in DOMString tagName)
raises(DOMException);
nsIDOMDocumentFragment createDocumentFragment();
--- a/dom/interfaces/core/nsIDOMDocumentFragment.idl
+++ b/dom/interfaces/core/nsIDOMDocumentFragment.idl
@@ -9,17 +9,17 @@
* DocumentFragment is a "lightweight" or "minimal" Document object.
* nsIDOMDocumentFragment is used in situations where the Document
* interface can potentially be a heavyweight interface.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
-[builtinclass, uuid(5c601878-5b77-4f88-9425-3fe8d2dc8813)]
+[builtinclass, uuid(24b34c61-7326-42d4-87ec-5d3b5c0b1b26)]
interface nsIDOMDocumentFragment : nsIDOMNode
{
/**
* Return nodes that match a given CSS selector.
*
* @see <http://dev.w3.org/2006/webapi/selectors-api/>
*/
nsIDOMElement querySelector([Null(Stringify)] in DOMString selectors);
--- a/dom/interfaces/core/nsIDOMDocumentType.idl
+++ b/dom/interfaces/core/nsIDOMDocumentType.idl
@@ -10,17 +10,17 @@
* or a DocumentType object.
* The nsIDOMDocumentType interface in the DOM Core provides an
* interface to the list of entities that are defined for the document.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
-[uuid(55fe2f3f-35e8-4cb0-b39d-bea1bd0061c7)]
+[uuid(23c1f549-d40b-49b8-992e-2a1136afa13f)]
interface nsIDOMDocumentType : nsIDOMNode
{
readonly attribute DOMString name;
readonly attribute DOMString publicId;
readonly attribute DOMString systemId;
readonly attribute DOMString internalSubset;
[binaryname(MozRemove)]
--- a/dom/interfaces/core/nsIDOMElement.idl
+++ b/dom/interfaces/core/nsIDOMElement.idl
@@ -10,17 +10,17 @@ interface nsIDOMMozNamedAttrMap;
/**
* The nsIDOMElement interface represents an element in an HTML or
* XML document.
*
* For more information on this interface please see
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-element
*/
-[uuid(ea94c5e2-5d5d-4afe-b3ab-431903797f31)]
+[uuid(59eb63f9-c8c0-41d2-bf73-739de43b17f9)]
interface nsIDOMElement : nsIDOMNode
{
readonly attribute DOMString tagName;
attribute DOMString id;
attribute DOMString className;
/**
* Returns a DOMTokenList object reflecting the class attribute.
@@ -37,16 +37,17 @@ interface nsIDOMElement : nsIDOMNode
in DOMString qualifiedName,
in DOMString value);
void removeAttribute(in DOMString name);
void removeAttributeNS(in DOMString namespaceURI,
in DOMString localName);
boolean hasAttribute(in DOMString name);
boolean hasAttributeNS(in DOMString namespaceURI,
in DOMString localName);
+ boolean hasAttributes();
// Obsolete methods.
nsIDOMAttr getAttributeNode(in DOMString name);
nsIDOMAttr setAttributeNode(in nsIDOMAttr newAttr);
nsIDOMAttr removeAttributeNode(in nsIDOMAttr oldAttr);
nsIDOMAttr getAttributeNodeNS(in DOMString namespaceURI,
in DOMString localName);
nsIDOMAttr setAttributeNodeNS(in nsIDOMAttr newAttr)
--- a/dom/interfaces/core/nsIDOMNode.idl
+++ b/dom/interfaces/core/nsIDOMNode.idl
@@ -11,17 +11,17 @@ interface nsIVariant;
* The nsIDOMNode interface is the primary datatype for the entire
* Document Object Model.
* It represents a single node in the document tree.
*
* For more information on this interface please see
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
-[uuid(3eef1ab9-2f87-4eda-9bb9-469c37294f72)]
+[uuid(238222a9-7aa5-4804-9f86-484853ce4b15)]
interface nsIDOMNode : nsISupports
{
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2;
const unsigned short TEXT_NODE = 3;
const unsigned short CDATA_SECTION_NODE = 4;
const unsigned short ENTITY_REFERENCE_NODE = 5;
const unsigned short ENTITY_NODE = 6;
@@ -63,18 +63,16 @@ interface nsIDOMNode : nsISupports
void normalize();
// Introduced in DOM Level 2:
readonly attribute DOMString namespaceURI;
// Modified in DOM Core
readonly attribute DOMString prefix;
// Introduced in DOM Level 2:
readonly attribute DOMString localName;
- // Introduced in DOM Level 2:
- boolean hasAttributes();
// Introduced in DOM Level 3:
// This uses a binaryname to avoid warnings due to name collision with
// nsINode::GetBaseURI
[binaryname(DOMBaseURI)] readonly attribute DOMString baseURI;
// DocumentPosition
const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
--- a/dom/interfaces/core/nsIDOMProcessingInstruction.idl
+++ b/dom/interfaces/core/nsIDOMProcessingInstruction.idl
@@ -10,13 +10,13 @@
* "processing instruction", used in XML as a way to keep processor-specific
* information in the text of the document.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/ and
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
-[uuid(ca632936-4c6b-48b4-9920-fbe1e3710802)]
+[uuid(d0163f44-8f5b-4234-b3aa-43cab64e2039)]
interface nsIDOMProcessingInstruction : nsIDOMCharacterData
{
readonly attribute DOMString target;
};
--- a/dom/interfaces/core/nsIDOMText.idl
+++ b/dom/interfaces/core/nsIDOMText.idl
@@ -8,17 +8,17 @@
/**
* The nsIDOMText interface inherits from nsIDOMCharacterData and represents
* the textual content (termed character data in XML) of an Element or Attr.
*
* For more information on this interface please see
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
-[uuid(b16d449b-60f1-444a-a7e5-dc50a5d0ffad)]
+[uuid(775bbd26-1581-4e54-b82c-5d9dc5a3363b)]
interface nsIDOMText : nsIDOMCharacterData
{
nsIDOMText splitText(in unsigned long offset)
raises(DOMException);
/**
* The concatenation of all logically adjacent text nodes with this text
* node, where "logically adjacent" consists of all text nodes which can be
--- a/dom/interfaces/core/nsIDOMXMLDocument.idl
+++ b/dom/interfaces/core/nsIDOMXMLDocument.idl
@@ -1,16 +1,16 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMDocument.idl"
-[uuid(dc767223-838f-4ca2-9f4c-ae685862d1df)]
+[uuid(1d54e44a-2012-4567-805d-bd5455fc6421)]
interface nsIDOMXMLDocument : nsIDOMDocument
{
// DOM Level 3 Load & Save, DocumentLS
// http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS
/**
* Whether to load synchronously or asynchronously.
* The default is async==true.
*/
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -8,17 +8,17 @@
/**
* The nsIDOMHTMLDocument interface is the interface to a [X]HTML
* document object.
*
* @see <http://www.whatwg.org/html/>
*/
interface nsISelection;
-[uuid(b7fcb58a-9ad5-44b5-8c6f-b7181c249413)]
+[uuid(abf369fb-a8b2-4fba-95f5-9e4a896e40a8)]
interface nsIDOMHTMLDocument : nsIDOMDocument
{
attribute DOMString domain;
attribute DOMString cookie;
readonly attribute nsIDOMHTMLHeadElement head;
attribute nsIDOMHTMLElement body;
--- a/dom/interfaces/html/nsIDOMHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLElement.idl
@@ -14,17 +14,17 @@ interface nsIDOMHTMLMenuElement;
* tree.
*
* This interface is trying to follow the DOM Level 2 HTML specification:
* http://www.w3.org/TR/DOM-Level-2-HTML/
*
* with changes from the work-in-progress WHATWG HTML specification:
* http://www.whatwg.org/specs/web-apps/current-work/
*/
-[uuid(2728c077-9ecc-4a75-ac95-16fbfcb007df)]
+[uuid(8c9472c2-785a-40b6-ad47-4d98e64562bd)]
interface nsIDOMHTMLElement : nsIDOMElement
{
// metadata attributes
attribute DOMString title;
attribute DOMString lang;
attribute DOMString dir;
readonly attribute nsISupports dataset;
--- a/dom/interfaces/svg/nsIDOMSVGElement.idl
+++ b/dom/interfaces/svg/nsIDOMSVGElement.idl
@@ -4,17 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMElement.idl"
interface nsIDOMCSSStyleDeclaration;
interface nsIDOMCSSValue;
-[uuid(7a11697a-668b-4a6e-a44a-909abffee230)]
+[uuid(6618074e-0c77-4fec-8870-a6f79aa79b07)]
interface nsIDOMSVGElement : nsIDOMElement
{
// raises DOMException on setting
readonly attribute nsIDOMSVGElement ownerSVGElement;
readonly attribute nsIDOMSVGElement viewportElement;
[binaryname(SVGClassName)]
readonly attribute nsISupports className;
--- a/dom/interfaces/xul/nsIDOMXULDocument.idl
+++ b/dom/interfaces/xul/nsIDOMXULDocument.idl
@@ -5,17 +5,17 @@
#include "domstubs.idl"
#include "nsIDOMDocument.idl"
interface nsIDOMXULCommandDispatcher;
interface nsIObserver;
interface nsIBoxObject;
-[uuid(546c658e-805f-4293-9738-6e6a00d75839)]
+[uuid(6f932360-ae43-4fa7-9200-66f64e05a356)]
interface nsIDOMXULDocument : nsIDOMDocument
{
attribute nsIDOMNode popupNode;
/**
* These attributes correspond to trustedGetPopupNode().rangeOffset and
* rangeParent. They will help you find where in the DOM the popup is
* happening. Can be accessed from chrome only, and only during a popup
--- a/dom/interfaces/xul/nsIDOMXULElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULElement.idl
@@ -7,17 +7,17 @@
interface nsIRDFCompositeDataSource;
interface nsIXULTemplateBuilder;
interface nsIRDFResource;
interface nsIControllers;
interface nsIBoxObject;
-[uuid(1bd9303d-0854-4ed3-9fda-added29a570e)]
+[uuid(ef62515d-3160-4463-abd7-fc9b7385ecef)]
interface nsIDOMXULElement : nsIDOMElement
{
// Layout properties
attribute DOMString align;
attribute DOMString dir;
attribute DOMString flex;
attribute DOMString flexGroup;
attribute DOMString ordinal;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1572,41 +1572,43 @@ MediaManager::NotifyRecordingStatusChang
}
/**
* The entry point for this file. A call from Navigator::mozGetUserMedia
* will end up here. MediaManager is a singleton that is responsible
* for handling all incoming getUserMedia calls from every window.
*/
nsresult
-MediaManager::GetUserMedia(bool aPrivileged,
+MediaManager::GetUserMedia(
nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints,
nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
+ bool privileged = nsContentUtils::IsChromeDoc(aWindow->GetExtantDoc());
+
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
MediaStreamConstraints c(aConstraints); // copy
/**
* If we were asked to get a picture, before getting a snapshot, we check if
* the calling page is allowed to open a popup. We do this because
* {picture:true} will open a new "window" to let the user preview or select
* an image, on Android. The desktop UI for {picture:true} is TBD, at which
* may point we can decide whether to extend this test there as well.
*/
#if !defined(MOZ_WEBRTC)
- if (c.mPicture && !aPrivileged) {
+ if (c.mPicture && !privileged) {
if (aWindow->GetPopupControlState() > openControlled) {
nsCOMPtr<nsIPopupWindowManager> pm =
do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
if (!pm) {
return NS_OK;
}
uint32_t permission;
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
@@ -1648,17 +1650,17 @@ MediaManager::GetUserMedia(bool aPrivile
GetUserMediaCallbackMediaStreamListener* listener =
new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID);
// No need for locking because we always do this in the main thread.
listeners->AppendElement(listener);
// Developer preference for turning off permission check.
if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
- aPrivileged = true;
+ privileged = true;
}
if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
c.mVideo.SetAsBoolean() = false;
}
#if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
// Be backwards compatible only on mobile and only for facingMode.
if (c.mVideo.IsMediaTrackConstraints()) {
@@ -1676,17 +1678,17 @@ MediaManager::GetUserMedia(bool aPrivile
n.mFacingMode.Construct(tc.mOptional.Value()[i].mFacingMode.Value());
tc.mAdvanced.Value().AppendElement(n);
}
}
}
}
#endif
- if (c.mVideo.IsMediaTrackConstraints() && !aPrivileged) {
+ if (c.mVideo.IsMediaTrackConstraints() && !privileged) {
auto& tc = c.mVideo.GetAsMediaTrackConstraints();
// only allow privileged content to set the window id
if (tc.mBrowserWindow.WasPassed()) {
tc.mBrowserWindow.Construct(-1);
}
if (tc.mAdvanced.WasPassed()) {
uint32_t length = tc.mAdvanced.Value().Length();
@@ -1733,17 +1735,17 @@ MediaManager::GetUserMedia(bool aPrivile
#if defined(XP_MACOSX)
!nsCocoaFeatures::OnLionOrLater()
#endif
#if defined (XP_WIN)
!IsVistaOrLater()
#endif
) ||
#endif
- (!aPrivileged && !HostHasPermission(*docURI))) {
+ (!privileged && !HostHasPermission(*docURI))) {
return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
}
}
}
#ifdef MOZ_B2G_CAMERA
if (mCameraManager == nullptr) {
mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
@@ -1762,21 +1764,21 @@ MediaManager::GetUserMedia(bool aPrivile
bool isLoop = false;
nsCOMPtr<nsIURI> loopURI;
nsresult rv = NS_NewURI(getter_AddRefs(loopURI), "about:loopconversation");
NS_ENSURE_SUCCESS(rv, rv);
rv = docURI->EqualsExceptRef(loopURI, &isLoop);
NS_ENSURE_SUCCESS(rv, rv);
if (isLoop) {
- aPrivileged = true;
+ privileged = true;
}
// XXX No full support for picture in Desktop yet (needs proper UI)
- if (aPrivileged ||
+ if (privileged ||
(c.mFake && !Preferences::GetBool("media.navigator.permission.fake"))) {
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
} else {
bool isHTTPS = false;
if (docURI) {
docURI->SchemeIs("https", &isHTTPS);
}
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -1,12 +1,15 @@
/* 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_MEDIAMANAGER_H
+#define MOZILLA_MEDIAMANAGER_H
+
#include "MediaEngine.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "nsIMediaManager.h"
#include "nsHashKeys.h"
#include "nsGlobalWindow.h"
#include "nsClassHashtable.h"
@@ -569,19 +572,19 @@ public:
void RemoveWindowID(uint64_t aWindowId);
bool IsWindowStillActive(uint64_t aWindowId) {
return !!GetWindowListeners(aWindowId);
}
// Note: also calls aListener->Remove(), even if inactive
void RemoveFromWindowList(uint64_t aWindowID,
GetUserMediaCallbackMediaStreamListener *aListener);
- nsresult GetUserMedia(bool aPrivileged,
+ nsresult GetUserMedia(
nsPIDOMWindow* aWindow,
- const dom::MediaStreamConstraints& aRawConstraints,
+ const dom::MediaStreamConstraints& aConstraints,
nsIDOMGetUserMediaSuccessCallback* onSuccess,
nsIDOMGetUserMediaErrorCallback* onError);
nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
const dom::MediaStreamConstraints& aConstraints,
nsIGetUserMediaDevicesSuccessCallback* onSuccess,
nsIDOMGetUserMediaErrorCallback* onError,
uint64_t aInnerWindowID = 0);
@@ -627,8 +630,10 @@ private:
static StaticRefPtr<MediaManager> sSingleton;
#ifdef MOZ_B2G_CAMERA
nsRefPtr<nsDOMCameraManager> mCameraManager;
#endif
};
} // namespace mozilla
+
+#endif // MOZILLA_MEDIAMANAGER_H
--- a/dom/settings/SettingsRequestManager.jsm
+++ b/dom/settings/SettingsRequestManager.jsm
@@ -678,17 +678,21 @@ let SettingsRequestManager = {
broadcastMessage: function broadcastMessage(aMsgName, aContent) {
if (DEBUG) debug("Broadcast");
this.children.forEach(function(msgMgr) {
let principal = this.mmPrincipals.get(msgMgr);
if (!principal) {
if (DEBUG) debug("Cannot find principal for message manager to check permissions");
}
else if (SettingsPermissions.hasReadPermission(principal, aContent.key)) {
- msgMgr.sendAsyncMessage(aMsgName, aContent);
+ try {
+ msgMgr.sendAsyncMessage(aMsgName, aContent);
+ } catch (e) {
+ if (DEBUG) debug("Failed sending message: " + aMsgName);
+ }
}
}.bind(this));
if (DEBUG) debug("Finished Broadcasting");
},
addObserver: function(aMsgMgr, aPrincipal) {
if (DEBUG) debug("Add observer for " + aPrincipal.origin);
if (this.children.indexOf(aMsgMgr) == -1) {
--- a/dom/tests/mochitest/dom-level2-core/exclusions.js
+++ b/dom/tests/mochitest/dom-level2-core/exclusions.js
@@ -22,17 +22,17 @@ dtdTests = ["attrgetownerelement01", "do
"prefix08", "removeAttributeNS01", "removeAttributeNS02",
"removeNamedItemNS03", "setAttributeNodeNS02", "setAttributeNS03",
"setNamedItemNS04"];
bug371552 = ["elementhasattributens02"];
wrongDocError = ["elementsetattributenodens05", "namednodemapsetnameditemns03",
"setAttributeNodeNS05", "setNamedItemNS02"];
attrExodus = ["elementsetattributenodens06", "importNode01",
- "hc_namednodemapinvalidtype1"];
+ "hc_namednodemapinvalidtype1", "nodehasattributes02"];
bogusPrefix = ["nodesetprefix05", "nodesetprefix09", "prefix06", "prefix07"];
prefixReplacement = ["setAttributeNodeNS04"];
function concat(lst/*...*/) {
var f = [];
if (arguments !== null) {
f = arguments[0];
}
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -250,16 +250,18 @@ var interfaceNamesInGlobalScope =
"CSS2Properties",
// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSCharsetRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSConditionRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSCounterStyleRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "CSSFontFaceLoadEvent", pref: "layout.css.font-loading-api.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSFontFaceRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSFontFeatureValuesRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSGroupingRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
"CSSImportRule",
// IMPORTANT: Do not change this list without review from a DOM peer!
@@ -394,16 +396,20 @@ var interfaceNamesInGlobalScope =
"FileReader",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "FMRadio", b2g: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"FocusEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"FormData",
// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "FontFace", pref: "layout.css.font-loading-api.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "FontFaceSet", pref: "layout.css.font-loading-api.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
"GainNode",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "Gamepad", b2g: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "GamepadAxisMoveEvent", b2g: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "GamepadButtonEvent", b2g: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/mochitest/notification/NotificationTest.js
+++ b/dom/tests/mochitest/notification/NotificationTest.js
@@ -4,16 +4,17 @@ var NotificationTest = (function () {
function info(msg, name) {
SimpleTest.info("::Notification Tests::" + (name || ""), msg);
}
function setup_testing_env() {
SimpleTest.waitForExplicitFinish();
// turn on testing pref (used by notification.cpp, and mock the alerts
SpecialPowers.setBoolPref("notification.prompt.testing", true);
+ SpecialPowers.setAllAppsLaunchable(true);
}
function teardown_testing_env() {
SimpleTest.finish();
}
function executeTests(tests, callback) {
// context is `this` object in test functions
--- a/dom/webidl/Animation.webidl
+++ b/dom/webidl/Animation.webidl
@@ -9,10 +9,13 @@
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[Pref="dom.animations-api.core.enabled"]
interface Animation {
// FIXME: |effect| should have type (AnimationEffect or EffectCallback)?
// but we haven't implemented EffectCallback yet.
- [Cached,Pure] readonly attribute AnimationEffect? effect;
+ [Cached,Pure]
+ readonly attribute AnimationEffect? effect;
+ // FIXME: This should be writeable (bug 1067769)
+ readonly attribute Element? target;
};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSFontFaceLoadEvent.webidl
@@ -0,0 +1,21 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#FontFaceSet-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+dictionary CSSFontFaceLoadEventInit : EventInit {
+ sequence<FontFace> fontfaces = [];
+};
+
+[Constructor(DOMString type, optional CSSFontFaceLoadEventInit eventInitDict),
+ Pref="layout.css.font-loading-api.enabled"]
+interface CSSFontFaceLoadEvent : Event {
+ [Cached, Constant] readonly attribute sequence<FontFace> fontfaces;
+};
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -356,8 +356,9 @@ partial interface Document {
};
Document implements XPathEvaluator;
Document implements GlobalEventHandlers;
Document implements TouchEventHandlers;
Document implements ParentNode;
Document implements OnErrorEventHandlerForNodes;
Document implements GeometryUtils;
+Document implements FontFaceSource;
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -46,16 +46,18 @@ interface Element : Node {
[Throws]
void removeAttribute(DOMString name);
[Throws]
void removeAttributeNS(DOMString? namespace, DOMString localName);
[Pure]
boolean hasAttribute(DOMString name);
[Pure]
boolean hasAttributeNS(DOMString? namespace, DOMString localName);
+ [Pure]
+ boolean hasAttributes();
[Throws, Pure]
Element? closest(DOMString selector);
[Throws, Pure]
boolean matches(DOMString selector);
[Pure]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FontFace.webidl
@@ -0,0 +1,48 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#fontface-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+typedef (ArrayBuffer or ArrayBufferView) BinaryData;
+
+dictionary FontFaceDescriptors {
+ DOMString style = "normal";
+ DOMString weight = "normal";
+ DOMString stretch = "normal";
+ DOMString unicodeRange = "U+0-10FFFF";
+ DOMString variant = "normal";
+ DOMString featureSettings = "normal";
+};
+
+enum FontFaceLoadStatus { "unloaded", "loading", "loaded", "error" };
+
+// Bug 1072107 is for exposing this in workers.
+// [Exposed=(Window,Worker)]
+[Constructor(DOMString family,
+ (DOMString or BinaryData) source,
+ optional FontFaceDescriptors descriptors),
+ Pref="layout.css.font-loading-api.enabled"]
+interface FontFace {
+ [SetterThrows] attribute DOMString family;
+ [SetterThrows] attribute DOMString style;
+ [SetterThrows] attribute DOMString weight;
+ [SetterThrows] attribute DOMString stretch;
+ [SetterThrows] attribute DOMString unicodeRange;
+ [SetterThrows] attribute DOMString variant;
+ [SetterThrows] attribute DOMString featureSettings;
+
+ readonly attribute FontFaceLoadStatus status;
+
+ [Throws]
+ Promise<FontFace> load();
+
+ [Throws]
+ readonly attribute Promise<FontFace> loaded;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FontFaceSet.webidl
@@ -0,0 +1,63 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#FontFaceSet-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+enum FontFaceSetLoadStatus { "loading", "loaded" };
+
+// Bug 1072762 is for the FontFaceSet constructor.
+// [Constructor(sequence<FontFace> initialFaces)]
+[Pref="layout.css.font-loading-api.enabled"]
+interface FontFaceSet : EventTarget {
+
+ // Emulate the Set interface, until we can extend Set correctly.
+ // Implementing these commented out operations and the iterator is
+ // bug 1072101.
+ // readonly attribute unsigned long size;
+ [Throws] void add(FontFace font);
+ boolean has(FontFace font);
+ [Throws] boolean delete(FontFace font);
+ void clear();
+ // Iterator entries();
+ // Iterator keys();
+ // Iterator values();
+ // void forEach(ForEachCallback cb, optional any thisArg);
+ // FontFace iterator;
+
+ // -- events for when loading state changes
+ attribute EventHandler onloading;
+ attribute EventHandler onloadingdone;
+ attribute EventHandler onloadingerror;
+
+ // check and start loads if appropriate
+ // and fulfill promise when all loads complete
+ // Not implemented yet: bug 1072102.
+ [Throws] Promise<sequence<FontFace>> load(DOMString font, optional DOMString text = " ");
+
+ // return whether all fonts in the fontlist are loaded
+ // (does not initiate load if not available)
+ // Not implemented yet: bug 1072102.
+ // [Throws] boolean check(DOMString font, optional DOMString text = " ");
+
+ // async notification that font loading and layout operations are done
+ [Throws] readonly attribute Promise<void> ready;
+
+ // loading state, "loading" while one or more fonts loading, "loaded" otherwise
+ readonly attribute FontFaceSetLoadStatus status;
+};
+
+// This provides access to the FontFace objects in the FontFaceSet until we
+// get iterators working (bug 1072101). Don't enable the pref for the CSS Font
+// Loading API until the iterator is available, as we don't want to expose more
+// indexed properties on the Web.
+partial interface FontFaceSet {
+ getter FontFace (unsigned long index);
+ readonly attribute unsigned long length;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FontFaceSource.webidl
@@ -0,0 +1,18 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css-font-loading/#font-face-source
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[NoInterfaceObject]
+interface FontFaceSource {
+
+ [Throws, Pref="layout.css.font-loading-api.enabled"]
+ readonly attribute FontFaceSet fonts;
+};
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -96,18 +96,16 @@ interface Node : EventTarget {
// a non-nullable type.
[Constant]
readonly attribute DOMString? namespaceURI;
[Constant]
readonly attribute DOMString? prefix;
[Constant]
readonly attribute DOMString? localName;
- [Pure]
- boolean hasAttributes();
[Throws, Func="IsChromeOrXBL"]
any setUserData(DOMString key, any data);
[Throws, Func="IsChromeOrXBL"]
any getUserData(DOMString key);
[ChromeOnly]
readonly attribute Principal nodePrincipal;
[ChromeOnly]
readonly attribute URI? baseURIObject;
--- a/dom/webidl/WorkerGlobalScope.webidl
+++ b/dom/webidl/WorkerGlobalScope.webidl
@@ -34,16 +34,19 @@ partial interface WorkerGlobalScope {
void importScripts(DOMString... urls);
readonly attribute WorkerNavigator navigator;
};
WorkerGlobalScope implements WindowTimers;
WorkerGlobalScope implements WindowBase64;
+// Not implemented yet: bug 1072107.
+// WorkerGlobalScope implements FontFaceSource;
+
// Mozilla extensions
partial interface WorkerGlobalScope {
attribute EventHandler onclose;
void dump(optional DOMString str);
// XXXbz no spec for this yet, because the webperf WG is a bit dysfunctional
readonly attribute Performance performance;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -125,16 +125,19 @@ WEBIDL_FILES = [
'EventSource.webidl',
'EventTarget.webidl',
'File.webidl',
'FileList.webidl',
'FileMode.webidl',
'FileReader.webidl',
'FileReaderSync.webidl',
'FocusEvent.webidl',
+ 'FontFace.webidl',
+ 'FontFaceSet.webidl',
+ 'FontFaceSource.webidl',
'FormData.webidl',
'Function.webidl',
'GainNode.webidl',
'Geolocation.webidl',
'GeometryUtils.webidl',
'GetUserMediaRequest.webidl',
'Headers.webidl',
'History.webidl',
@@ -643,16 +646,17 @@ if CONFIG['MOZ_B2G_FM']:
GENERATED_EVENTS_WEBIDL_FILES = [
'AutocompleteErrorEvent.webidl',
'BlobEvent.webidl',
'CallEvent.webidl',
'CallGroupErrorEvent.webidl',
'CFStateChangeEvent.webidl',
'CloseEvent.webidl',
+ 'CSSFontFaceLoadEvent.webidl',
'DataErrorEvent.webidl',
'DataStoreChangeEvent.webidl',
'DeviceLightEvent.webidl',
'DeviceOrientationEvent.webidl',
'DeviceProximityEvent.webidl',
'DeviceStorageChangeEvent.webidl',
'DOMTransactionEvent.webidl',
'DownloadEvent.webidl',
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -246,26 +246,17 @@ GetRetainedImageFromSourceSurface(Source
data->Stride(), data->GetFormat());
}
}
}
TemporaryRef<SourceSurface>
DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const
{
- if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE ||
- aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT) {
- return aSurface;
- }
- RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
-
- return CreateSourceSurfaceFromData(data->GetData(),
- data->GetSize(),
- data->Stride(),
- data->GetFormat());
+ return aSurface;
}
class UnboundnessFixer
{
CGRect mClipBounds;
CGLayerRef mLayer;
CGContextRef mCg;
public:
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -283,27 +283,37 @@ ChooseConfig(GLContext* gl, GLLibraryEGL
NS_WARNING("No configs found for the requested formats.");
return EGL_NO_CONFIG;
}
// The requests passed to ChooseConfig are treated as minimums. If you ask
// for 0 bits of alpha, we might still get 8 bits.
EGLConfig config = EGL_NO_CONFIG;
for (int i = 0; i < foundConfigs; i++) {
- EGLConfig cur = configs[0];
- if (DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
- caps.alpha) &&
- DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
- caps.depth) &&
- DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
- caps.stencil))
+ EGLConfig cur = configs[i];
+ if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
+ caps.depth) ||
+ !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
+ caps.stencil))
{
- config = cur;
- break;
+ continue;
}
+
+ // We can't enforce alpha on ANGLE yet because of:
+ // https://code.google.com/p/angleproject/issues/detail?id=764
+ if (!gl->IsANGLE()) {
+ if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
+ caps.alpha))
+ {
+ continue;
+ }
+ }
+
+ config = cur;
+ break;
}
if (config == EGL_NO_CONFIG) {
NS_WARNING("No acceptable EGLConfig found.");
return EGL_NO_CONFIG;
}
if (gl->DebugMode()) {
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1284,16 +1284,20 @@ nsEventStatus AsyncPanZoomController::On
case NOTHING:
// May happen if the user double-taps and drags without lifting after the
// second tap. Ignore if this happens.
return nsEventStatus_eIgnore;
case TOUCHING:
case CROSS_SLIDING_X:
case CROSS_SLIDING_Y:
+ // We may have some velocity stored on the axis from move events
+ // that were not big enough to trigger scrolling. Clear that out.
+ mX.SetVelocity(0);
+ mY.SetVelocity(0);
SetState(NOTHING);
return nsEventStatus_eIgnore;
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
{
CurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
@@ -2444,17 +2448,21 @@ bool AsyncPanZoomController::UpdateAnima
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
return true;
}
return false;
}
-void AsyncPanZoomController::GetOverscrollTransform(Matrix4x4* aTransform) const {
+Matrix4x4 AsyncPanZoomController::GetOverscrollTransform() const {
+ if (!IsOverscrolled()) {
+ return Matrix4x4();
+ }
+
// The overscroll effect is a uniform stretch along the overscrolled axis,
// with the edge of the content where we have reached the end of the
// scrollable area pinned into place.
// The kStretchFactor parameter determines how much overscroll can stretch the
// content.
const float kStretchFactor = gfxPrefs::APZOverscrollStretchFactor();
@@ -2479,18 +2487,18 @@ void AsyncPanZoomController::GetOverscro
if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) {
// Overscrolled at the bottomn.
ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
translation.y = -extraCompositionHeight;
}
// Combine the transformations into a matrix.
- *aTransform = Matrix4x4().Scale(scaleX, scaleY, 1)
- .PostTranslate(translation.x, translation.y, 0);
+ return Matrix4x4().Scale(scaleX, scaleY, 1)
+ .PostTranslate(translation.x, translation.y, 0);
}
bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
{
AssertOnCompositorThread();
// Don't send any state-change notifications until the end of the function,
// because we may go through some intermediate states while we finish
@@ -2556,29 +2564,22 @@ bool AsyncPanZoomController::AdvanceAnim
mAsyncScrollTimeoutTask,
gfxPrefs::APZAsyncScrollTimeout());
}
return requestAnimationFrame;
}
void AsyncPanZoomController::SampleContentTransformForFrame(ViewTransform* aOutTransform,
- ScreenPoint& aScrollOffset,
- Matrix4x4* aOutOverscrollTransform)
+ ScreenPoint& aScrollOffset)
{
ReentrantMonitorAutoEnter lock(mMonitor);
aScrollOffset = mFrameMetrics.GetScrollOffset() * mFrameMetrics.GetZoom();
*aOutTransform = GetCurrentAsyncTransform();
-
- // If we are overscrolled, we would like the compositor to apply an
- // additional transform that produces an overscroll effect.
- if (aOutOverscrollTransform && IsOverscrolled()) {
- GetOverscrollTransform(aOutOverscrollTransform);
- }
}
ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
ReentrantMonitorAutoEnter lock(mMonitor);
CSSPoint lastPaintScrollOffset;
if (mLastContentPaintMetrics.IsScrollable()) {
lastPaintScrollOffset = mLastContentPaintMetrics.GetScrollOffset();
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -161,28 +161,27 @@ public:
bool AdvanceAnimations(const TimeStamp& aSampleTime);
bool UpdateAnimation(const TimeStamp& aSampleTime,
Vector<Task*>* aOutDeferredTasks);
/**
* Query the transforms that should be applied to the layer corresponding
* to this APZC due to asynchronous panning and zooming.
- * This function returns two transforms via out parameters:
- * |aOutTransform| is the transform due to regular panning and zooming
- * |aOverscrollTransform| is the transform due to overscrolling
- * The two are separated because some clients want to ignore the overscroll
- * transform for some purposes (and for convenience to these clients, the
- * overscroll transform parameter may be nullptr). Clients who do not want
- * to ignore the overscroll transform should multiply the two transforms
- * together.
+ * This function returns the async transform via the |aOutTransform|
+ * out parameter.
*/
void SampleContentTransformForFrame(ViewTransform* aOutTransform,
- ScreenPoint& aScrollOffset,
- Matrix4x4* aOutOverscrollTransform);
+ ScreenPoint& aScrollOffset);
+
+ /**
+ * Return a visual effect that reflects this apzc's
+ * overscrolled state, if any.
+ */
+ Matrix4x4 GetOverscrollTransform() const;
/**
* A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics
* for the container layer corresponding to this APZC.
* |aIsFirstPaint| is a flag passed from the shadow
* layers code indicating that the frame metrics being sent with this call are
* the initial metrics and the initial paint of the frame has just happened.
*/
@@ -590,22 +589,16 @@ private:
/**
* Convert ScreenPoint relative to this APZC to CSSPoint relative
* to the parent document. This excludes the transient compositor transform.
* NOTE: This must be converted to CSSPoint relative to the child
* document before sending over IPC.
*/
bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut);
- /**
- * Return in |aTransform| a visual effect that reflects this apzc's
- * overscrolled state, if any.
- */
- void GetOverscrollTransform(Matrix4x4* aTransform) const;
-
enum AxisLockMode {
FREE, /* No locking at all */
STANDARD, /* Default axis locking mode that remains locked until pan ends*/
STICKY, /* Allow lock to be broken, with hysteresis */
};
static AxisLockMode GetAxisLockMode();
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -507,17 +507,17 @@ TileClient::~TileClient()
TileClient::TileClient(const TileClient& o)
{
mBackBuffer.Set(this, o.mBackBuffer);
mBackBufferOnWhite = o.mBackBufferOnWhite;
mFrontBuffer = o.mFrontBuffer;
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
- mCompositableClient = o.mCompositableClient;
+ mCompositableClient = nullptr;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mManager = o.mManager;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
}
@@ -526,17 +526,17 @@ TileClient::operator=(const TileClient&
{
if (this == &o) return *this;
mBackBuffer.Set(this, o.mBackBuffer);
mBackBufferOnWhite = o.mBackBufferOnWhite;
mFrontBuffer = o.mFrontBuffer;
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
- mCompositableClient = o.mCompositableClient;
+ mCompositableClient = nullptr;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mManager = o.mManager;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
return *this;
}
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -581,21 +581,20 @@ AsyncCompositionManager::ApplyAsyncConte
AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
if (!controller) {
continue;
}
hasAsyncTransform = true;
ViewTransform asyncTransformWithoutOverscroll;
- Matrix4x4 overscrollTransform;
ScreenPoint scrollOffset;
controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
- scrollOffset,
- &overscrollTransform);
+ scrollOffset);
+ Matrix4x4 overscrollTransform = controller->GetOverscrollTransform();
if (!aLayer->IsScrollInfoLayer()) {
controller->MarkAsyncTransformAppliedToContent();
}
const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
@@ -728,25 +727,33 @@ ApplyAsyncTransformToScrollbarForContent
Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
if (aScrollbarIsDescendant) {
// If the scrollbar layer is a child of the content it is a scrollbar for, then we
// need to do an extra untransform to cancel out the transient async transform on
// the content. This is needed because otherwise that transient async transform is
// part of the effective transform of this scrollbar, and the scrollbar will jitter
// as the content scrolls.
- Matrix4x4 transientUntransform = transientTransform.Inverse();
- transform = transform * transientUntransform;
+ // Since the async transform is applied on top of the content's regular
+ // transform, we need to make sure to unapply the async transform in the
+ // same coordinate space. This requires applying the content transform and
+ // then unapplying it after unapplying the async transform.
+ Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse();
+ Matrix4x4 contentTransform = aContent.GetTransform();
+ Matrix4x4 contentUntransform = contentTransform.Inverse();
+
+ Matrix4x4 compensation = contentTransform * asyncUntransform * contentUntransform;
+ transform = transform * compensation;
// We also need to make a corresponding change on the clip rect of all the
// layers on the ancestor chain from the scrollbar layer up to but not
// including the layer with the async transform. Otherwise the scrollbar
// shifts but gets clipped and so appears to flicker.
for (Layer* ancestor = aScrollbar; ancestor != aContent.GetLayer(); ancestor = ancestor->GetParent()) {
- TransformClipRect(ancestor, transientUntransform);
+ TransformClipRect(ancestor, compensation);
}
}
// GetTransform already takes the pre- and post-scale into account. Since we
// will apply the pre- and post-scale again when computing the effective
// transform, we must apply the inverses here.
if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
transform.Scale(1.0f/container->GetPreXScale(),
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -157,20 +157,19 @@ public:
while (AdvanceAnimations(aSampleTime)) {
aSampleTime += aIncrement;
}
}
bool SampleContentTransformForFrame(const TimeStamp& aSampleTime,
ViewTransform* aOutTransform,
ScreenPoint& aScrollOffset) {
- Matrix4x4 aOverscrollTransform; // ignored
bool ret = AdvanceAnimations(aSampleTime);
AsyncPanZoomController::SampleContentTransformForFrame(
- aOutTransform, aScrollOffset, &aOverscrollTransform);
+ aOutTransform, aScrollOffset);
return ret;
}
};
class TestAPZCTreeManager : public APZCTreeManager {
};
static FrameMetrics
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -121,16 +121,18 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
gfxSparseBitSet* aUnicodeRanges)
: gfxFontEntry(NS_LITERAL_STRING("userfont")),
mUserFontLoadState(STATUS_NOT_LOADED),
mFontDataLoadingState(NOT_LOADING),
mUnsupportedFormat(false),
mLoader(nullptr),
mFontSet(aFontSet)
{
+ MOZ_ASSERT(aWeight != 0,
+ "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
mIsUserFontContainer = true;
mSrcList = aFontFaceSrcList;
mSrcIndex = 0;
mWeight = aWeight;
mStretch = aStretch;
// XXX Currently, we don't distinguish 'italic' and 'oblique' styles;
// we need to fix this. (Bug 543715)
mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
@@ -244,31 +246,55 @@ gfxUserFontEntry::StoreUserFontData(gfxF
uint32_t aMetaOrigLen)
{
if (!aFontEntry->mUserFontData) {
aFontEntry->mUserFontData = new gfxUserFontData;
}
gfxUserFontData* userFontData = aFontEntry->mUserFontData;
userFontData->mSrcIndex = mSrcIndex;
const gfxFontFaceSrc& src = mSrcList[mSrcIndex];
- if (src.mIsLocal) {
- userFontData->mLocalName = src.mLocalName;
- } else {
- userFontData->mURI = src.mURI;
- userFontData->mPrincipal = mPrincipal;
+ switch (src.mSourceType) {
+ case gfxFontFaceSrc::eSourceType_Local:
+ userFontData->mLocalName = src.mLocalName;
+ break;
+ case gfxFontFaceSrc::eSourceType_URL:
+ userFontData->mURI = src.mURI;
+ userFontData->mPrincipal = mPrincipal;
+ break;
+ case gfxFontFaceSrc::eSourceType_Buffer:
+ userFontData->mIsBuffer = true;
+ break;
}
userFontData->mPrivate = aPrivate;
userFontData->mFormat = src.mFormatFlags;
userFontData->mRealName = aOriginalName;
if (aMetadata) {
userFontData->mMetadata.SwapElements(*aMetadata);
userFontData->mMetaOrigLen = aMetaOrigLen;
}
}
+void
+gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
+ nsACString& aURI)
+{
+ aFamilyName.Assign(NS_ConvertUTF16toUTF8(mFamilyName));
+
+ aURI.Truncate();
+ if (mSrcIndex == mSrcList.Length()) {
+ aURI.AppendLiteral("(end of source list)");
+ } else {
+ if (mSrcList[mSrcIndex].mURI) {
+ mSrcList[mSrcIndex].mURI->GetSpec(aURI);
+ } else {
+ aURI.AppendLiteral("(invalid URI)");
+ }
+ }
+}
+
struct WOFFHeader {
AutoSwap_PRUint32 signature;
AutoSwap_PRUint32 flavor;
AutoSwap_PRUint32 length;
AutoSwap_PRUint16 numTables;
AutoSwap_PRUint16 reserved;
AutoSwap_PRUint32 totalSfntSize;
AutoSwap_PRUint16 majorVersion;
@@ -332,21 +358,21 @@ gfxUserFontEntry::LoadNextSrc()
// but don't reset state - if we've already timed out,
// that counts against the new download
mSrcIndex++;
}
// load each src entry in turn, until a local face is found
// or a download begins successfully
while (mSrcIndex < numSrc) {
- const gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex];
+ gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex];
// src local ==> lookup and load immediately
- if (currSrc.mIsLocal) {
+ if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) {
gfxFontEntry* fe =
gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName,
mWeight,
mStretch,
mItalic);
mFontSet->SetLocalRulesUsed();
if (fe) {
LOG(("fontset (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
@@ -368,17 +394,17 @@ gfxUserFontEntry::LoadNextSrc()
LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
mFontSet, mSrcIndex,
NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
}
// src url ==> start the load process
- else {
+ else if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL) {
if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
currSrc.mFormatFlags)) {
nsIPrincipal* principal = nullptr;
bool bypassCache;
nsresult rv = mFontSet->CheckFontLoad(&currSrc, &principal,
&bypassCache);
@@ -455,16 +481,38 @@ gfxUserFontEntry::LoadNextSrc()
}
} else {
// We don't log a warning to the web console yet,
// as another source may load successfully
mUnsupportedFormat = true;
}
}
+ // FontFace buffer ==> load immediately
+
+ else {
+ MOZ_ASSERT(currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Buffer);
+
+ uint8_t* buffer = nullptr;
+ uint32_t bufferLength = 0;
+
+ // sync load font immediately
+ currSrc.mBuffer->TakeBuffer(buffer, bufferLength);
+ if (buffer && LoadPlatformFont(buffer, bufferLength)) {
+ // LoadPlatformFont takes ownership of the buffer, so no need
+ // to free it here.
+ SetLoadState(STATUS_LOADED);
+ return;
+ } else {
+ mFontSet->LogMessage(this,
+ "font load failed",
+ nsIScriptError::errorFlag);
+ }
+ }
+
mSrcIndex++;
}
if (mUnsupportedFormat) {
mFontSet->LogMessage(this, "no supported format found",
nsIScriptError::warningFlag);
}
@@ -572,32 +620,32 @@ gfxUserFontEntry::LoadPlatformFont(const
this, mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
#endif
}
// The downloaded data can now be discarded; the font entry is using the
// sanitized copy
- NS_Free((void*)aFontData);
+ moz_free((void*)aFontData);
return fe != nullptr;
}
void
gfxUserFontEntry::Load()
{
if (mUserFontLoadState == STATUS_NOT_LOADED) {
LoadNextSrc();
}
}
// This is called when a font download finishes.
// Ownership of aFontData passes in here, and the font set must
-// ensure that it is eventually deleted via NS_Free().
+// ensure that it is eventually deleted via moz_free().
bool
gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
uint32_t aLength,
nsresult aDownloadStatus)
{
// forget about the loader, as we no longer potentially need to cancel it
// if the entry is obsoleted
mLoader = nullptr;
@@ -648,17 +696,17 @@ gfxUserFontSet::~gfxUserFontSet()
{
gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
if (fp) {
fp->RemoveUserFontSet(this);
}
}
already_AddRefed<gfxUserFontEntry>
-gfxUserFontSet::FindOrCreateFontFace(
+gfxUserFontSet::FindOrCreateUserFontEntry(
const nsAString& aFamilyName,
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
uint32_t aWeight,
int32_t aStretch,
uint32_t aItalicStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
uint32_t aLanguageOverride,
gfxSparseBitSet* aUnicodeRanges)
@@ -675,19 +723,19 @@ gfxUserFontSet::FindOrCreateFontFace(
if (family) {
entry = FindExistingUserFontEntry(family, aFontFaceSrcList, aWeight,
aStretch, aItalicStyle,
aFeatureSettings, aLanguageOverride,
aUnicodeRanges);
}
if (!entry) {
- entry = CreateFontFace(aFontFaceSrcList, aWeight, aStretch,
- aItalicStyle, aFeatureSettings, aLanguageOverride,
- aUnicodeRanges);
+ entry = CreateUserFontEntry(aFontFaceSrcList, aWeight, aStretch,
+ aItalicStyle, aFeatureSettings,
+ aLanguageOverride, aUnicodeRanges);
entry->mFamilyName = aFamilyName;
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("userfonts (%p) created \"%s\" (%p) with style: %s weight: %d "
"stretch: %d",
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), entry.get(),
(aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
@@ -696,26 +744,25 @@ gfxUserFontSet::FindOrCreateFontFace(
}
#endif
}
return entry.forget();
}
already_AddRefed<gfxUserFontEntry>
-gfxUserFontSet::CreateFontFace(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+gfxUserFontSet::CreateUserFontEntry(
+ const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
uint32_t aWeight,
int32_t aStretch,
uint32_t aItalicStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
uint32_t aLanguageOverride,
gfxSparseBitSet* aUnicodeRanges)
{
- MOZ_ASSERT(aWeight != 0,
- "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
nsRefPtr<gfxUserFontEntry> userFontEntry =
new gfxUserFontEntry(this, aFontFaceSrcList, aWeight,
aStretch, aItalicStyle, aFeatureSettings,
aLanguageOverride, aUnicodeRanges);
return userFontEntry.forget();
}
@@ -751,18 +798,18 @@ gfxUserFontSet::FindExistingUserFontEntr
return existingUserFontEntry;
}
return nullptr;
}
void
-gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
- gfxUserFontEntry* aUserFontEntry)
+gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
+ gfxUserFontEntry* aUserFontEntry)
{
gfxUserFontFamily* family = GetFamily(aFamilyName);
family->AddFontEntry(aUserFontEntry);
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("userfonts (%p) added \"%s\" (%p)",
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry));
@@ -984,31 +1031,40 @@ gfxUserFontSet::UserFontCache::Entry::Ke
}
void
gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry* aFontEntry,
EntryPersistence aPersistence)
{
NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
"caching a font associated with no family yet");
+
+ gfxUserFontData* data = aFontEntry->mUserFontData;
+ if (data->mIsBuffer) {
+#ifdef DEBUG_USERFONT_CACHE
+ printf("userfontcache skipped fontentry with buffer source: %p\n",
+ aFontEntry);
+#endif
+ return;
+ }
+
if (!sUserFonts) {
sUserFonts = new nsTHashtable<Entry>;
nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService();
if (obs) {
Flusher* flusher = new Flusher;
obs->AddObserver(flusher, "cacheservice:empty-cache",
false);
obs->AddObserver(flusher, "last-pb-context-exited", false);
obs->AddObserver(flusher, "xpcom-shutdown", false);
}
}
- gfxUserFontData* data = aFontEntry->mUserFontData;
if (data->mLength) {
MOZ_ASSERT(aPersistence == kPersistent);
MOZ_ASSERT(!data->mPrivate);
sUserFonts->PutEntry(Key(data->mCRC32, data->mLength, aFontEntry,
data->mPrivate, aPersistence));
} else {
MOZ_ASSERT(aPersistence == kDiscardable);
// For data: URIs, the principal is ignored; anyone who has the same
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -14,74 +14,105 @@
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsURIHashKey.h"
class nsFontFaceLoader;
//#define DEBUG_USERFONT_CACHE
+class gfxFontFaceBufferSource
+{
+ NS_INLINE_DECL_REFCOUNTING(gfxFontFaceBufferSource)
+public:
+ virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) = 0;
+
+protected:
+ virtual ~gfxFontFaceBufferSource() {}
+};
+
// parsed CSS @font-face rule information
// lifetime: from when @font-face rule processed until font is loaded
struct gfxFontFaceSrc {
- bool mIsLocal; // url or local
+
+ enum SourceType {
+ eSourceType_Local,
+ eSourceType_URL,
+ eSourceType_Buffer
+ };
+
+ SourceType mSourceType;
// if url, whether to use the origin principal or not
bool mUseOriginPrincipal;
// format hint flags, union of all possible formats
// (e.g. TrueType, EOT, SVG, etc.)
// see FLAG_FORMAT_* enum values below
uint32_t mFormatFlags;
nsString mLocalName; // full font name if local
nsCOMPtr<nsIURI> mURI; // uri if url
nsCOMPtr<nsIURI> mReferrer; // referrer url if url
nsCOMPtr<nsIPrincipal> mOriginPrincipal; // principal if url
+
+ nsRefPtr<gfxFontFaceBufferSource> mBuffer;
};
inline bool
operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b)
{
- bool equals;
- return (a.mIsLocal && b.mIsLocal &&
- a.mLocalName == b.mLocalName) ||
- (!a.mIsLocal && !b.mIsLocal &&
- a.mUseOriginPrincipal == b.mUseOriginPrincipal &&
- a.mFormatFlags == b.mFormatFlags &&
- NS_SUCCEEDED(a.mURI->Equals(b.mURI, &equals)) && equals &&
- NS_SUCCEEDED(a.mReferrer->Equals(b.mReferrer, &equals)) && equals &&
- a.mOriginPrincipal->Equals(b.mOriginPrincipal));
+ if (a.mSourceType != b.mSourceType) {
+ return false;
+ }
+ switch (a.mSourceType) {
+ case gfxFontFaceSrc::eSourceType_Local:
+ return a.mLocalName == b.mLocalName;
+ case gfxFontFaceSrc::eSourceType_URL: {
+ bool equals;
+ return a.mUseOriginPrincipal == b.mUseOriginPrincipal &&
+ a.mFormatFlags == b.mFormatFlags &&
+ NS_SUCCEEDED(a.mURI->Equals(b.mURI, &equals)) && equals &&
+ NS_SUCCEEDED(a.mReferrer->Equals(b.mReferrer, &equals)) &&
+ equals &&
+ a.mOriginPrincipal->Equals(b.mOriginPrincipal);
+ }
+ case gfxFontFaceSrc::eSourceType_Buffer:
+ return a.mBuffer == b.mBuffer;
+ }
+ NS_WARNING("unexpected mSourceType");
+ return false;
}
// Subclassed to store platform-specific code cleaned out when font entry is
// deleted.
// Lifetime: from when platform font is created until it is deactivated.
// If the platform does not need to add any platform-specific code/data here,
// then the gfxUserFontSet will allocate a base gfxUserFontData and attach
// to the entry to track the basic user font info fields here.
class gfxUserFontData {
public:
gfxUserFontData()
: mSrcIndex(0), mFormat(0), mMetaOrigLen(0),
- mCRC32(0), mLength(0), mPrivate(false)
+ mCRC32(0), mLength(0), mPrivate(false), mIsBuffer(false)
{ }
virtual ~gfxUserFontData() { }
nsTArray<uint8_t> mMetadata; // woff metadata block (compressed), if any
nsCOMPtr<nsIURI> mURI; // URI of the source, if it was url()
nsCOMPtr<nsIPrincipal> mPrincipal; // principal for the download, if url()
nsString mLocalName; // font name used for the source, if local()
nsString mRealName; // original fullname from the font resource
uint32_t mSrcIndex; // index in the rule's source list
uint32_t mFormat; // format hint for the source used, if any
uint32_t mMetaOrigLen; // length needed to decompress metadata
uint32_t mCRC32; // Checksum
uint32_t mLength; // Font length
bool mPrivate; // whether font belongs to a private window
+ bool mIsBuffer; // whether the font source was a buffer
};
// initially contains a set of userfont font entry objects, replaced with
// platform/user fonts as downloaded
class gfxUserFontFamily : public gfxFontFamily {
public:
friend class gfxUserFontSet;
@@ -149,40 +180,40 @@ public:
// creates a font face without adding it to a particular family
// weight - [100, 900] (multiples of 100)
// stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
// italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
// language override = result of calling gfxFontStyle::ParseFontLanguageOverride
// TODO: support for unicode ranges not yet implemented
- already_AddRefed<gfxUserFontEntry> CreateFontFace(
+ virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
uint32_t aWeight,
int32_t aStretch,
uint32_t aItalicStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
uint32_t aLanguageOverride,
- gfxSparseBitSet* aUnicodeRanges);
+ gfxSparseBitSet* aUnicodeRanges) = 0;
// creates a font face for the specified family, or returns an existing
// matching entry on the family if there is one
- already_AddRefed<gfxUserFontEntry> FindOrCreateFontFace(
+ already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
const nsAString& aFamilyName,
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
uint32_t aWeight,
int32_t aStretch,
uint32_t aItalicStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
uint32_t aLanguageOverride,
gfxSparseBitSet* aUnicodeRanges);
// add in a font face for which we have the gfxUserFontEntry already
- void AddFontFace(const nsAString& aFamilyName,
- gfxUserFontEntry* aUserFontEntry);
+ void AddUserFontEntry(const nsAString& aFamilyName,
+ gfxUserFontEntry* aUserFontEntry);
// Whether there is a face with this family name
bool HasFamily(const nsAString& aFamilyName) const
{
return LookupFamily(aFamilyName) != nullptr;
}
// Look up and return the gfxUserFontFamily in mFontFamilies with
@@ -438,17 +469,17 @@ protected:
virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
const char* aMessage,
uint32_t aFlags = nsIScriptError::errorFlag,
nsresult aStatus = NS_OK) = 0;
// helper method for performing the actual userfont set rebuild
virtual void DoRebuildUserFontSet() = 0;
- // helper method for FindOrCreateFontFace
+ // helper method for FindOrCreateUserFontEntry
gfxUserFontEntry* FindExistingUserFontEntry(
gfxUserFontFamily* aFamily,
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
uint32_t aWeight,
int32_t aStretch,
uint32_t aItalicStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
uint32_t aLanguageOverride,
@@ -519,27 +550,36 @@ public:
return mUserFontLoadState == STATUS_LOADING &&
mFontDataLoadingState < LOADING_SLOWLY;
}
// load the font - starts the loading of sources which continues until
// a valid font resource is found or all sources fail
void Load();
+ // methods to expose some information to FontFaceSet::UserFontSet
+ // since we can't make that class a friend
+ void SetLoader(nsFontFaceLoader* aLoader) { mLoader = aLoader; }
+ nsFontFaceLoader* GetLoader() { return mLoader; }
+ nsIPrincipal* GetPrincipal() { return mPrincipal; }
+ uint32_t GetSrcIndex() { return mSrcIndex; }
+ void GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
+ nsACString& aURI);
+
protected:
const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
uint32_t aLength,
uint32_t& aSaneLength,
bool aIsCompressed);
// attempt to load the next resource in the src list.
void LoadNextSrc();
// change the load state
- void SetLoadState(UserFontLoadState aLoadState);
+ virtual void SetLoadState(UserFontLoadState aLoadState);
// when download has been completed, pass back data here
// aDownloadStatus == NS_OK ==> download succeeded, error otherwise
// returns true if platform font creation sucessful (or local()
// reference was next in line)
// Ownership of aFontData is passed in here; the font set must
// ensure that it is eventually deleted with NS_Free().
bool FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength,
--- a/image/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -17,26 +17,36 @@
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIMIMEService.h"
#include "nsCExternalHandlerService.h"
#include "nsILocalFileMac.h"
#include "nsIFileURL.h"
#include "nsTArray.h"
#include "nsObjCExceptions.h"
+#include "nsProxyRelease.h"
#include <Cocoa/Cocoa.h>
// nsIconChannel methods
nsIconChannel::nsIconChannel()
{
}
nsIconChannel::~nsIconChannel()
-{}
+{
+ if (mLoadInfo) {
+ nsCOMPtr<nsIThread> mainThread;
+ NS_GetMainThread(getter_AddRefs(mainThread));
+
+ nsILoadInfo *forgetableLoadInfo;
+ mLoadInfo.forget(&forgetableLoadInfo);
+ NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+ }
+}
NS_IMPL_ISUPPORTS(nsIconChannel,
nsIChannel,
nsIRequest,
nsIRequestObserver,
nsIStreamListener)
nsresult nsIconChannel::Init(nsIURI* uri)
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -18,16 +18,17 @@
#include "nsIStringStream.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIFile.h"
#include "nsIFileURL.h"
#include "nsIMIMEService.h"
#include "nsCExternalHandlerService.h"
#include "nsDirectoryServiceDefs.h"
+#include "nsProxyRelease.h"
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
// we need windows.h to read out registry information...
#include <windows.h>
@@ -62,17 +63,26 @@ static SHSTOCKICONID GetStockIconIDForNa
}
// nsIconChannel methods
nsIconChannel::nsIconChannel()
{
}
nsIconChannel::~nsIconChannel()
-{}
+{
+ if (mLoadInfo) {
+ nsCOMPtr<nsIThread> mainThread;
+ NS_GetMainThread(getter_AddRefs(mainThread));
+
+ nsILoadInfo *forgetableLoadInfo;
+ mLoadInfo.forget(&forgetableLoadInfo);
+ NS_ProxyRelease(mainThread, forgetableLoadInfo, false);
+ }
+}
NS_IMPL_ISUPPORTS(nsIconChannel,
nsIChannel,
nsIRequest,
nsIRequestObserver,
nsIStreamListener)
nsresult nsIconChannel::Init(nsIURI* uri)
--- a/ipc/glue/ProcessUtils_linux.cpp
+++ b/ipc/glue/ProcessUtils_linux.cpp
@@ -112,70 +112,64 @@ static void ProcLoaderClientDeinit();
* starting from kBeginReserveFileDescriptor so that operations like
* __android_log_print() won't take these magic FDs.
*/
static const int kReservedFileDescriptors = 5;
static const int kBeginReserveFileDescriptor = STDERR_FILENO + 1;
class ProcLoaderParent : public PProcLoaderParent
{
-private:
- nsAutoPtr<FileDescriptor> mChannelFd; // To keep a reference.
-
public:
- ProcLoaderParent(FileDescriptor *aFd) : mChannelFd(aFd) {}
+ ProcLoaderParent() {}
+ virtual ~ProcLoaderParent() {}
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool RecvLoadComplete(const int32_t &aPid,
const int32_t &aCookie) MOZ_OVERRIDE;
-
- virtual void OnChannelError() MOZ_OVERRIDE;
};
void
ProcLoaderParent::ActorDestroy(ActorDestroyReason aWhy)
{
+ if (aWhy == AbnormalShutdown) {
+ NS_WARNING("ProcLoaderParent is destroyed abnormally.");
+ }
+
+ if (sProcLoaderClientOnDeinit) {
+ // Get error for closing while the channel is already error.
+ return;
+ }
+
+ // Destroy self asynchronously.
+ ProcLoaderClientDeinit();
}
static void
_ProcLoaderParentDestroy(PProcLoaderParent *aLoader)
{
- aLoader->Close();
delete aLoader;
sProcLoaderClientOnDeinit = false;
}
bool
ProcLoaderParent::RecvLoadComplete(const int32_t &aPid,
const int32_t &aCookie)
{
- ProcLoaderClientDeinit();
return true;
}
static void
CloseFileDescriptors(FdArray& aFds)
{
for (size_t i = 0; i < aFds.length(); i++) {
unused << HANDLE_EINTR(close(aFds[i]));
}
}
-void
-ProcLoaderParent::OnChannelError()
-{
- if (sProcLoaderClientOnDeinit) {
- // Get error for closing while the channel is already error.
- return;
- }
- NS_WARNING("ProcLoaderParent is in channel error");
- ProcLoaderClientDeinit();
-}
-
/**
* Initialize the client of B2G loader for loader itself.
*
* The initialization of B2G loader are divided into two stages. First
* stage is to collect child info passed from the main program of the
* loader. Second stage is to initialize Gecko according to info from the
* first stage and make the client of loader service ready.
*
@@ -199,21 +193,21 @@ void
ProcLoaderClientGeckoInit()
{
MOZ_ASSERT(sProcLoaderClientInitialized, "call ProcLoaderClientInit() at first");
MOZ_ASSERT(!sProcLoaderClientGeckoInitialized,
"call ProcLoaderClientGeckoInit() more than once");
sProcLoaderClientGeckoInitialized = true;
- FileDescriptor *fd = new FileDescriptor(sProcLoaderChannelFd);
- close(sProcLoaderChannelFd);
+ TransportDescriptor fd;
+ fd.mFd = base::FileDescriptor(sProcLoaderChannelFd, /*auto_close=*/ false);
sProcLoaderChannelFd = -1;
- Transport *transport = OpenDescriptor(*fd, Transport::MODE_CLIENT);
- sProcLoaderParent = new ProcLoaderParent(fd);
+ Transport *transport = OpenDescriptor(fd, Transport::MODE_CLIENT);
+ sProcLoaderParent = new ProcLoaderParent();
sProcLoaderParent->Open(transport,
sProcLoaderPid,
XRE_GetIOMessageLoop(),
ParentSide);
sProcLoaderLoop = MessageLoop::current();
}
/**
@@ -543,18 +537,18 @@ ProcLoaderServiceRun(pid_t aPeerPid, int
gArgc = aArgc;
{
nsresult rv = XRE_InitCommandLine(aArgc, _argv);
if (NS_FAILED(rv)) {
MOZ_CRASH();
}
- FileDescriptor fd(aFd);
- close(aFd);
+ TransportDescriptor fd;
+ fd.mFd = base::FileDescriptor(aFd, /*auto_close =*/false);
MOZ_ASSERT(!sProcLoaderServing);
MessageLoop loop;
nsAutoPtr<ContentProcess> process;
process = new ContentProcess(aPeerPid);
ChildThread *iothread = process->child_thread();
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -269,17 +269,20 @@ class Node {
}
template<typename T>
Node &operator=(const Rooted<T *> &root) {
construct(root.get());
return *this;
}
// Constructors accepting SpiderMonkey's other generic-pointer-ish types.
- explicit Node(JS::HandleValue value);
+ // Note that we *do* want an implicit constructor here: JS::Value and
+ // JS::ubi::Node are both essentially tagged references to other sorts of
+ // objects, so letting conversions happen automatically is appropriate.
+ MOZ_IMPLICIT Node(JS::HandleValue value);
Node(JSGCTraceKind kind, void *ptr);
// copy construction and copy assignment just use memcpy, since we know
// instances contain nothing but a vtable pointer and a data pointer.
//
// To be completely correct, concrete classes could provide a virtual
// 'construct' member function, which we could invoke on rhs to construct an
// instance in our storage. But this is good enough; there's no need to jump
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2064,17 +2064,17 @@ IsSimdAvailable(JSContext *cx, unsigned
return true;
}
static bool
ByteSize(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
mozilla::MallocSizeOf mallocSizeOf = cx->runtime()->debuggerMallocSizeOf;
- JS::ubi::Node node(args.get(0));
+ JS::ubi::Node node = args.get(0);
if (node)
args.rval().set(NumberValue(node.size(mallocSizeOf)));
else
args.rval().setUndefined();
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
--- a/js/src/doc/Debugger/Debugger.Object.md
+++ b/js/src/doc/Debugger/Debugger.Object.md
@@ -151,16 +151,19 @@ from its prototype:
: If the referent is a function that is debuggee code, a
[`Debugger.Environment`][environment] instance representing the lexical
environment enclosing the function when it was created. If the referent
is a function proxy or not debuggee code, this is `undefined`.
`isBoundFunction`
: `true` if the referent is a bound function; `false` otherwise.
+`isArrowFunction`
+: `true` if the referent is an arrow function; `false` otherwise.
+
`boundTargetFunction`
: If the referent is a bound function, this is its target function—the
function that was bound to a particular `this` object. If the referent
is not a bound function, this is `undefined`.
`boundThis`
: If the referent is a bound function, this is the `this` value it was
bound to. If the referent is not a bound function, this is `undefined`.
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -139,18 +139,18 @@ static const size_t MAX_BACKGROUND_FINAL
class TenuredCell;
// A GC cell is the base class for all GC things.
struct Cell
{
public:
MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
- MOZ_ALWAYS_INLINE const TenuredCell *asTenured() const;
- MOZ_ALWAYS_INLINE TenuredCell *asTenured();
+ MOZ_ALWAYS_INLINE const TenuredCell &asTenured() const;
+ MOZ_ALWAYS_INLINE TenuredCell &asTenured();
inline JSRuntime *runtimeFromMainThread() const;
inline JS::shadow::Runtime *shadowRuntimeFromMainThread() const;
// Note: Unrestricted access to the runtime of a GC thing from an arbitrary
// thread can easily lead to races. Use this method very carefully.
inline JSRuntime *runtimeFromAnyThread() const;
inline JS::shadow::Runtime *shadowRuntimeFromAnyThread() const;
@@ -1141,28 +1141,28 @@ static void
AssertValidColor(const TenuredCell *thing, uint32_t color)
{
#ifdef DEBUG
ArenaHeader *aheader = thing->arenaHeader();
MOZ_ASSERT(color < aheader->getThingSize() / CellSize);
#endif
}
-MOZ_ALWAYS_INLINE const TenuredCell *
+MOZ_ALWAYS_INLINE const TenuredCell &
Cell::asTenured() const
{
MOZ_ASSERT(isTenured());
- return static_cast<const TenuredCell *>(this);
+ return *static_cast<const TenuredCell *>(this);
}
-MOZ_ALWAYS_INLINE TenuredCell *
+MOZ_ALWAYS_INLINE TenuredCell &
Cell::asTenured()
{
MOZ_ASSERT(isTenured());
- return static_cast<TenuredCell *>(this);
+ return *static_cast<TenuredCell *>(this);
}
inline JSRuntime *
Cell::runtimeFromMainThread() const
{
JSRuntime *rt = chunk()->info.trailer.runtime;
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
return rt;
@@ -1378,17 +1378,17 @@ TenuredCell::writeBarrierPostRemove(Tenu
}
#ifdef DEBUG
bool
Cell::isAligned() const
{
if (!isTenured())
return true;
- return asTenured()->isAligned();
+ return asTenured().isAligned();
}
bool
TenuredCell::isAligned() const
{
return Arena::isAligned(address(), arenaHeader()->getThingSize());
}
#endif
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -114,17 +114,17 @@ void
js::IterateGrayObjects(Zone *zone, GCThingCallback cellCallback, void *data)
{
zone->runtimeFromMainThread()->gc.evictNursery();
AutoPrepareForTracing prep(zone->runtimeFromMainThread(), SkipAtoms);
for (size_t finalizeKind = 0; finalizeKind <= FINALIZE_OBJECT_LAST; finalizeKind++) {
for (ZoneCellIterUnderGC i(zone, AllocKind(finalizeKind)); !i.done(); i.next()) {
JSObject *obj = i.get<JSObject>();
- if (obj->asTenured()->isMarked(GRAY))
+ if (obj->asTenured().isMarked(GRAY))
cellCallback(data, obj);
}
}
}
JS_PUBLIC_API(void)
JS_IterateCompartments(JSRuntime *rt, void *data,
JSIterateCompartmentCallback compartmentCallback)
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -225,17 +225,17 @@ CheckMarkedThing(JSTracer *trc, T **thin
/*
* Try to assert that the thing is allocated. This is complicated by the
* fact that allocated things may still contain the poison pattern if that
* part has not been overwritten, and that the free span list head in the
* ArenaHeader may not be synced with the real one in ArenaLists.
*/
MOZ_ASSERT_IF(IsThingPoisoned(thing) && rt->isHeapBusy(),
- !InFreeList(thing->asTenured()->arenaHeader(), thing));
+ !InFreeList(thing->asTenured().arenaHeader(), thing));
#endif
}
/*
* We only set the maybeAlive flag for objects and scripts. It's assumed that,
* if a compartment is alive, then it will have at least some live object or
* script it in. Even if we get this wrong, the worst that will happen is that
* scheduledForDestruction will be set on the compartment, which will cause some
@@ -445,24 +445,24 @@ IsMarked(T **thingp)
#endif
{
if (IsInsideNursery(*thingp)) {
Nursery &nursery = rt->gc.nursery;
return nursery.getForwardedPointer(thingp);
}
}
#endif // JSGC_GENERATIONAL
- Zone *zone = (*thingp)->asTenured()->zone();
+ Zone *zone = (*thingp)->asTenured().zone();
if (!zone->isCollecting() || zone->isGCFinished())
return true;
#ifdef JSGC_COMPACTING
if (zone->isGCCompacting() && IsForwarded(*thingp))
*thingp = Forwarded(*thingp);
#endif
- return (*thingp)->asTenured()->isMarked();
+ return (*thingp)->asTenured().isMarked();
}
template <typename T>
static bool
IsAboutToBeFinalized(T **thingp)
{
MOZ_ASSERT(thingp);
MOZ_ASSERT(*thingp);
@@ -490,29 +490,29 @@ IsAboutToBeFinalized(T **thingp)
if (rt->isHeapMinorCollecting()) {
if (IsInsideNursery(thing))
return !nursery.getForwardedPointer(thingp);
return false;
}
}
#endif // JSGC_GENERATIONAL
- Zone *zone = thing->asTenured()->zone();
+ Zone *zone = thing->asTenured().zone();
if (zone->isGCSweeping()) {
/*
* We should return false for things that have been allocated during
* incremental sweeping, but this possibility doesn't occur at the moment
* because this function is only called at the very start of the sweeping a
* compartment group and during minor gc. Rather than do the extra check,
* we just assert that it's not necessary.
*/
MOZ_ASSERT_IF(!rt->isHeapMinorCollecting(),
- !thing->asTenured()->arenaHeader()->allocatedDuringIncremental);
+ !thing->asTenured().arenaHeader()->allocatedDuringIncremental);
- return !thing->asTenured()->isMarked();
+ return !thing->asTenured().isMarked();
}
#ifdef JSGC_COMPACTING
else if (zone->isGCCompacting() && IsForwarded(thing)) {
*thingp = Forwarded(thing);
return false;
}
#endif
@@ -661,17 +661,17 @@ DeclMarkerImpl(TypeObject, js::types::Ty
void
gc::MarkKind(JSTracer *trc, void **thingp, JSGCTraceKind kind)
{
MOZ_ASSERT(thingp);
MOZ_ASSERT(*thingp);
DebugOnly<Cell *> cell = static_cast<Cell *>(*thingp);
MOZ_ASSERT_IF(cell->isTenured(),
- kind == MapAllocToTraceKind(cell->asTenured()->getAllocKind()));
+ kind == MapAllocToTraceKind(cell->asTenured().getAllocKind()));
switch (kind) {
case JSTRACE_OBJECT:
MarkInternal(trc, reinterpret_cast<JSObject **>(thingp));
break;
case JSTRACE_STRING:
MarkInternal(trc, reinterpret_cast<JSString **>(thingp));
break;
case JSTRACE_SYMBOL:
@@ -943,40 +943,40 @@ ShouldMarkCrossCompartment(JSTracer *trc
uint32_t color = AsGCMarker(trc)->getMarkColor();
MOZ_ASSERT(color == BLACK || color == GRAY);
if (IsInsideNursery(cell)) {
MOZ_ASSERT(color == BLACK);
return false;
}
- TenuredCell *tenured = cell->asTenured();
+ TenuredCell &tenured = cell->asTenured();
- JS::Zone *zone = tenured->zone();
+ JS::Zone *zone = tenured.zone();
if (color == BLACK) {
/*
* Having black->gray edges violates our promise to the cycle
* collector. This can happen if we're collecting a compartment and it
* has an edge to an uncollected compartment: it's possible that the
* source and destination of the cross-compartment edge should be gray,
* but the source was marked black by the conservative scanner.
*/
- if (tenured->isMarked(GRAY)) {
+ if (tenured.isMarked(GRAY)) {
MOZ_ASSERT(!zone->isCollecting());
trc->runtime()->gc.setFoundBlackGrayEdges();
}
return zone->isGCMarking();
} else {
if (zone->isGCMarkingBlack()) {
/*
* The destination compartment is being not being marked gray now,
* but it will be later, so record the cell so it can be marked gray
* at the appropriate time.
*/
- if (!tenured->isMarked())
+ if (!tenured.isMarked())
DelayCrossCompartmentGrayMarking(src);
return false;
}
return zone->isGCMarkingGray();
}
}
void
@@ -1036,17 +1036,17 @@ gc::IsCellAboutToBeFinalized(Cell **thin
JS_COMPARTMENT_ASSERT_STR(rt, sym)
static void
PushMarkStack(GCMarker *gcmarker, ObjectImpl *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
- if (thing->asTenured()->markIfUnmarked(gcmarker->getMarkColor()))
+ if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
/*
* PushMarkStack for BaseShape unpacks its children directly onto the mark
* stack. For a pre-barrier between incremental slices, this may result in
* objects in the nursery getting pushed onto the mark stack. It is safe to
* ignore these objects because they will be marked by the matching
@@ -1054,27 +1054,27 @@ PushMarkStack(GCMarker *gcmarker, Object
*/
static void
MaybePushMarkStackBetweenSlices(GCMarker *gcmarker, JSObject *thing)
{
DebugOnly<JSRuntime *> rt = gcmarker->runtime();
JS_COMPARTMENT_ASSERT(rt, thing);
MOZ_ASSERT_IF(rt->isHeapBusy(), !IsInsideNursery(thing));
- if (!IsInsideNursery(thing) && thing->asTenured()->markIfUnmarked(gcmarker->getMarkColor()))
+ if (!IsInsideNursery(thing) && thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
- if (thing->asTenured()->markIfUnmarked(gcmarker->getMarkColor()))
+ if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
@@ -1704,17 +1704,17 @@ GCMarker::processMarkStackTop(SliceBudge
MOZ_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == obj->zone());
if (str->markIfUnmarked())
ScanString(this, str);
}
} else if (v.isObject()) {
JSObject *obj2 = &v.toObject();
JS_COMPARTMENT_ASSERT(runtime(), obj2);
MOZ_ASSERT(obj->compartment() == obj2->compartment());
- if (obj2->asTenured()->markIfUnmarked(getMarkColor())) {
+ if (obj2->asTenured().markIfUnmarked(getMarkColor())) {
pushValueArray(obj, vp, end);
obj = obj2;
goto scan_obj;
}
} else if (v.isSymbol()) {
JS::Symbol *sym = v.toSymbol();
if (!sym->isWellKnownSymbol()) {
JS_COMPARTMENT_ASSERT_SYM(runtime(), sym);
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -582,17 +582,17 @@ GCMarker::markDelayedChildren(SliceBudge
}
#ifdef DEBUG
void
GCMarker::checkZone(void *p)
{
MOZ_ASSERT(started);
DebugOnly<Cell *> cell = static_cast<Cell *>(p);
- MOZ_ASSERT_IF(cell->isTenured(), cell->asTenured()->zone()->isCollecting());
+ MOZ_ASSERT_IF(cell->isTenured(), cell->asTenured().zone()->isCollecting());
}
#endif
bool
GCMarker::hasBufferedGrayRoots() const
{
return grayBufferState == GRAY_BUFFER_OK;
}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-isArrowFunction.js
@@ -0,0 +1,22 @@
+// Debugger.Object.prototype.isArrowFunction recognizes arrow functions.
+
+var g = newGlobal();
+var dbg = new Debugger;
+var gDO = dbg.addDebuggee(g);
+var hits = 0;
+
+function checkIsArrow(shouldBe, expr) {
+ print(expr);
+ assertEq(gDO.evalInGlobal(expr).return.isArrowFunction, shouldBe);
+}
+
+checkIsArrow(true, '() => { }');
+checkIsArrow(true, '(a) => { bleh; }');
+checkIsArrow(false, 'Object.getPrototypeOf(() => { })');
+checkIsArrow(false, '(function () { })');
+checkIsArrow(false, 'function f() { } f');
+checkIsArrow(false, '({})');
+checkIsArrow(false, 'Math.atan2');
+checkIsArrow(false, 'Function.prototype');
+checkIsArrow(false, 'Function("")');
+checkIsArrow(false, 'new Function("")');
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4006,17 +4006,17 @@ static const VMFunction NewGCThingParInf
bool
CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
Register tempReg1, Register tempReg2, JSObject *templateObj)
{
MOZ_ASSERT(lir->mirRaw());
MOZ_ASSERT(lir->mirRaw()->isInstruction());
- gc::AllocKind allocKind = templateObj->asTenured()->getAllocKind();
+ gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
#ifdef JSGC_FJGENERATIONAL
OutOfLineCode *ool = oolCallVM(NewGCThingParInfo, lir,
(ArgList(), Imm32(allocKind)), StoreRegisterTo(objReg));
if (!ool)
return false;
#else
OutOfLineNewGCThingPar *ool = new(alloc()) OutOfLineNewGCThingPar(lir, allocKind, objReg, cxReg);
if (!ool || !addOutOfLineCode(ool, lir->mirRaw()->toInstruction()))
@@ -4188,17 +4188,17 @@ typedef JSObject *(*NewGCObjectFn)(JSCon
gc::InitialHeap initialHeap);
static const VMFunction NewGCObjectInfo =
FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
bool
CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
{
JSObject *templateObject = lir->mir()->templateObject();
- gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+ gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
gc::InitialHeap initialHeap = lir->mir()->initialHeap();
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
OutOfLineCode *ool = oolCallVM(NewGCObjectInfo, lir,
(ArgList(), Imm32(allocKind), Imm32(initialHeap)),
StoreRegisterTo(objReg));
if (!ool)
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6772,17 +6772,17 @@ IonBuilder::ensureDefiniteTypeSet(MDefin
static size_t
NumFixedSlots(JSObject *object)
{
// Note: we can't use object->numFixedSlots() here, as this will read the
// shape and can race with the main thread if we are building off thread.
// The allocation kind and object class (which goes through the type) can
// be read freely, however.
- gc::AllocKind kind = object->asTenured()->getAllocKind();
+ gc::AllocKind kind = object->asTenured().getAllocKind();
return gc::GetGCKindSlots(kind, object->getClass());
}
bool
IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded,
MDefinition *lexicalCheck)
{
jsid id = NameToId(name);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -590,28 +590,28 @@ void
MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail)
{
// This method does not initialize the object: if external slots get
// allocated into |temp|, there is no easy way for us to ensure the caller
// frees them. Instead just assert this case does not happen.
MOZ_ASSERT(!templateObj->numDynamicSlots());
- gc::AllocKind allocKind = templateObj->asTenured()->getAllocKind();
+ gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
allocateObject(result, temp, allocKind, templateObj->numDynamicSlots(), initialHeap, fail);
}
void
MacroAssembler::createGCObject(Register obj, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots)
{
uint32_t nDynamicSlots = templateObj->numDynamicSlots();
- gc::AllocKind allocKind = templateObj->asTenured()->getAllocKind();
+ gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
// Arrays with copy on write elements do not need fixed space for an
// elements header. The template object, which owns the original elements,
// might have another allocation kind.
if (templateObj->denseElementsAreCopyOnWrite())
allocKind = gc::FINALIZE_OBJECT0_BACKGROUND;
@@ -731,17 +731,17 @@ MacroAssembler::newGCTenuredThingPar(Reg
// tempReg1->head.first = tempReg2;
storePtr(tempReg2, Address(tempReg1, gc::FreeList::offsetOfFirst()));
}
void
MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
JSObject *templateObject, Label *fail)
{
- gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+ gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
MOZ_ASSERT(!templateObject->numDynamicSlots());
newGCThingPar(result, cx, tempReg1, tempReg2, allocKind, fail);
}
void
MacroAssembler::newGCStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3239,17 +3239,17 @@ MObjectState::Copy(TempAllocator &alloc,
}
bool
MNewArray::shouldUseVM() const
{
MOZ_ASSERT(count() < JSObject::NELEMENTS_LIMIT);
size_t arraySlots =
- gc::GetGCKindSlots(templateObject()->asTenured()->getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
+ gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
// Allocate space using the VMCall when mir hints it needs to get allocated
// immediately, but only when data doesn't fit the available array slots.
bool allocating = allocatingBehaviour() != NewArray_Unallocating && count() > arraySlots;
return templateObject()->hasSingletonType() || allocating;
}
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1115,17 +1115,17 @@ RCreateThisWithTemplate::recover(JSConte
{
RootedObject templateObject(cx, &iter.read().toObject());
// Use AutoEnterAnalysis to avoid invoking the object metadata callback
// while bailing out, which could try to walk the stack.
types::AutoEnterAnalysis enter(cx);
// See CodeGenerator::visitCreateThisWithTemplate
- gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+ gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
gc::InitialHeap initialHeap = tenuredHeap_ ? gc::TenuredHeap : gc::DefaultHeap;
JSObject *resultObject = JSObject::copy(cx, allocKind, initialHeap, templateObject);
if (!resultObject)
return false;
RootedValue result(cx);
result.setObject(*resultObject);
iter.storeInstructionResult(result);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1127,19 +1127,19 @@ AssertValidObjectPtr(JSContext *cx, JSOb
MOZ_ASSERT(obj->compartment() == cx->compartment());
MOZ_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
MOZ_ASSERT_IF(!obj->hasLazyType(),
obj->type()->clasp() == obj->lastProperty()->getObjectClass());
if (obj->isTenured()) {
MOZ_ASSERT(obj->isAligned());
- gc::AllocKind kind = obj->asTenured()->getAllocKind();
+ gc::AllocKind kind = obj->asTenured().getAllocKind();
MOZ_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
- MOZ_ASSERT(obj->asTenured()->zone() == cx->zone());
+ MOZ_ASSERT(obj->asTenured().zone() == cx->zone());
}
}
void
AssertValidStringPtr(JSContext *cx, JSString *str)
{
// We can't closely inspect strings from another runtime.
if (str->runtimeFromAnyThread() != cx->runtime()) {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -647,17 +647,17 @@ js::GCThingTraceKind(void *thing)
}
JS_FRIEND_API(void)
js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure)
{
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
gc::Cell *thing = e.front().key().wrapped;
- if (thing->isTenured() && thing->asTenured()->isMarked(gc::GRAY))
+ if (thing->isTenured() && thing->asTenured().isMarked(gc::GRAY))
callback(closure, thing);
}
}
}
JS_FRIEND_API(JSObject *)
js::GetWeakmapKeyDelegate(JSObject *key)
{
@@ -1184,17 +1184,17 @@ JS::IncrementalReferenceBarrier(void *pt
if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast<JSString *>(ptr)))
return;
gc::Cell *cell = static_cast<gc::Cell *>(ptr);
#ifdef DEBUG
Zone *zone = kind == JSTRACE_OBJECT
? static_cast<JSObject *>(cell)->zone()
- : cell->asTenured()->zone();
+ : cell->asTenured().zone();
MOZ_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting());
#endif
if (kind == JSTRACE_OBJECT)
JSObject::writeBarrierPre(static_cast<JSObject*>(cell));
else if (kind == JSTRACE_STRING)
JSString::writeBarrierPre(static_cast<JSString*>(cell));
else if (kind == JSTRACE_SYMBOL)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -456,17 +456,17 @@ class JSFunction : public JSObject
private:
inline js::FunctionExtended *toExtended();
inline const js::FunctionExtended *toExtended() const;
public:
inline bool isExtended() const {
JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
- MOZ_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (asTenured()->getAllocKind() == ExtendedFinalizeKind));
+ MOZ_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (asTenured().getAllocKind() == ExtendedFinalizeKind));
return !!(flags() & EXTENDED);
}
/*
* Accessors for data stored in extended functions. Use setExtendedSlot if
* the function has already been initialized. Otherwise use
* initExtendedSlot.
*/
@@ -479,17 +479,17 @@ class JSFunction : public JSObject
static bool setTypeForScriptedFunction(js::ExclusiveContext *cx, js::HandleFunction fun,
bool singleton = false);
/* GC support. */
js::gc::AllocKind getAllocKind() const {
js::gc::AllocKind kind = FinalizeKind;
if (isExtended())
kind = ExtendedFinalizeKind;
- MOZ_ASSERT_IF(isTenured(), kind == asTenured()->getAllocKind());
+ MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
return kind;
}
};
extern JSString *
fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent);
inline JSFunction::Flags
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -498,17 +498,17 @@ Arena::finalize(FreeOp *fop, AllocKind t
uintptr_t lastThing = thingsEnd() - thingSize;
FreeSpan newListHead;
FreeSpan *newListTail = &newListHead;
size_t nmarked = 0;
for (ArenaCellIterUnderFinalize i(&aheader); !i.done(); i.next()) {
T *t = i.get<T>();
- if (t->asTenured()->isMarked()) {
+ if (t->asTenured().isMarked()) {
uintptr_t thing = reinterpret_cast<uintptr_t>(t);
if (thing != firstThingOrSuccessorOfLastMarkedThing) {
// We just finished passing over one or more free things,
// so record a new FreeSpan.
newListTail->initBoundsUnchecked(firstThingOrSuccessorOfLastMarkedThing,
thing - thingSize);
newListTail = newListTail->nextSpanUnchecked();
}
@@ -4194,39 +4194,39 @@ DropStringWrappers(JSRuntime *rt)
*/
void
JSCompartment::findOutgoingEdges(ComponentFinder<JS::Zone> &finder)
{
for (js::WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
CrossCompartmentKey::Kind kind = e.front().key().kind;
MOZ_ASSERT(kind != CrossCompartmentKey::StringWrapper);
- TenuredCell *other = e.front().key().wrapped->asTenured();
+ TenuredCell &other = e.front().key().wrapped->asTenured();
if (kind == CrossCompartmentKey::ObjectWrapper) {
/*
* Add edge to wrapped object compartment if wrapped object is not
* marked black to indicate that wrapper compartment not be swept
* after wrapped compartment.
*/
- if (!other->isMarked(BLACK) || other->isMarked(GRAY)) {
- JS::Zone *w = other->zone();
+ if (!other.isMarked(BLACK) || other.isMarked(GRAY)) {
+ JS::Zone *w = other.zone();
if (w->isGCMarking())
finder.addEdgeTo(w);
}
} else {
MOZ_ASSERT(kind == CrossCompartmentKey::DebuggerScript ||
kind == CrossCompartmentKey::DebuggerSource ||
kind == CrossCompartmentKey::DebuggerObject ||
kind == CrossCompartmentKey::DebuggerEnvironment);
/*
* Add edge for debugger object wrappers, to ensure (in conjuction
* with call to Debugger::findCompartmentEdges below) that debugger
* and debuggee objects are always swept in the same group.
*/
- JS::Zone *w = other->zone();
+ JS::Zone *w = other.zone();
if (w->isGCMarking())
finder.addEdgeTo(w);
}
}
Debugger::findCompartmentEdges(zone(), finder);
}
@@ -4457,21 +4457,21 @@ MarkIncomingCrossCompartmentPointers(JSR
for (JSObject *src = c->gcIncomingGrayPointers;
src;
src = NextIncomingCrossCompartmentPointer(src, unlinkList))
{
JSObject *dst = CrossCompartmentPointerReferent(src);
MOZ_ASSERT(dst->compartment() == c);
if (color == GRAY) {
- if (IsObjectMarked(&src) && src->asTenured()->isMarked(GRAY))
+ if (IsObjectMarked(&src) && src->asTenured().isMarked(GRAY))
MarkGCThingUnbarriered(&rt->gc.marker, (void**)&dst,
"cross-compartment gray pointer");
} else {
- if (IsObjectMarked(&src) && !src->asTenured()->isMarked(GRAY))
+ if (IsObjectMarked(&src) && !src->asTenured().isMarked(GRAY))
MarkGCThingUnbarriered(&rt->gc.marker, (void**)&dst,
"cross-compartment black pointer");
}
}
if (unlinkList)
c->gcIncomingGrayPointers = nullptr;
}
@@ -6336,27 +6336,27 @@ AutoDisableProxyCheck::~AutoDisableProxy
{
gc.enableStrictProxyChecking();
}
JS_FRIEND_API(void)
JS::AssertGCThingMustBeTenured(JSObject *obj)
{
MOZ_ASSERT(obj->isTenured() &&
- (!IsNurseryAllocable(obj->asTenured()->getAllocKind()) || obj->getClass()->finalize));
+ (!IsNurseryAllocable(obj->asTenured().getAllocKind()) || obj->getClass()->finalize));
}
JS_FRIEND_API(void)
js::gc::AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind)
{
MOZ_ASSERT(cell);
if (IsInsideNursery(cell))
MOZ_ASSERT(kind == JSTRACE_OBJECT);
else
- MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured()->getAllocKind()) == kind);
+ MOZ_ASSERT(MapAllocToTraceKind(cell->asTenured().getAllocKind()) == kind);
}
JS_FRIEND_API(size_t)
JS::GetGCNumber()
{
JSRuntime *rt = js::TlsPerThreadData.get()->runtimeFromMainThread();
if (!rt)
return 0;
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -36,17 +36,17 @@ ThreadSafeContext::isThreadLocal(T thing
if (cx->nursery().isInsideNewspace(thing))
return true;
#endif
// Global invariant
MOZ_ASSERT(!IsInsideNursery(thing));
// The thing is not in the nursery, but is it in the private tenured area?
- if (allocator_->arenas.containsArena(runtime_, thing->asTenured()->arenaHeader()))
+ if (allocator_->arenas.containsArena(runtime_, thing->asTenured().arenaHeader()))
{
// GC should be suppressed in preparation for mutating thread local
// objects, as we don't want to trip any barriers.
MOZ_ASSERT(!thing->zoneFromAnyThread()->needsIncrementalBarrier());
MOZ_ASSERT(!thing->runtimeFromAnyThread()->needsIncrementalBarrier());
return true;
}
@@ -87,17 +87,17 @@ inline JSGCTraceKind
GetGCThingTraceKind(const void *thing)
{
MOZ_ASSERT(thing);
const Cell *cell = static_cast<const Cell *>(thing);
#ifdef JSGC_GENERATIONAL
if (IsInsideNursery(cell))
return JSTRACE_OBJECT;
#endif
- return MapAllocToTraceKind(cell->asTenured()->getAllocKind());
+ return MapAllocToTraceKind(cell->asTenured().getAllocKind());
}
inline void
GCRuntime::poke()
{
poked = true;
#ifdef JS_GC_ZEAL
@@ -541,17 +541,17 @@ static inline void
CheckIncrementalZoneState(ThreadSafeContext *cx, T *t)
{
#ifdef DEBUG
if (!cx->isJSContext())
return;
Zone *zone = cx->asJSContext()->zone();
MOZ_ASSERT_IF(t && zone->wasGCStarted() && (zone->isGCMarking() || zone->isGCSweeping()),
- t->asTenured()->arenaHeader()->allocatedDuringIncremental);
+ t->asTenured().arenaHeader()->allocatedDuringIncremental);
#endif
}
/*
* Allocate a new GC thing. After a successful allocation the caller must
* fully initialize the thing before calling any function that can potentially
* trigger GC. This will ensure that GC tracing never sees junk values stored
* in the partially initialized thing.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2050,17 +2050,17 @@ js::DeepCloneObjectLiteral(JSContext *cx
RootedValue v(cx);
RootedObject deepObj(cx);
if (obj->is<ArrayObject>()) {
clone = NewDenseUnallocatedArray(cx, obj->as<ArrayObject>().length(), nullptr, newKind);
} else {
// Object literals are tenured by default as holded by the JSScript.
MOZ_ASSERT(obj->isTenured());
- AllocKind kind = obj->asTenured()->getAllocKind();
+ AllocKind kind = obj->asTenured().getAllocKind();
Rooted<TypeObject*> typeObj(cx, obj->getType(cx));
if (!typeObj)
return nullptr;
RootedObject parent(cx, obj->getParent());
clone = NewObjectWithGivenProto(cx, &JSObject::class_, TaggedProto(typeObj->proto().toObject()),
parent, kind, newKind);
}
@@ -2158,17 +2158,17 @@ js::XDRObjectLiteral(XDRState<mode> *xdr
} else {
// Code the alloc kind of the object.
AllocKind kind;
{
if (mode == XDR_ENCODE) {
MOZ_ASSERT(obj->getClass() == &JSObject::class_);
MOZ_ASSERT(obj->isTenured());
- kind = obj->asTenured()->getAllocKind();
+ kind = obj->asTenured().getAllocKind();
}
if (!xdr->codeEnum32(&kind))
return false;
if (mode == XDR_DECODE)
obj.set(NewBuiltinClassInstance(cx, &JSObject::class_, kind, js::MaybeSingletonObject));
}
@@ -2356,17 +2356,17 @@ js::XDRObjectLiteral(XDRState<XDR_ENCODE
template bool
js::XDRObjectLiteral(XDRState<XDR_DECODE> *xdr, MutableHandleObject obj);
JSObject *
js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj)
{
if (srcObj->getClass() == &JSObject::class_) {
AllocKind kind = GetBackgroundAllocKind(GuessObjectGCKind(srcObj->numFixedSlots()));
- MOZ_ASSERT_IF(srcObj->isTenured(), kind == srcObj->asTenured()->getAllocKind());
+ MOZ_ASSERT_IF(srcObj->isTenured(), kind == srcObj->asTenured().getAllocKind());
JSObject *proto = cx->global()->getOrCreateObjectPrototype(cx);
if (!proto)
return nullptr;
Rooted<TypeObject*> typeObj(cx, cx->getNewType(&JSObject::class_, TaggedProto(proto)));
if (!typeObj)
return nullptr;
@@ -2386,17 +2386,17 @@ js::CloneObjectLiteral(JSContext *cx, Ha
RootedId id(cx);
RootedValue value(cx);
for (size_t i = 0; i < length; i++) {
// The only markable values in copy on write arrays are atoms, which
// can be freely copied between compartments.
value = srcObj->getDenseElement(i);
MOZ_ASSERT_IF(value.isMarkable(),
value.toGCThing()->isTenured() &&
- cx->runtime()->isAtomsZone(value.toGCThing()->asTenured()->zone()));
+ cx->runtime()->isAtomsZone(value.toGCThing()->asTenured().zone()));
id = INT_TO_JSID(i);
if (!JSObject::defineGeneric(cx, res, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
return nullptr;
}
if (!ObjectElements::MakeElementsCopyOnWrite(cx, res))
return nullptr;
@@ -2471,26 +2471,26 @@ JSObject::ReserveForTradeGuts(JSContext
* inline slots. The fixed slots will be updated in place during TradeGuts.
* Non-native objects need to be reshaped according to the new count.
*/
if (a->isNative()) {
if (!a->generateOwnShape(cx))
MOZ_CRASH();
} else {
reserved.newbshape = EmptyShape::getInitialShape(cx, aClass, aProto, a->getParent(), a->getMetadata(),
- b->asTenured()->getAllocKind());
+ b->asTenured().getAllocKind());
if (!reserved.newbshape)
MOZ_CRASH();
}
if (b->isNative()) {
if (!b->generateOwnShape(cx))
MOZ_CRASH();
} else {
reserved.newashape = EmptyShape::getInitialShape(cx, bClass, bProto, b->getParent(), b->getMetadata(),
- a->asTenured()->getAllocKind());
+ a->asTenured().getAllocKind());
if (!reserved.newashape)
MOZ_CRASH();
}
/* The avals/bvals vectors hold all original values from the objects. */
if (!reserved.avals.reserve(a->slotSpan()))
MOZ_CRASH();
@@ -2680,18 +2680,18 @@ JSObject::TradeGuts(JSContext *cx, JSObj
#endif
}
/* Use this method with extreme caution. It trades the guts of two objects. */
bool
JSObject::swap(JSContext *cx, HandleObject a, HandleObject b)
{
// Ensure swap doesn't cause a finalizer to not be run.
- MOZ_ASSERT(IsBackgroundFinalized(a->asTenured()->getAllocKind()) ==
- IsBackgroundFinalized(b->asTenured()->getAllocKind()));
+ MOZ_ASSERT(IsBackgroundFinalized(a->asTenured().getAllocKind()) ==
+ IsBackgroundFinalized(b->asTenured().getAllocKind()));
MOZ_ASSERT(a->compartment() == b->compartment());
unsigned r = NotifyGCPreSwap(a, b);
TradeGutsReserved reserved(cx);
if (!ReserveForTradeGuts(cx, a, b, reserved)) {
NotifyGCPostSwap(b, a, r);
return false;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -79,17 +79,17 @@ JSObject::unwatch(JSContext *cx, JS::Han
inline void
JSObject::finalize(js::FreeOp *fop)
{
js::probes::FinalizeObject(this);
#ifdef DEBUG
MOZ_ASSERT(isTenured());
- if (!IsBackgroundFinalized(asTenured()->getAllocKind())) {
+ if (!IsBackgroundFinalized(asTenured().getAllocKind())) {
/* Assert we're on the main thread. */
MOZ_ASSERT(CurrentThreadCanAccessRuntime(fop->runtime()));
}
#endif
const js::Class *clasp = getClass();
if (clasp->finalize)
clasp->finalize(fop, this);
@@ -1094,17 +1094,17 @@ NewObjectScriptedCall(JSContext *cx, Mut
static inline JSObject *
CopyInitializerObject(JSContext *cx, HandleObject baseobj, NewObjectKind newKind = GenericObject)
{
MOZ_ASSERT(baseobj->getClass() == &JSObject::class_);
MOZ_ASSERT(!baseobj->inDictionaryMode());
gc::AllocKind allocKind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
allocKind = gc::GetBackgroundAllocKind(allocKind);
- MOZ_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->asTenured()->getAllocKind());
+ MOZ_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->asTenured().getAllocKind());
RootedObject obj(cx);
obj = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind);
if (!obj)
return nullptr;
RootedObject metadata(cx, obj->getMetadata());
RootedShape lastProp(cx, baseobj->lastProperty());
if (!JSObject::setLastProperty(cx, obj, lastProp))
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2911,17 +2911,17 @@ Rebase(JSScript *dst, JSScript *src, T *
JSScript *
js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
NewObjectKind newKind /* = GenericObject */)
{
/* NB: Keep this in sync with XDRScript. */
/* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
- MOZ_ASSERT(!src->sourceObject()->asTenured()->isMarked(gc::GRAY));
+ MOZ_ASSERT(!src->sourceObject()->asTenured().isMarked(gc::GRAY));
uint32_t nconsts = src->hasConsts() ? src->consts()->length : 0;
uint32_t nobjects = src->hasObjects() ? src->objects()->length : 0;
uint32_t nregexps = src->hasRegexps() ? src->regexps()->length : 0;
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
/* Script data */
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -175,17 +175,17 @@ ObjectValueMap::findZoneEdges()
* For unmarked weakmap keys with delegates in a different zone, add a zone
* edge to ensure that the delegate zone does finish marking after the key
* zone.
*/
JS::AutoSuppressGCAnalysis nogc;
Zone *mapZone = compartment->zone();
for (Range r = all(); !r.empty(); r.popFront()) {
JSObject *key = r.front().key();
- if (key->asTenured()->isMarked(BLACK) && !key->asTenured()->isMarked(GRAY))
+ if (key->asTenured().isMarked(BLACK) && !key->asTenured().isMarked(GRAY))
continue;
JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp;
if (!op)
continue;
JSObject *delegate = op(key);
if (!delegate)
continue;
Zone *delegateZone = delegate->zone();
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -160,10 +160,10 @@ bool Wrapper::finalizeInBackground(Value
* Make the 'background-finalized-ness' of the wrapper the same as the
* wrapped object, to allow transplanting between them.
*
* If the wrapped object is in the nursery then we know it doesn't have a
* finalizer, and so background finalization is ok.
*/
if (IsInsideNursery(&priv.toObject()))
return true;
- return IsBackgroundFinalized(priv.toObject().asTenured()->getAllocKind());
+ return IsBackgroundFinalized(priv.toObject().asTenured().getAllocKind());
}
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -5283,16 +5283,26 @@ DebuggerObject_getEnvironment(JSContext
if (!env)
return false;
}
return dbg->wrapEnvironment(cx, env, args.rval());
}
static bool
+DebuggerObject_getIsArrowFunction(JSContext *cx, unsigned argc, Value *vp)
+{
+ THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get isArrowFunction", args, refobj);
+
+ args.rval().setBoolean(refobj->is<JSFunction>()
+ && refobj->as<JSFunction>().isArrow());
+ return true;
+}
+
+static bool
DebuggerObject_getIsBoundFunction(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get isBoundFunction", args, refobj);
args.rval().setBoolean(refobj->isBoundFunction());
return true;
}
@@ -5862,16 +5872,17 @@ static const JSPropertySpec DebuggerObje
JS_PSG("proto", DebuggerObject_getProto, 0),
JS_PSG("class", DebuggerObject_getClass, 0),
JS_PSG("callable", DebuggerObject_getCallable, 0),
JS_PSG("name", DebuggerObject_getName, 0),
JS_PSG("displayName", DebuggerObject_getDisplayName, 0),
JS_PSG("parameterNames", DebuggerObject_getParameterNames, 0),
JS_PSG("script", DebuggerObject_getScript, 0),
JS_PSG("environment", DebuggerObject_getEnvironment, 0),
+ JS_PSG("isArrowFunction", DebuggerObject_getIsArrowFunction, 0),
JS_PSG("isBoundFunction", DebuggerObject_getIsBoundFunction, 0),
JS_PSG("boundTargetFunction", DebuggerObject_getBoundTargetFunction, 0),
JS_PSG("boundThis", DebuggerObject_getBoundThis, 0),
JS_PSG("boundArguments", DebuggerObject_getBoundArguments, 0),
JS_PSG("global", DebuggerObject_getGlobal, 0),
JS_PSG("allocationSite", DebuggerObject_getAllocationSite, 0),
JS_PS_END
};
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -819,17 +819,17 @@ class ObjectImpl : public gc::Cell
* capacity is not stored explicitly, and the allocated size of the slot
* array is kept in sync with this count.
*/
static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp);
/* Memory usage functions. */
size_t tenuredSizeOfThis() const {
MOZ_ASSERT(isTenured());
- return js::gc::Arena::thingSize(asTenured()->getAllocKind());
+ return js::gc::Arena::thingSize(asTenured().getAllocKind());
}
/* Elements accessors. */
ObjectElements * getElementsHeader() const {
return ObjectElements::fromElements(elements);
}
@@ -979,24 +979,24 @@ class ObjectImpl : public gc::Cell
static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
};
/* static */ MOZ_ALWAYS_INLINE void
ObjectImpl::readBarrier(ObjectImpl *obj)
{
if (!isNullLike(obj) && obj->isTenured())
- obj->asTenured()->readBarrier(obj->asTenured());
+ obj->asTenured().readBarrier(&obj->asTenured());
}
/* static */ MOZ_ALWAYS_INLINE void
ObjectImpl::writeBarrierPre(ObjectImpl *obj)
{
if (!isNullLike(obj) && obj->isTenured())
- obj->asTenured()->writeBarrierPre(obj->asTenured());
+ obj->asTenured().writeBarrierPre(&obj->asTenured());
}
/* static */ MOZ_ALWAYS_INLINE void
ObjectImpl::writeBarrierPost(ObjectImpl *obj, void *cellp)
{
MOZ_ASSERT(cellp);
#ifdef JSGC_GENERATIONAL
if (IsNullTaggedPointer(obj))
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -247,17 +247,17 @@ RegExpObject::trace(JSTracer *trc, JSObj
// be collected. To detect this we need to test all the following
// conditions, since:
// 1. During TraceRuntime, isHeapBusy() is true, but the tracer might not
// be a marking tracer.
// 2. When a write barrier executes, IS_GC_MARKING_TRACER is true, but
// isHeapBusy() will be false.
if (trc->runtime()->isHeapBusy() &&
IS_GC_MARKING_TRACER(trc) &&
- !obj->asTenured()->zone()->isPreservingCode())
+ !obj->asTenured().zone()->isPreservingCode())
{
obj->setPrivate(nullptr);
} else {
shared->trace(trc);
}
}
const Class RegExpObject::class_ = {
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1284,17 +1284,17 @@ CloneObject(JSContext *cx, HandleObject
if (!str)
return nullptr;
clone = StringObject::create(cx, str);
} else if (selfHostedObject->is<ArrayObject>()) {
clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
} else {
MOZ_ASSERT(selfHostedObject->isNative());
clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), TaggedProto(nullptr), cx->global(),
- selfHostedObject->asTenured()->getAllocKind(),
+ selfHostedObject->asTenured().getAllocKind(),
SingletonObject);
}
if (!clone)
return nullptr;
if (!CloneProperties(cx, selfHostedObject, clone))
return nullptr;
return clone;
}
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -62,16 +62,17 @@ skip-if = buildapp == 'mulet'
[test_bug865948.xul]
[test_bug866823.xul]
[test_bug895340.xul]
[test_bug932906.xul]
[test_bug996069.xul]
[test_bug1041626.xul]
[test_bug1042436.xul]
[test_bug1050049.html]
+[test_bug1074863.html]
[test_xrayToJS.xul]
skip-if = buildapp == 'mulet'
[test_chrometoSource.xul]
skip-if = buildapp == 'mulet'
[test_cloneInto.xul]
[test_cows.xul]
skip-if = buildapp == 'mulet'
[test_discardSystemSource.xul]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_bug1074863.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1074863
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1074863</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1074863 **/
+ const Cu = Components.utils;
+ var sb = new Cu.Sandbox('http://www.example.com');
+ sb.namedCtor = Image;
+ ok(true, "Didn't assert");
+
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1074863">Mozilla Bug 1074863</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -109,16 +109,21 @@ WrapperFactory::WaiveXray(JSContext *cx,
// In general, we're trying to deprecate COWs incrementally as we introduce
// Xrays to the corresponding object types. But switching off COWs for certain
// things would be too tumultuous at present, so we punt on them for later.
static bool
ForceCOWBehavior(JSObject *obj)
{
JSProtoKey key = IdentifyStandardInstanceOrPrototype(obj);
+ if (key == JSProto_Function && GetXrayType(obj) == XrayForDOMObject) {
+ // This means that we've got a DOM constructor, which we never want to
+ // expose COW-style.
+ return false;
+ }
if (key == JSProto_Object || key == JSProto_Array || key == JSProto_Function) {
MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject,
"We should use XrayWrappers for standard ES Object, Array, and Function "
"instances modulo this hack");
return true;
}
return false;
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -277,17 +277,17 @@ ActiveLayerTracker::IsStyleAnimated(nsIF
return true;
}
}
if (aProperty == eCSSProperty_transform && aFrame->Preserves3D()) {
return IsStyleAnimated(aFrame->GetParent(), aProperty);
}
nsIContent* content = aFrame->GetContent();
if (content) {
- return nsLayoutUtils::HasAnimations(content, aProperty);
+ return nsLayoutUtils::HasCurrentAnimationsForProperty(content, aProperty);
}
return false;
}
/* static */ bool
ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame)
{
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -235,16 +235,19 @@ public:
// CreateNeededFrames.
// Note: It's the caller's responsibility to make sure to wrap a
// ProcessPendingRestyles call in a view update batch and a script blocker.
// This function does not call ProcessAttachedQueue() on the binding manager.
// If the caller wants that to happen synchronously, it needs to handle that
// itself.
void ProcessPendingRestyles();
+ // Returns whether there are any pending restyles.
+ bool HasPendingRestyles() { return mPendingRestyles.Count() != 0; }
+
// ProcessPendingRestyles calls into one of our RestyleTracker
// objects. It then calls back to these functions at the beginning
// and end of its work.
void BeginProcessingRestyles();
void EndProcessingRestyles();
// Update styles for animations that are running on the compositor and
// whose updating is suppressed on the main thread (to save
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -90,16 +90,17 @@ class nsAccessibilityService;
namespace mozilla {
namespace a11y {
class DocAccessible;
} // namespace a11y
} // namespace mozilla
#endif
class nsIWidget;
struct nsArenaMemoryStats;
+class nsITimer;
typedef short SelectionType;
namespace mozilla {
class EventStates;
namespace dom {
class Element;
@@ -1606,16 +1607,19 @@ public:
bool IsNeverPainting() {
return mIsNeverPainting;
}
void SetNeverPainting(bool aNeverPainting) {
mIsNeverPainting = aNeverPainting;
}
+ bool HasPendingReflow() const
+ { return mReflowScheduled || mReflowContinueTimer; }
+
protected:
friend class nsRefreshDriver;
// IMPORTANT: The ownership implicit in the following member variables
// has been explicitly checked. If you add any members to this class,
// please make the ownership explicit (pinkerton, scc).
// These are the same Document and PresContext owned by the DocViewer.
@@ -1631,16 +1635,22 @@ protected:
// GetRootFrame() can be inlined:
nsFrameManagerBase* mFrameManager;
mozilla::WeakPtr<nsDocShell> mForwardingContainer;
nsRefreshDriver* mHiddenInvalidationObserverRefreshDriver;
#ifdef ACCESSIBILITY
mozilla::a11y::DocAccessible* mDocAccessible;
#endif
+ // At least on Win32 and Mac after interupting a reflow we need to post
+ // the resume reflow event off a timer to avoid event starvation because
+ // posted messages are processed before other messages when the modal
+ // moving/sizing loop is running, see bug 491700 for details.
+ nsCOMPtr<nsITimer> mReflowContinueTimer;
+
#ifdef DEBUG
nsIFrame* mDrawEventTargetFrame;
// Ensure that every allocation from the PresArena is eventually freed.
uint32_t mPresArenaAllocCount;
#endif
// Count of the number of times this presshell has been painted to a window.
uint64_t mPaintCount;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -389,28 +389,47 @@ nsLayoutUtils::HasAnimations(nsIContent*
return GetAnimationsOrTransitions(aContent, nsGkAtoms::animationsProperty,
aProperty) ||
GetAnimationsOrTransitions(aContent, nsGkAtoms::transitionsProperty,
aProperty);
}
bool
nsLayoutUtils::HasCurrentAnimations(nsIContent* aContent,
- nsIAtom* aAnimationProperty,
- nsPresContext* aPresContext)
+ nsIAtom* aAnimationProperty)
{
if (!aContent->MayHaveAnimations())
return false;
AnimationPlayerCollection* collection =
static_cast<AnimationPlayerCollection*>(
aContent->GetProperty(aAnimationProperty));
return (collection && collection->HasCurrentAnimations());
}
+bool
+nsLayoutUtils::HasCurrentAnimationsForProperty(nsIContent* aContent,
+ nsCSSProperty aProperty)
+{
+ if (!aContent->MayHaveAnimations())
+ return false;
+
+ static nsIAtom* const sAnimProps[] = { nsGkAtoms::transitionsProperty,
+ nsGkAtoms::animationsProperty,
+ nullptr };
+ for (nsIAtom* const* animProp = sAnimProps; *animProp; animProp++) {
+ AnimationPlayerCollection* collection =
+ static_cast<AnimationPlayerCollection*>(aContent->GetProperty(*animProp));
+ if (collection && collection->HasCurrentAnimationsForProperty(aProperty))
+ return true;
+ }
+
+ return false;
+}
+
static gfxSize
GetScaleForValue(const StyleAnimationValue& aValue, nsIFrame* aFrame)
{
if (!aFrame) {
NS_WARNING("No frame.");
return gfxSize();
}
if (aValue.GetUnit() != StyleAnimationValue::eUnit_Transform) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1874,23 +1874,30 @@ public:
/**
* Returns true if the content node has animations or transitions for the
* property.
*/
static bool HasAnimations(nsIContent* aContent, nsCSSProperty aProperty);
/**
- * Returns true if the content node has any current animations or transitions.
+ * Returns true if the content node has any current animations or transitions
+ * (depending on the value of |aAnimationProperty|).
* A current animation is any animation that has not yet finished playing
* including paused animations.
*/
static bool HasCurrentAnimations(nsIContent* aContent,
- nsIAtom* aAnimationProperty,
- nsPresContext* aPresContext);
+ nsIAtom* aAnimationProperty);
+
+ /**
+ * Returns true if the content node has any current animations or transitions
+ * for the specified property.
+ */
+ static bool HasCurrentAnimationsForProperty(nsIContent* aContent,
+ nsCSSProperty aProperty);
/**
* Checks if off-main-thread animations are enabled.
*/
static bool AreAsyncAnimationsEnabled();
/**
* Checks if we should warn about animations that can't be async
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -55,17 +55,17 @@
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/TabParent.h"
#include "nsRefreshDriver.h"
#include "Layers.h"
#include "nsIDOMEvent.h"
#include "gfxPrefs.h"
#include "nsIDOMChromeWindow.h"
#include "nsFrameLoader.h"
-
+#include "mozilla/dom/FontFaceSet.h"
#include "nsContentUtils.h"
#include "nsPIWindowRoot.h"
#include "mozilla/Preferences.h"
// Needed for Start/Stop of Image Animation
#include "imgIContainer.h"
#include "nsIImageLoadingContent.h"
@@ -232,18 +232,17 @@ nsPresContext::nsPresContext(nsIDocument
if (!IsDynamic()) {
mImageAnimationMode = imgIContainer::kDontAnimMode;
mNeverAnimate = true;
} else {
mImageAnimationMode = imgIContainer::kNormalAnimMode;
mNeverAnimate = false;
}
NS_ASSERTION(mDocument, "Null document");
- mUserFontSet = nullptr;
- mUserFontSetDirty = true;
+ mFontFaceSetDirty = true;
mCounterStylesDirty = true;
// if text perf logging enabled, init stats struct
PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
if (log && log->level >= PR_LOG_WARNING) {
mTextPerf = new gfxTextPerfMetrics();
}
@@ -1089,20 +1088,20 @@ nsPresContext::Init(nsDeviceContext* aDe
return NS_OK;
}
// Note: We don't hold a reference on the shell; it has a reference to
// us
void
nsPresContext::SetShell(nsIPresShell* aShell)
{
- if (mUserFontSet) {
+ if (mFontFaceSet) {
// Clear out user font set if we have one
- mUserFontSet->Destroy();
- NS_RELEASE(mUserFontSet);
+ mFontFaceSet->DestroyUserFontSet();
+ mFontFaceSet = nullptr;
}
if (mShell) {
// Remove ourselves as the charset observer from the shell's doc, because
// this shell may be going away for good.
nsIDocument *doc = mShell->GetDocument();
if (doc) {
doc->RemoveCharSetObserver(this);
@@ -2063,29 +2062,33 @@ nsPresContext::GetUserFontSetInternal()
// for somebody to call GetUserFontSet in order to rebuild it (see
// comments below in RebuildUserFontSet for why).
#ifdef DEBUG
bool userFontSetGottenBefore = mGetUserFontSetCalled;
#endif
// Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
// flush.
mGetUserFontSetCalled = true;
- if (mUserFontSetDirty) {
+ if (mFontFaceSetDirty) {
// If this assertion fails, and there have actually been changes to
// @font-face rules, then we will call StyleChangeReflow in
// FlushUserFontSet. If we're in the middle of reflow,
// that's a bad thing to do, and the caller was responsible for
// flushing first. If we're not (e.g., in frame construction), it's
// ok.
NS_ASSERTION(!userFontSetGottenBefore || !mShell->IsReflowLocked(),
"FlushUserFontSet should have been called first");
FlushUserFontSet();
}
- return mUserFontSet;
+ if (!mFontFaceSet) {
+ return nullptr;
+ }
+
+ return mFontFaceSet->GetUserFontSet();
}
gfxUserFontSet*
nsPresContext::GetUserFontSetExternal()
{
return GetUserFontSetInternal();
}
@@ -2093,71 +2096,57 @@ void
nsPresContext::FlushUserFontSet()
{
if (!mShell) {
return; // we've been torn down
}
if (!mGetUserFontSetCalled) {
return; // No one cares about this font set yet, but we want to be careful
- // to not unset our mUserFontSetDirty bit, so when someone really
+ // to not unset our mFontFaceSetDirty bit, so when someone really
// does we'll create it.
}
- if (mUserFontSetDirty) {
+ if (mFontFaceSetDirty) {
if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
nsTArray<nsFontFaceRuleContainer> rules;
if (!mShell->StyleSet()->AppendFontFaceRules(this, rules)) {
- if (mUserFontSet) {
- mUserFontSet->Destroy();
- NS_RELEASE(mUserFontSet);
- }
return;
}
- bool changed = false;
-
- if (rules.Length() == 0) {
- if (mUserFontSet) {
- mUserFontSet->Destroy();
- NS_RELEASE(mUserFontSet);
- changed = true;
- }
- } else {
- if (!mUserFontSet) {
- mUserFontSet = new nsUserFontSet(this);
- NS_ADDREF(mUserFontSet);
- }
- changed = mUserFontSet->UpdateRules(rules);
+ if (!mFontFaceSet) {
+ mFontFaceSet = new FontFaceSet(mDocument->GetInnerWindow(), this);
}
+ mFontFaceSet->EnsureUserFontSet(this);
+ bool changed = mFontFaceSet->UpdateRules(rules);
// We need to enqueue a style change reflow (for later) to
// reflect that we're modifying @font-face rules. (However,
// without a reflow, nothing will happen to start any downloads
// that are needed.)
if (changed) {
UserFontSetUpdated();
}
}
- mUserFontSetDirty = false;
+ mFontFaceSetDirty = false;
}
}
void
nsPresContext::RebuildUserFontSet()
{
if (!mGetUserFontSetCalled) {
// We want to lazily build the user font set the first time it's
// requested (so we don't force creation of rule cascades too
// early), so don't do anything now.
return;
}
- mUserFontSetDirty = true;
+ mFontFaceSetDirty = true;
mDocument->SetNeedStyleFlush();
// Somebody has already asked for the user font set, so we need to
// post an event to rebuild it. Setting the user font set to be dirty
// and lazily rebuilding it isn't sufficient, since it is only the act
// of rebuilding it that will trigger the style change reflow that
// calls GetUserFontSet. (This reflow causes rebuilding of text runs,
// which starts font loads, whose completion causes another style
@@ -2187,16 +2176,26 @@ nsPresContext::UserFontSetUpdated()
// 2. Changing the value of the 'ex' and 'ch' units in style data,
// which also depend on font metrics. Updating this information
// requires rebuilding the rule tree from the top, avoiding the
// reuse of cached data even when no style rules have changed.
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
}
+FontFaceSet*
+nsPresContext::Fonts()
+{
+ if (!mFontFaceSet) {
+ mFontFaceSet = new FontFaceSet(mDocument->GetInnerWindow(), this);
+ GetUserFontSet(); // this will cause the user font set to be created/updated
+ }
+ return mFontFaceSet;
+}
+
void
nsPresContext::FlushCounterStyles()
{
if (!mShell) {
return; // we've been torn down
}
if (mCounterStyleManager->IsInitial()) {
// Still in its initial state, no need to clean.
@@ -2643,16 +2642,31 @@ nsPresContext::HavePendingInputEvent()
}
}
return false;
}
}
}
void
+nsPresContext::NotifyFontFaceSetOnRefresh()
+{
+ if (mFontFaceSet) {
+ mFontFaceSet->DidRefresh();
+ }
+}
+
+bool
+nsPresContext::HasPendingRestyleOrReflow()
+{
+ return (mRestyleManager && mRestyleManager->HasPendingRestyles()) ||
+ PresShell()->HasPendingReflow();
+}
+
+void
nsPresContext::ReflowStarted(bool aInterruptible)
{
#ifdef NOISY_INTERRUPTIBLE_REFLOW
if (!aInterruptible) {
printf("STARTING NONINTERRUPTIBLE REFLOW\n");
}
#endif
// We don't support interrupting in paginated contexts, since page
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -53,30 +53,30 @@ class nsFrameManager;
class nsILinkHandler;
class nsIAtom;
class nsICSSPseudoComparator;
struct nsStyleBackground;
struct nsStyleBorder;
class nsIRunnable;
class gfxUserFontSet;
class gfxTextPerfMetrics;
-class nsUserFontSet;
struct nsFontFaceRuleContainer;
class nsPluginFrame;
class nsTransitionManager;
class nsAnimationManager;
class nsRefreshDriver;
class nsIWidget;
class nsDeviceContext;
namespace mozilla {
class EventStateManager;
class RestyleManager;
class CounterStyleManager;
namespace dom {
+class FontFaceSet;
class MediaQueryList;
}
namespace layers {
class ContainerLayer;
}
}
// supported values for cached bool types
@@ -866,16 +866,18 @@ public:
void FlushUserFontSet();
void RebuildUserFontSet(); // asynchronously
// Should be called whenever the set of fonts available in the user
// font set changes (e.g., because a new font loads, or because the
// user font set is changed and fonts become unavailable).
void UserFontSetUpdated();
+ mozilla::dom::FontFaceSet* Fonts();
+
void FlushCounterStyles();
void RebuildCounterStyles(); // asynchronously
// Ensure that it is safe to hand out CSS rules outside the layout
// engine by ensuring that all CSS style sheets have unique inners
// and, if necessary, synchronously rebuilding all style data.
void EnsureSafeToHandOutCSSRules();
@@ -916,16 +918,27 @@ public:
void SetProcessingAnimationStyleChange(bool aProcessing) {
NS_ASSERTION(aProcessing != bool(mProcessingAnimationStyleChange),
"should never nest");
mProcessingAnimationStyleChange = aProcessing;
}
/**
+ * Returns whether there are any pending restyles or reflows.
+ */
+ bool HasPendingRestyleOrReflow();
+
+ /**
+ * Informs the document's FontFaceSet that the refresh driver ticked,
+ * flushing style and layout.
+ */
+ void NotifyFontFaceSetOnRefresh();
+
+ /**
* Notify the prescontext that the presshell is about to reflow a reflow root.
* The single argument indicates whether this reflow should be interruptible.
* If aInterruptible is false then CheckForInterrupt and HasPendingInterrupt
* will always return false. If aInterruptible is true then CheckForInterrupt
* will return true when a pending event is detected. This is for use by the
* presshell only. Reflow code wanting to prevent interrupts should use
* InterruptPreventer.
*/
@@ -1242,17 +1255,17 @@ protected:
nsCOMPtr<nsITimer> mPrefChangedTimer;
FramePropertyTable mPropertyTable;
nsInvalidateRequestList mInvalidateRequestsSinceLastPaint;
nsInvalidateRequestList mUndeliveredInvalidateRequestsBeforeLastPaint;
// container for per-context fonts (downloadable, SVG, etc.)
- nsUserFontSet* mUserFontSet;
+ nsRefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
// text performance metrics
nsAutoPtr<gfxTextPerfMetrics> mTextPerf;
nsRect mVisibleArea;
nsSize mPageSize;
float mPageScale;
float mPPScale;
@@ -1323,18 +1336,18 @@ protected:
// Does the associated document use root-em (rem) units?
unsigned mUsesRootEMUnits : 1;
// Does the associated document use viewport units (vw/vh/vmin/vmax)?
unsigned mUsesViewportUnits : 1;
// Has there been a change to the viewport's dimensions?
unsigned mPendingViewportChange : 1;
- // Is the current mUserFontSet valid?
- unsigned mUserFontSetDirty : 1;
+ // Is the current mFontFaceSet valid?
+ unsigned mFontFaceSetDirty : 1;
// Has GetUserFontSet() been called?
unsigned mGetUserFontSetCalled : 1;
// Do we currently have an event posted to call FlushUserFontSet?
unsigned mPostedFlushUserFontSet : 1;
// Is the current mCounterStyleManager valid?
unsigned mCounterStylesDirty : 1;
// Do we currently have an event posted to call FlushCounterStyles?
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -773,22 +773,16 @@ protected:
nsRefPtr<mozilla::TouchCaret> mTouchCaret;
nsRefPtr<mozilla::SelectionCarets> mSelectionCarets;
// This timer controls painting suppression. Until it fires
// or all frames are constructed, we won't paint anything but
// our <body> background and scrollbars.
nsCOMPtr<nsITimer> mPaintSuppressionTimer;
- // At least on Win32 and Mac after interupting a reflow we need to post
- // the resume reflow event off a timer to avoid event starvation because
- // posted messages are processed before other messages when the modal
- // moving/sizing loop is running, see bug 491700 for details.
- nsCOMPtr<nsITimer> mReflowContinueTimer;
-
nsCOMPtr<nsITimer> mDelayedPaintTimer;
// The `performance.now()` value when we last started to process reflows.
DOMHighResTimeStamp mLastReflowStart;
mozilla::TimeStamp mLoadBegin; // used to time loads
// Information needed to properly handle scrolling content into view if the
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1236,16 +1236,23 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
profiler_tracing("Paint", "Styles", mStyleCause, TRACING_INTERVAL_START);
mStyleCause = nullptr;
}
NS_ADDREF(shell);
mStyleFlushObservers.RemoveElement(shell);
shell->GetPresContext()->RestyleManager()->mObservingRefreshDriver = false;
shell->FlushPendingNotifications(ChangesToFlush(Flush_Style, false));
+ // Inform the FontFaceSet that we ticked, so that it can resolve its
+ // ready promise if it needs to (though it might still be waiting on
+ // a layout flush).
+ nsPresContext* presContext = shell->GetPresContext();
+ if (presContext) {
+ presContext->NotifyFontFaceSetOnRefresh();
+ }
NS_RELEASE(shell);
if (docShell) {
docShell->AddProfileTimelineMarker("Styles", TRACING_INTERVAL_END);
}
}
if (tracingStyleFlush) {
@@ -1277,16 +1284,22 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
}
NS_ADDREF(shell);
mLayoutFlushObservers.RemoveElement(shell);
shell->mReflowScheduled = false;
shell->mSuppressInterruptibleReflows = false;
shell->FlushPendingNotifications(ChangesToFlush(Flush_InterruptibleLayout,
false));
+ // Inform the FontFaceSet that we ticked, so that it can resolve its
+ // ready promise if it needs to.
+ nsPresContext* presContext = shell->GetPresContext();
+ if (presContext) {
+ presContext->NotifyFontFaceSetOnRefresh();
+ }
NS_RELEASE(shell);
}
if (tracingLayoutFlush) {
profiler_tracing("Paint", "Reflow", TRACING_INTERVAL_END);
}
}
}
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -26,16 +26,17 @@
#include "nsListControlFrame.h"
#include "nsAutoPtr.h"
#include "nsStyleSet.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "nsLayoutUtils.h"
#include "nsDisplayList.h"
#include "nsITheme.h"
+#include "nsThemeConstants.h"
#include "nsRenderingContext.h"
#include "mozilla/Likely.h"
#include <algorithm>
#include "nsTextNode.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/EventStates.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/MouseEvents.h"
@@ -729,18 +730,21 @@ nsComboboxControlFrame::GetIntrinsicISiz
dropdownContentWidth = NSCoordSaturatingSubtract(dropdownContentWidth,
scrollbarWidth,
nscoord_MAX);
displayWidth = std::max(dropdownContentWidth, displayWidth);
}
// add room for the dropmarker button if there is one
- if (!IsThemed() || presContext->GetTheme()->ThemeNeedsComboboxDropmarker())
+ if ((!IsThemed() ||
+ presContext->GetTheme()->ThemeNeedsComboboxDropmarker()) &&
+ StyleDisplay()->mAppearance != NS_THEME_NONE) {
displayWidth += scrollbarWidth;
+ }
return displayWidth;
}
nscoord
nsComboboxControlFrame::GetMinISize(nsRenderingContext *aRenderingContext)
{
@@ -808,17 +812,18 @@ nsComboboxControlFrame::Reflow(nsPresCon
// it's released in its ReflowFinished / ReflowCallbackCanceled.
unused << resize.forget();
}
// Get the width of the vertical scrollbar. That will be the width of the
// dropdown button.
nscoord buttonWidth;
const nsStyleDisplay *disp = StyleDisplay();
- if (IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) {
+ if ((IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) ||
+ StyleDisplay()->mAppearance == NS_THEME_NONE) {
buttonWidth = 0;
}
else {
nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
NS_ASSERTION(scrollable, "List must be a scrollable frame");
buttonWidth = scrollable->GetNondisappearingScrollbarWidth(
PresContext(), aReflowState.rendContext);
if (buttonWidth > aReflowState.ComputedWidth()) {
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -18,16 +18,17 @@
#include "mozilla/BasicEvents.h"
#include "mozilla/EventStates.h"
#include "nsContentUtils.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentList.h"
#include "nsStyleSet.h"
#include "nsIDOMMutationEvent.h"
#include "nsThreadUtils.h"
+#include "mozilla/FloatingPoint.h"
#ifdef ACCESSIBILITY
#include "mozilla/a11y/AccTypes.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
@@ -767,17 +768,17 @@ nsNumberControlFrame::GetValueOfAnonText
// number format does not allow the ',' grouping separator. We can detect all
// the cases where we need to convert by seeing if the locale-specific
// parsing function understands the user input to mean the same thing as the
// HTML-5-conforming parsing function. If so, then we should return the value
// as-is to avoid normalization. Otherwise, we return the de-localized
// serialization.
ICUUtils::LanguageTagIterForContent langTagIter(mContent);
double value = ICUUtils::ParseNumber(aValue, langTagIter);
- if (NS_finite(value) &&
+ if (IsFinite(value) &&
value != HTMLInputElement::StringToDecimal(aValue).toDouble()) {
aValue.Truncate();
aValue.AppendFloat(value);
}
#endif
// else, we return whatever FromContent put into aValue (the number as typed
// in by the user)
}
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -16,16 +16,17 @@
#include "nsPlaceholderFrame.h"
#include "nsPresContext.h"
#include "nsRenderingContext.h"
#include "nsStyleContext.h"
#include "nsStyleUtil.h"
#include "prlog.h"
#include <algorithm>
#include "mozilla/LinkedList.h"
+#include "mozilla/FloatingPoint.h"
using namespace mozilla;
using namespace mozilla::layout;
// Convenience typedefs for helper classes that we forward-declare in .h file
// (so that nsFlexContainerFrame methods can use them as parameters):
typedef nsFlexContainerFrame::FlexItem FlexItem;
typedef nsFlexContainerFrame::FlexLine FlexLine;
@@ -2123,17 +2124,17 @@ FlexLine::ResolveFlexibleLengths(nscoord
float curWeight = item->GetWeight(isUsingFlexGrow);
float curFlexFactor = item->GetFlexFactor(isUsingFlexGrow);
MOZ_ASSERT(curWeight >= 0.0f, "weights are non-negative");
MOZ_ASSERT(curFlexFactor >= 0.0f, "flex factors are non-negative");
weightSum += curWeight;
flexFactorSum += curFlexFactor;
- if (NS_finite(weightSum)) {
+ if (IsFinite(weightSum)) {
if (curWeight == 0.0f) {
item->SetShareOfWeightSoFar(0.0f);
} else {
item->SetShareOfWeightSoFar(curWeight / weightSum);
}
} // else, the sum of weights overflows to infinity, in which
// case we don't bother with "SetShareOfWeightSoFar" since
// we know we won't use it. (instead, we'll just give every
@@ -2194,17 +2195,17 @@ FlexLine::ResolveFlexibleLengths(nscoord
MOZ_ASSERT(item,
"numUnfrozenItemsToBeSeen says items remain to be seen");
if (!item->IsFrozen()) {
numUnfrozenItemsToBeSeen--;
// To avoid rounding issues, we compute the change in size for this
// item, and then subtract it from the remaining available space.
nscoord sizeDelta = 0;
- if (NS_finite(weightSum)) {
+ if (IsFinite(weightSum)) {
float myShareOfRemainingSpace =
item->GetShareOfWeightSoFar();
MOZ_ASSERT(myShareOfRemainingSpace >= 0.0f &&
myShareOfRemainingSpace <= 1.0f,
"my share should be nonnegative fractional amount");
if (myShareOfRemainingSpace == 1.0f) {
--- a/layout/inspector/nsFontFace.cpp
+++ b/layout/inspector/nsFontFace.cpp
@@ -5,16 +5,20 @@
#include "nsFontFace.h"
#include "nsIDOMCSSFontFaceRule.h"
#include "nsCSSRules.h"
#include "gfxTextRun.h"
#include "gfxUserFontSet.h"
#include "nsFontFaceLoader.h"
#include "mozilla/gfx/2D.h"
#include "zlib.h"
+#include "mozilla/dom/FontFaceSet.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
nsFontFace::nsFontFace(gfxFontEntry* aFontEntry,
gfxFontGroup* aFontGroup,
uint8_t aMatchType)
: mFontEntry(aFontEntry),
mFontGroup(aFontGroup),
mMatchType(aMatchType)
{
@@ -83,20 +87,23 @@ nsFontFace::GetCSSFamilyName(nsAString &
/* readonly attribute nsIDOMCSSFontFaceRule rule; */
NS_IMETHODIMP
nsFontFace::GetRule(nsIDOMCSSFontFaceRule **aRule)
{
// check whether this font entry is associated with an @font-face rule
// in the relevant font group's user font set
nsCSSFontFaceRule* rule = nullptr;
if (mFontEntry->IsUserFont()) {
- nsUserFontSet* fontSet =
- static_cast<nsUserFontSet*>(mFontGroup->GetUserFontSet());
+ FontFaceSet::UserFontSet* fontSet =
+ static_cast<FontFaceSet::UserFontSet*>(mFontGroup->GetUserFontSet());
if (fontSet) {
- rule = fontSet->FindRuleForEntry(mFontEntry);
+ FontFaceSet* fontFaceSet = fontSet->GetFontFaceSet();
+ if (fontFaceSet) {
+ rule = fontFaceSet->FindRuleForEntry(mFontEntry);
+ }
}
}
NS_IF_ADDREF(*aRule = rule);
return NS_OK;
}
/* readonly attribute long srcIndex; */
--- a/layout/reftests/css-enabled/select/reftest.list
+++ b/layout/reftests/css-enabled/select/reftest.list
@@ -1,9 +1,9 @@
== select-fieldset-1.html select-fieldset-ref.html
-fails-if(Android||B2G) == select-fieldset-2.html select-fieldset-ref-disabled.html
-fails-if(Android||B2G) == select-fieldset-3.html select-fieldset-ref-disabled.html
+fails-if(B2G) == select-fieldset-2.html select-fieldset-ref-disabled.html
+fails-if(B2G) == select-fieldset-3.html select-fieldset-ref-disabled.html
== select-fieldset-4.html select-fieldset-ref.html
== select-fieldset-legend-1.html select-fieldset-legend-ref-1.html
-fails-if(Android||B2G) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html
-fails-if(Android||B2G) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html
+fails-if(B2G) == select-fieldset-legend-2.html select-fieldset-legend-ref-2.html
+fails-if(B2G) == select-fieldset-legend-3.html select-fieldset-legend-ref-3.html
== select-fieldset-legend-4.html select-fieldset-legend-ref-4.html
== select-fieldset-legend-5.html select-fieldset-legend-ref-5.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-insert-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+ font-family: One;
+ src: url(../fonts/markA.ttf);
+}
+body { font-family: One; }
+</style>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-insert-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+body { font-family: One; }
+</style>
+<script>
+window.addEventListener("MozReftestInvalidate", function() {
+ var face = new FontFace("One", "url(../fonts/markA.ttf)");
+ face.load().then(function() {
+ document.fonts.add(face);
+ document.documentElement.className = "";
+ });
+});
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-remove-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+ font-family: One;
+ src: url(../fonts/markA.ttf);
+}
+body { font-family: One; }
+</style>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/dynamic-remove-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+body { font-family: One; }
+</style>
+<script>
+var f1 = new FontFace("One", "url(../fonts/markA.ttf)");
+var f2 = new FontFace("One", "url(../fonts/mark2A.ttf)");
+
+f1.load();
+f2.load();
+
+Promise.all([f1.load(), f2.load()])
+ .then(function() {
+ document.fonts.add(f1);
+ document.fonts.add(f2);
+ })
+ .then(document.fonts.ready)
+ .then(function() {
+ document.fonts.delete(f2);
+ document.documentElement.className = "";
+ });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/ex-unit-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/ex-unit-1.html -->
+<html class="reftest-wait">
+<title>ex unit with Ahem font</title>
+<style>
+html { background: white; }
+body { font-family: Ahhhem; font-size: 50px; height: 2ex; width: 2ex; background: blue; }
+</style>
+<script>
+document.fonts.add(new FontFace("Ahhhem", "url(../fonts/Ahem.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/name-collision.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<!-- modeled after ../font-face/name-collision.html -->
+<html class="reftest-wait">
+<!--
+ Font family names in @font-face rules take precedence over locally-available font families,
+ so none of the names of commonly used platform fonts should match against locally available
+ fonts.
+-->
+<style>
+body { margin: 50px; font-family: fallback; }
+table { font-family: Sample; margin-left: 3em; }
+.sample { font-family: Sample, fallback; }
+table td { font-size: 24pt; }
+
+/* Windows */
+
+.arial { font-family: Arial, fallback; }
+.timesnewroman { font-family: Times New Roman, fallback; }
+.couriernew { font-family: Courier New, fallback; }
+
+/* Mac OS X */
+
+.futura { font-family: Futura, fallback; }
+.helvetica { font-family: Helvetica, fallback; }
+.times { font-family: Times, fallback; }
+.courier { font-family: Courier, fallback; }
+
+/* Linux */
+
+.bitstreamverasans { font-family: Bitstream Vera Sans, fallback; }
+.dejavusans { font-family: DejaVu Sans, fallback; }
+.freesans { font-family: FreeSans, fallback; }
+</style>
+<script>
+function addTestFont(aFamily) {
+ document.fonts.add(new FontFace(aFamily, "url(../fonts/mplus/mplus-1p-black.ttf)", { weight: 900 }));
+}
+
+document.fonts.add(new FontFace("fallback", "url(../fonts/mplus/mplus-1p-regular.ttf)"));
+
+addTestFont("Sample");
+
+/* Windows */
+
+addTestFont("Arial");
+addTestFont("Times New Roman");
+addTestFont("Courier New");
+
+/* Mac OS X */
+
+addTestFont("Futura");
+addTestFont("Helvetica");
+addTestFont("Times");
+addTestFont("Courier");
+
+/* Linux */
+
+addTestFont("Bitstream Vera Sans");
+addTestFont("DejaVu Sans");
+addTestFont("FreeSans");
+
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+
+<p>All text below should appear in the same extra bold font face:</p>
+
+<table>
+<tr class="sample"><td>Sample</td></tr>
+<tr class="arial"><td>Arial</td></tr>
+<tr class="timesnewroman"><td>Times New Roman</td></tr>
+<tr class="couriernew"><td>Courier New</td></tr>
+<tr class="futura"><td>Futura</td></tr>
+<tr class="helvetica"><td>Helvetica</td></tr>
+<tr class="times"><td>Times</td></tr>
+<tr class="courier"><td>Courier</td></tr>
+<tr class="bitstreamverasans"><td>Bitstream Vera Sans</td></tr>
+<tr class="dejavusans"><td>DejaVu Sans</td></tr>
+<tr class="freesans"><td>FreeSans</td></tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/order-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/order-1.html -->
+<html class="reftest-wait">
+<style>
+body { font-family: "One"; }
+</style>
+<script>
+document.fonts.add(new FontFace("One", "url(../fonts/mark2A.ttf)"));
+document.fonts.add(new FontFace("One", "url(../fonts/markA.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/reftest.list
@@ -0,0 +1,10 @@
+default-preferences pref(layout.css.font-loading-api.enabled,true)
+
+HTTP(..) == dynamic-insert-1.html dynamic-insert-1-ref.html
+HTTP(..) == dynamic-remove-1.html dynamic-remove-1-ref.html
+HTTP(..) == ex-unit-1.html ../font-face/ex-unit-1-ref.html
+HTTP(..) == name-collision.html ../font-face/name-collision-ref.html
+HTTP(..) == order-1.html ../font-face/order-1-ref.html
+HTTP(..) == src-list-1.html ../font-face/src-list-1-ref.html
+HTTP(..) == src-list-2.html ../font-face/src-list-2-ref.html
+HTTP(..) == src-list-data-1.html ../font-face/src-list-data-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/src-list-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/src-list-1.html -->
+<html class="reftest-wait">
+<style>
+body { font-family: One; }
+</style>
+<script>
+document.fonts.add(new FontFace("One", "url(../fonts/markA.ttf), url(../fonts/mark2A.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/src-list-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/src-list-2.html -->
+<html class="reftest-wait">
+<style>
+body { font-family: "One"; }
+</style>
+<script>
+document.fonts.add(new FontFace("One", "url(../fonts/markA.ttf), url(../fonts/markB.ttf)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>ABC</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-loading-api/src-list-data-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- modeled on ../font-face/src-list-data-1.html -->
+<html class="reftest-wait">
+<style>
+body { margin: 20px; font-size: 100px; font-family: test; }
+p { margin: 0; padding: 0; }
+</style>
+<script>
+document.fonts.add(new FontFace("test", "url(data:font/opentype;base64,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AC4AIABDAG8AcAB5AHIAaQBnAGgAdAAgAGkAbgBmAG8AIABwAGUAbgBkAGkAbgBnAC4AbABvAGEAZAB0AGUAcwB0AFIAZQBnAHUAbABhAHIAdwBlAGIAZgBvAG4AdABsAG8AYQBkAHQAZQBzAHQAIABSAGUAZwB1AGwAYQByAFYAZQByAHMAaQBvAG4AIAAwADAAMQAuADAAMAAxAEIAYQBzAGUAZAAgAG8AbgAgAEwAZQBhAGcAdQBlACAARwBvAHQAaABpAGMAIABiAHkAIABMAGUAYQBnAHUAZQAgAG8AZgAgAE0AbwB2AGUAYQBiAGwAZQAgAFQAeQBwAGUALAAgAG0AbwBkAGkAZgBpAGUAZAAgAGIAeQAgAEoAbwBoAG4AIABEAGEAZwBnAGUAdAB0AGgAdAB0AHAAOgAvAC8AdwB3AHcALgB0AGgAZQBsAGUAYQBnAHUAZQBvAGYAbQBvAHYAZQBhAGIAbABlAHQAeQBwAGUALgBjAG8AbQAvAGwAZQBhAGcAdQBlAC0AZwBvAHQAaABpAGMAQQBsAGwAIABmAG8AbgB0AHMAIABmAHIAbwBtACAAVABoAGUAIABMAGUAYQBnAHUAZQAgAG8AZgAgAE0AbwB2AGUAYQBiAGwAZQAgAFQAeQBwAGUAIABhAHIAZQAgAHMAdQBiAGoAZQBjAHQAIAB0AG8AIAB0AGgAZQAgAE8AcABlAG4AIABGAG8AbgB0ACAATABpAGMAZQBuAHMAZQBoAHQAdABwADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAAgAAAAAAAP9nAGYAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgBfAGAAYQECAKMAhACFAJYAjgCLAQMAigDaAI0AwwDeAKIArQDJAMcArgBiAGMAkABkAMsAZQDIAMoAzwDMAM0AzgDpAGYA0wDQANEArwBnAJEA1gDUANUAaADrAO0AiQBqAGkAawBtAGwAbgCgAG8AcQBwAHIAcwB1AHQAdgB3AOoAeAB6AHkAewB9AHwAoQB/AH4AgACBAOwA7gC6ANcA4gDjALAAsQDkAOUAuwDmAOcA2ADhANsA3ADdAOAA2QDfAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQCyALMAtgC3AMQAtAC1AMUAhwCrARIBEwEUAIwA7wEVARYBFwd1bmkwMEEwB3VuaTAwQUQHdW5pMjAwMAd1bmkyMDAxB3VuaTIwMDIHdW5pMjAwMwd1bmkyMDA0B3VuaTIwMDUHdW5pMjAwNgd1bmkyMDA3B3VuaTIwMDgHdW5pMjAwOQd1bmkyMDBBB3VuaTIwMTAHdW5pMjAxMQpmaWd1cmVkYXNoB3VuaTIwMkYHdW5pMjA1RgRFdXJvB3VuaUUwMDAHdW5pRkIwMQd1bmlGQjAyAAAAAQAB//8ADwAAAAEAAAAAyYlvMQAAAADGp3m3AAAAAMrhKHcAAQAAAAwAAAAWAAAAAgABAAEA3wABAAQAAAABAAAAAAABAAAACgAuADwAAkRGTFQADmxhdG4AGAAEAAAAAP//AAAABAAAAAD//wABAAAAAVRTVDEACAAAAAEAAAABAAQAAQAAAAEACAACAA4ABABEADMANgBWAAEABAAkACkALAAvAAA=)"));
+document.fonts.ready.then(function() { document.documentElement.className = ""; });
+</script>
+<p>FAIL</p>
--- a/layout/reftests/native-theme/combobox-nonnative-when-styled-ref.html
+++ b/layout/reftests/native-theme/combobox-nonnative-when-styled-ref.html
@@ -1,17 +1,21 @@
<!DOCTYPE HTML>
+<div style="position:relative">
+<!-- mask the dropdown button -->
+<div style="position:absolute; width:50px; left:7px; top:0; bottom:0; background:black;"></div>
<!-- these should make the select non-native -->
-<select size="1" style="-moz-appearance: none; border-width: 0"></select>
-<select size="1" style="-moz-appearance: none; border-width: 1px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 2px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 3px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 4px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 5px"></select>
-<select size="1" style="-moz-appearance: none; border-width: 6px"></select>
-<select size="1" style="-moz-appearance: none; border-style: dotted"></select>
-<select size="1" style="-moz-appearance: none; border-color: green"></select>
-<select size="1" style="-moz-appearance: none; background-color: transparent"></select>
-<select size="1" style="-moz-appearance: none; background-color: white"></select>
+<select size="1" style="-moz-appearance: none; border-width: 0"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 1px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 2px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 3px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 4px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 5px"></select><br>
+<select size="1" style="-moz-appearance: none; border-width: 6px"></select><br>
+<select size="1" style="-moz-appearance: none; border-style: dotted"></select><br>
+<select size="1" style="-moz-appearance: none; border-color: green"></select><br>
+<select size="1" style="-moz-appearance: none; background-color: transparent"></select><br>
+<select size="1" style="-moz-appearance: none; background-color: white"></select><br>
+</div>
<!-- these should let it stay native -->
<select size="1"></select>
<select size="1"></select>
--- a/layout/reftests/native-theme/combobox-nonnative-when-styled.html
+++ b/layout/reftests/native-theme/combobox-nonnative-when-styled.html
@@ -1,17 +1,21 @@
<!DOCTYPE HTML>
+<div style="position:relative">
+<!-- mask the dropdown button -->
+<div style="position:absolute; width:50px; left:7px; top:0; bottom:0; background:black;"></div>
<!-- these should make the select non-native -->
-<select size="1" style="border-width: 0"></select>
-<select size="1" style="border-width: 1px"></select>
-<select size="1" style="border-width: 2px"></select>
-<select size="1" style="border-width: 3px"></select>
-<select size="1" style="border-width: 4px"></select>
-<select size="1" style="border-width: 5px"></select>
-<select size="1" style="border-width: 6px"></select>
-<select size="1" style="border-style: dotted"></select>
-<select size="1" style="border-color: green"></select>
-<select size="1" style="background-color: transparent"></select>
-<select size="1" style="background-color: white"></select>
+<select size="1" style="border-width: 0"></select><br>
+<select size="1" style="border-width: 1px"></select><br>
+<select size="1" style="border-width: 2px"></select><br>
+<select size="1" style="border-width: 3px"></select><br>
+<select size="1" style="border-width: 4px"></select><br>
+<select size="1" style="border-width: 5px"></select><br>
+<select size="1" style="border-width: 6px"></select><br>
+<select size="1" style="border-style: dotted"></select><br>
+<select size="1" style="border-color: green"></select><br>
+<select size="1" style="background-color: transparent"></select><br>
+<select size="1" style="background-color: white"></select><br>
+</div>
<!-- these should let it stay native -->
<select size="1" style="color: black"></select>
<select size="1" style="font-weight: normal"></select>
--- a/layout/reftests/native-theme/reftest.list
+++ b/layout/reftests/native-theme/reftest.list
@@ -12,17 +12,17 @@
# The following tests will fail if the platform does not have native
# theme support (which all platforms should have).
fails-if(!nativeThemePref) != text-input-native.html text-input-nonnative.html
== text-input-nonnative-when-styled.html text-input-nonnative-when-styled-ref.html
fails-if(!nativeThemePref) != textarea-native.html textarea-nonnative.html
== textarea-nonnative-when-styled.html textarea-nonnative-when-styled-ref.html
fails-if(!nativeThemePref) != button-native.html button-nonnative.html
== button-nonnative-when-styled.html button-nonnative-when-styled-ref.html
-fails-if(!nativeThemePref) != combobox-native.html combobox-nonnative.html
+fails-if(!nativeThemePref&&!Android) != combobox-native.html combobox-nonnative.html
== combobox-nonnative-when-styled.html combobox-nonnative-when-styled-ref.html
fails-if(!nativeThemePref) needs-focus != listbox-native.html listbox-nonnative.html
needs-focus == listbox-nonnative-when-styled.html listbox-nonnative-when-styled-ref.html
fails-if(!nativeThemePref) != radio-native.html radio-nonnative.html
== radio-still-native-when-styled.html radio-still-native-when-styled-ref.html
fails-if(!nativeThemePref) != checkbox-native.html checkbox-nonnative.html
== checkbox-still-native-when-styled.html checkbox-still-native-when-styled-ref.html
== native-theme-disabled-cascade-levels.html native-theme-disabled-cascade-levels-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -176,16 +176,19 @@ include floats/reftest.list
include font-face/reftest.list
# font features (opentype)
include font-features/reftest.list
# mobile font size inflation
skip-if(B2G&&browserIsRemote) include font-inflation/reftest.list # Bug 972697
+# CSS Font Loading API
+include font-loading-api/reftest.list
+
# font matching
include font-matching/reftest.list
# forms
include forms/reftest.list
# gfx
include ../../gfx/tests/reftest/reftest.list
--- a/layout/reftests/text-overflow/combobox-zoom-ref.html
+++ b/layout/reftests/text-overflow/combobox-zoom-ref.html
@@ -14,21 +14,21 @@ html,body {
color:black; background-color:white; padding:0; margin:0;
}
* {
font-family:DejaVuSansMono!important;
font-size:16px!important;
}
select {
width: 200px;
- padding-right: 7px;
+ padding-right: 8px;
-moz-appearance: none;
}
</style>
</head>
<body>
<select></select><br>
-<select><option>long string long </option></select>
+<select><option>long string long s</option></select>
</body>
</html>
--- a/layout/reftests/text-overflow/combobox-zoom.html
+++ b/layout/reftests/text-overflow/combobox-zoom.html
@@ -14,17 +14,17 @@ html,body {
color:black; background-color:white; padding:0; margin:0;
}
* {
font-family:DejaVuSansMono!important;
font-size:16px!important;
}
select {
width: 200px;
- padding-right: 7px;
+ padding-right: 8px;
text-overflow: " ";
-moz-appearance: none;
}
</style>
</head>
<body>
<select></select><br>
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -714,20 +714,34 @@ void
AnimationPlayerCollection::UpdateAnimationGeneration(
nsPresContext* aPresContext)
{
mAnimationGeneration =
aPresContext->RestyleManager()->GetAnimationGeneration();
}
bool
-AnimationPlayerCollection::HasCurrentAnimations()
+AnimationPlayerCollection::HasCurrentAnimations() const
{
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
- if (mPlayers[playerIdx]->IsCurrent()) {
+ if (mPlayers[playerIdx]->HasCurrentSource()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+AnimationPlayerCollection::HasCurrentAnimationsForProperty(nsCSSProperty
+ aProperty) const
+{
+ for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
+ const Animation* anim = mPlayers[playerIdx]->GetSource();
+ if (anim && anim->IsCurrent() && anim->HasAnimationOfProperty(aProperty)) {
return true;
}
}
return false;
}
}
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -299,19 +299,21 @@ struct AnimationPlayerCollection : publi
// mAnimationGeneration is the sequence number of the last flush where a
// transition/animation changed. We keep a similar count on the
// corresponding layer so we can check that the layer is up to date with
// the animation manager.
uint64_t mAnimationGeneration;
// Update mAnimationGeneration to nsCSSFrameConstructor's count
void UpdateAnimationGeneration(nsPresContext* aPresContext);
- // Returns true if there is an animation in the before or active phase
- // at the current time.
- bool HasCurrentAnimations();
+ // Returns true if there is an animation that has yet to finish.
+ bool HasCurrentAnimations() const;
+ // Returns true if there is an animation of the specified property that
+ // has yet to finish.
+ bool HasCurrentAnimationsForProperty(nsCSSProperty aProperty) const;
// The refresh time associated with mStyleRule.
TimeStamp mStyleRuleRefreshTime;
// False when we know that our current style rule is valid
// indefinitely into the future (because all of our animations are
// either completed or paused). May be invalidated by a style change.
bool mNeedsRefreshes;
new file mode 100644
--- /dev/null
+++ b/layout/style/FontFace.cpp
@@ -0,0 +1,876 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/FontFace.h"
+
+#include "mozilla/dom/FontFaceBinding.h"
+#include "mozilla/dom/FontFaceSet.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/dom/UnionTypes.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
+#include "nsCSSParser.h"
+#include "nsCSSRules.h"
+#include "nsIDocument.h"
+#include "nsStyleUtil.h"
+
+namespace mozilla {
+namespace dom {
+
+// -- FontFaceBufferSource ---------------------------------------------------
+
+/**
+ * An object that wraps a FontFace object and exposes its ArrayBuffer
+ * or ArrayBufferView data in a form the user font set can consume.
+ */
+class FontFaceBufferSource : public gfxFontFaceBufferSource
+{
+public:
+ FontFaceBufferSource(FontFace* aFontFace)
+ : mFontFace(aFontFace) {}
+ virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
+
+private:
+ nsRefPtr<FontFace> mFontFace;
+};
+
+void
+FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
+{
+ mFontFace->TakeBuffer(aBuffer, aLength);
+}
+
+// -- FontFaceInitializer ----------------------------------------------------
+
+template<typename T>
+static void
+GetDataFrom(const T& aObject, uint8_t*& aBuffer, uint32_t& aLength)
+{
+ MOZ_ASSERT(!aBuffer);
+ aObject.ComputeLengthAndData();
+ // We use moz_malloc here rather than a FallibleTArray or fallible
+ // operator new[] since the gfxUserFontEntry will be calling moz_free
+ // on it.
+ aBuffer = (uint8_t*) moz_malloc(aObject.Length());
+ if (!aBuffer) {
+ return;
+ }
+ memcpy((void*) aBuffer, aObject.Data(), aObject.Length());
+ aLength = aObject.Length();
+}
+
+/**
+ * A task that is dispatched to the event queue to call Initialize() on a
+ * FontFace object with the source information that was passed to the JS
+ * constructor.
+ */
+class FontFaceInitializer : public nsIRunnable
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ FontFaceInitializer(FontFace* aFontFace)
+ : mFontFace(aFontFace)
+ , mSourceBuffer(nullptr)
+ , mSourceBufferLength(0) {}
+
+ void SetSource(const nsAString& aString);
+ void SetSource(const ArrayBuffer& aArrayBuffer);
+ void SetSource(const ArrayBufferView& aArrayBufferView);
+
+ NS_IMETHOD Run();
+ void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
+
+ nsRefPtr<FontFace> mFontFace;
+ FontFace::SourceType mSourceType;
+ nsString mSourceString;
+ uint8_t* mSourceBuffer; // allocated with NS_Alloc
+ uint32_t mSourceBufferLength;
+
+protected:
+ virtual ~FontFaceInitializer();
+};
+
+NS_IMPL_ISUPPORTS(FontFaceInitializer, nsIRunnable)
+
+FontFaceInitializer::~FontFaceInitializer()
+{
+ if (mSourceBuffer) {
+ NS_Free(mSourceBuffer);
+ }
+}
+
+void
+FontFaceInitializer::SetSource(const nsAString& aString)
+{
+ mSourceType = FontFace::eSourceType_URLs;
+ mSourceString = aString;
+}
+
+void
+FontFaceInitializer::SetSource(const ArrayBuffer& aArrayBuffer)
+{
+ mSourceType = FontFace::eSourceType_Buffer;
+ GetDataFrom(aArrayBuffer, mSourceBuffer, mSourceBufferLength);
+}
+
+void
+FontFaceInitializer::SetSource(const ArrayBufferView& aArrayBufferView)
+{
+ mSourceType = FontFace::eSourceType_Buffer;
+ GetDataFrom(aArrayBufferView, mSourceBuffer, mSourceBufferLength);
+}
+
+NS_IMETHODIMP
+FontFaceInitializer::Run()
+{
+ mFontFace->Initialize(this);
+ return NS_OK;
+}
+
+void
+FontFaceInitializer::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
+{
+ aBuffer = mSourceBuffer;
+ aLength = mSourceBufferLength;
+
+ mSourceBuffer = nullptr;
+ mSourceBufferLength = 0;
+}
+
+// -- FontFaceStatusSetter ---------------------------------------------------
+
+/**
+ * A task that is dispatched to the event queue to asynchronously call
+ * SetStatus() on a FontFace object.
+ */
+class FontFaceStatusSetter : public nsIRunnable
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ FontFaceStatusSetter(FontFace* aFontFace,
+ FontFaceLoadStatus aStatus)
+ : mFontFace(aFontFace)
+ , mStatus(aStatus) {}
+
+ NS_IMETHOD Run();
+
+protected:
+ virtual ~FontFaceStatusSetter() {}
+
+private:
+ nsRefPtr<FontFace> mFontFace;
+ FontFaceLoadStatus mStatus;
+};
+
+NS_IMPL_ISUPPORTS(FontFaceStatusSetter, nsIRunnable)
+
+NS_IMETHODIMP
+FontFaceStatusSetter::Run()
+{
+ mFontFace->SetStatus(mStatus);
+ return NS_OK;
+}
+
+// -- FontFace ---------------------------------------------------------------
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRule)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
+ if (!tmp->IsInFontFaceSet()) {
+ tmp->mFontFaceSet->RemoveUnavailableFontFace(tmp);
+ }
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mRule)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
+
+FontFace::FontFace(nsISupports* aParent, nsPresContext* aPresContext)
+ : mParent(aParent)
+ , mPresContext(aPresContext)
+ , mStatus(FontFaceLoadStatus::Unloaded)
+ , mSourceType(SourceType(0))
+ , mSourceBuffer(nullptr)
+ , mSourceBufferLength(0)
+ , mFontFaceSet(aPresContext->Fonts())
+ , mInFontFaceSet(false)
+ , mInitialized(false)
+ , mLoadWhenInitialized(false)
+{
+ MOZ_COUNT_CTOR(FontFace);
+
+ SetIsDOMBinding();
+
+ nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
+
+ if (global) {
+ ErrorResult rv;
+ mLoaded = Promise::Create(global, rv);
+ }
+}
+
+FontFace::~FontFace()
+{
+ MOZ_COUNT_DTOR(FontFace);
+
+ SetUserFontEntry(nullptr);
+
+ if (mFontFaceSet && !IsInFontFaceSet()) {
+ mFontFaceSet->RemoveUnavailableFontFace(this);
+ }
+
+ if (mSourceBuffer) {
+ NS_Free(mSourceBuffer);
+ }
+}
+
+JSObject*
+FontFace::WrapObject(JSContext* aCx)
+{
+ return FontFaceBinding::Wrap(aCx, this);
+}
+
+static FontFaceLoadStatus
+LoadStateToStatus(gfxUserFontEntry::UserFontLoadState aLoadState)
+{
+ switch (aLoadState) {
+ case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
+ return FontFaceLoadStatus::Unloaded;
+ case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
+ return FontFaceLoadStatus::Loading;
+ case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
+ return FontFaceLoadStatus::Loaded;
+ case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
+ return FontFaceLoadStatus::Error;
+ }
+ NS_NOTREACHED("invalid aLoadState value");
+ return FontFaceLoadStatus::Error;
+}
+
+already_AddRefed<FontFace>
+FontFace::CreateForRule(nsISupports* aGlobal,
+ nsPresContext* aPresContext,
+ nsCSSFontFaceRule* aRule,
+ gfxUserFontEntry* aUserFontEntry)
+{
+ nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aGlobal);
+
+ nsRefPtr<FontFace> obj = new FontFace(aGlobal, aPresContext);
+ obj->mInitialized = true;
+ obj->mRule = aRule;
+ obj->mSourceType = eSourceType_FontFaceRule;
+ obj->mInFontFaceSet = true;
+ obj->SetUserFontEntry(aUserFontEntry);
+ return obj.forget();
+}
+
+already_AddRefed<FontFace>
+FontFace::Constructor(const GlobalObject& aGlobal,
+ const nsAString& aFamily,
+ const StringOrArrayBufferOrArrayBufferView& aSource,
+ const FontFaceDescriptors& aDescriptors,
+ ErrorResult& aRv)
+{
+ nsISupports* global = aGlobal.GetAsSupports();
+ nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
+ nsIDocument* doc = window->GetDoc();
+ if (!doc) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ nsIPresShell* shell = doc->GetShell();
+ if (!shell) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ nsPresContext* presContext = shell->GetPresContext();
+ if (!presContext) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ nsRefPtr<FontFace> obj = new FontFace(global, presContext);
+ obj->mFontFaceSet->AddUnavailableFontFace(obj);
+ if (!obj->SetDescriptors(aFamily, aDescriptors)) {
+ return obj.forget();
+ }
+
+ nsRefPtr<FontFaceInitializer> task = new FontFaceInitializer(obj);
+
+ if (aSource.IsArrayBuffer()) {
+ task->SetSource(aSource.GetAsArrayBuffer());
+ } else if (aSource.IsArrayBufferView()) {
+ task->SetSource(aSource.GetAsArrayBufferView());
+ } else {
+ MOZ_ASSERT(aSource.IsString());
+ task->SetSource(aSource.GetAsString());
+ }
+
+ NS_DispatchToMainThread(task);
+
+ return obj.forget();
+}
+
+void
+FontFace::Initialize(FontFaceInitializer* aInitializer)
+{
+ MOZ_ASSERT(!HasRule());
+ MOZ_ASSERT(mSourceType == SourceType(0));
+
+ if (aInitializer->mSourceType == eSourceType_URLs) {
+ if (!ParseDescriptor(eCSSFontDesc_Src,
+ aInitializer->mSourceString,
+ mDescriptors->mSrc)) {
+ if (mLoaded) {
+ // The asynchronous SetStatus call we are about to do assumes that for
+ // FontFace objects with sources other than ArrayBuffer(View)s, that the
+ // mLoaded Promise is rejected with a network error. We get
+ // in here beforehand to set it to the required syntax error.
+ mLoaded->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
+ }
+
+ // Queue a task to set the status to "error".
+ nsCOMPtr<nsIRunnable> statusSetterTask =
+ new FontFaceStatusSetter(this, FontFaceLoadStatus::Error);
+ NS_DispatchToMainThread(statusSetterTask);
+ return;
+ }
+
+ mSourceType = eSourceType_URLs;
+
+ // Now that we have parsed the src descriptor, we are initialized.
+ OnInitialized();
+ return;
+ }
+
+ // We've been given an ArrayBuffer or ArrayBufferView as the source.
+ MOZ_ASSERT(aInitializer->mSourceType == eSourceType_Buffer);
+
+ mSourceType = aInitializer->mSourceType;
+ aInitializer->TakeBuffer(mSourceBuffer, mSourceBufferLength);
+
+ // Queue a task to set the status to "loading".
+ nsCOMPtr<nsIRunnable> statusSetterTask =
+ new FontFaceStatusSetter(this, FontFaceLoadStatus::Loading);
+ NS_DispatchToMainThread(statusSetterTask);
+
+ // We are initialized.
+ OnInitialized();
+
+ // ArrayBuffer(View)-backed FontFace objects are loaded on construction,
+ // but we need to do this after going through the event loop so that the
+ // FontFaceStatusSetter runs before us.
+ nsCOMPtr<nsIRunnable> loaderTask =
+ NS_NewRunnableMethod(this, &FontFace::DoLoad);
+ NS_DispatchToMainThread(loaderTask);
+}
+
+void
+FontFace::GetFamily(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+
+ // Serialize the same way as in nsCSSFontFaceStyleDecl::GetPropertyValue.
+ nsCSSValue value;
+ GetDesc(eCSSFontDesc_Family, value);
+
+ aResult.Truncate();
+ nsDependentString family(value.GetStringBufferValue());
+ if (!family.IsEmpty()) {
+ // The string length can be zero when the author passed an invalid
+ // family name or an invalid descriptor to the JS FontFace constructor.
+ nsStyleUtil::AppendEscapedCSSString(family, aResult);
+ }
+}
+
+void
+FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+ SetDescriptor(eCSSFontDesc_Family, aValue, aRv);
+}
+
+void
+FontFace::GetStyle(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+ GetDesc(eCSSFontDesc_Style, eCSSProperty_font_style, aResult);
+}
+
+void
+FontFace::SetStyle(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+ SetDescriptor(eCSSFontDesc_Style, aValue, aRv);
+}
+
+void
+FontFace::GetWeight(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+ GetDesc(eCSSFontDesc_Weight, eCSSProperty_font_weight, aResult);
+}
+
+void
+FontFace::SetWeight(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+ SetDescriptor(eCSSFontDesc_Weight, aValue, aRv);
+}
+
+void
+FontFace::GetStretch(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+ GetDesc(eCSSFontDesc_Stretch, eCSSProperty_font_stretch, aResult);
+}
+
+void
+FontFace::SetStretch(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+ SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv);
+}
+
+void
+FontFace::GetUnicodeRange(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+
+ nsCSSValue value;
+ GetDesc(eCSSFontDesc_UnicodeRange, value);
+
+ aResult.Truncate();
+ nsStyleUtil::AppendUnicodeRange(value, aResult);
+}
+
+void
+FontFace::SetUnicodeRange(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+ SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv);
+}
+
+void
+FontFace::GetVariant(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+
+ // XXX Just expose the font-variant descriptor as "normal" until we
+ // support it properly (bug 1055385).
+ aResult.AssignLiteral("normal");
+}
+
+void
+FontFace::SetVariant(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+
+ // XXX Ignore assignments to variant until we support font-variant
+ // descriptors (bug 1055385).
+}
+
+void
+FontFace::GetFeatureSettings(nsString& aResult)
+{
+ mPresContext->FlushUserFontSet();
+
+ nsCSSValue value;
+ GetDesc(eCSSFontDesc_FontFeatureSettings, value);
+
+ aResult.Truncate();
+ nsStyleUtil::AppendFontFeatureSettings(value, aResult);
+}
+
+void
+FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+ SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv);
+}
+
+FontFaceLoadStatus
+FontFace::Status()
+{
+ return mStatus;
+}
+
+Promise*
+FontFace::Load(ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+
+ if (!mLoaded) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ // Calling Load on a FontFace constructed with an ArrayBuffer data source,
+ // or on one that is already loading (or has finished loading), has no
+ // effect.
+ if (mSourceType == eSourceType_Buffer ||
+ mStatus != FontFaceLoadStatus::Unloaded) {
+ return mLoaded;
+ }
+
+ // Calling the user font entry's Load method will end up setting our
+ // status to Loading, but the spec requires us to set it to Loading
+ // here.
+ SetStatus(FontFaceLoadStatus::Loading);
+
+ if (mInitialized) {
+ DoLoad();
+ } else {
+ // We can only load an initialized font; this will cause the font to be
+ // loaded once it has been initialized.
+ mLoadWhenInitialized = true;
+ }
+
+ return mLoaded;
+}
+
+void
+FontFace::DoLoad()
+{
+ MOZ_ASSERT(mInitialized);
+
+ if (!mUserFontEntry) {
+ MOZ_ASSERT(!HasRule(),
+ "Rule backed FontFace objects should already have a user font "
+ "entry by the time Load() can be called on them");
+
+ nsRefPtr<gfxUserFontEntry> newEntry =
+ mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
+ if (!newEntry) {
+ return;
+ }
+
+ SetUserFontEntry(newEntry);
+ }
+
+ mUserFontEntry->Load();
+}
+
+Promise*
+FontFace::GetLoaded(ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+
+ if (!mLoaded) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ return mLoaded;
+}
+
+void
+FontFace::SetStatus(FontFaceLoadStatus aStatus)
+{
+ if (mStatus == aStatus) {
+ return;
+ }
+
+ if (aStatus < mStatus) {
+ // We're being asked to go backwards in status! Normally, this shouldn't
+ // happen. But it can if the FontFace had a user font entry that had
+ // loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
+ // if we used a local() rule. For now, just ignore the request to
+ // go backwards in status.
+ return;
+ }
+
+ mStatus = aStatus;
+
+ if (mInFontFaceSet) {
+ mFontFaceSet->OnFontFaceStatusChanged(this);
+ }
+
+ if (!mLoaded) {
+ return;
+ }
+
+ if (mStatus == FontFaceLoadStatus::Loaded) {
+ mLoaded->MaybeResolve(this);
+ } else if (mStatus == FontFaceLoadStatus::Error) {
+ if (mSourceType == eSourceType_Buffer) {
+ mLoaded->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
+ } else {
+ mLoaded->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
+ }
+ }
+}
+
+bool
+FontFace::ParseDescriptor(nsCSSFontDesc aDescID,
+ const nsAString& aString,
+ nsCSSValue& aResult)
+{
+ nsCSSParser parser;
+
+ nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
+ nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
+
+ nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent);
+ nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
+
+ if (!parser.ParseFontFaceDescriptor(aDescID, aString,
+ nullptr, // aSheetURL
+ base,
+ principal,
+ aResult)) {
+ aResult.Reset();
+ return false;
+ }
+
+ return true;
+}
+
+void
+FontFace::SetDescriptor(nsCSSFontDesc aFontDesc,
+ const nsAString& aValue,
+ ErrorResult& aRv)
+{
+ NS_ASSERTION(!HasRule(),
+ "we don't handle rule backed FontFace objects yet");
+ if (HasRule()) {
+ return;
+ }
+
+ nsCSSValue parsedValue;
+ if (!ParseDescriptor(aFontDesc, aValue, parsedValue)) {
+ aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+ return;
+ }
+
+ mDescriptors->Get(aFontDesc) = parsedValue;
+
+ // XXX Setting descriptors doesn't actually have any effect on FontFace
+ // objects that have started loading or have already been loaded.
+}
+
+bool
+FontFace::SetDescriptors(const nsAString& aFamily,
+ const FontFaceDescriptors& aDescriptors)
+{
+ MOZ_ASSERT(!HasRule());
+ MOZ_ASSERT(!mDescriptors);
+
+ mDescriptors = new CSSFontFaceDescriptors;
+
+ // Parse all of the mDescriptors in aInitializer, which are the values
+ // we got from the JS constructor.
+ if (!ParseDescriptor(eCSSFontDesc_Family,
+ aFamily,
+ mDescriptors->mFamily) ||
+ *mDescriptors->mFamily.GetStringBufferValue() == 0 ||
+ !ParseDescriptor(eCSSFontDesc_Style,
+ aDescriptors.mStyle,
+ mDescriptors->mStyle) ||
+ !ParseDescriptor(eCSSFontDesc_Weight,
+ aDescriptors.mWeight,
+ mDescriptors->mWeight) ||
+ !ParseDescriptor(eCSSFontDesc_Stretch,
+ aDescriptors.mStretch,
+ mDescriptors->mStretch) ||
+ !ParseDescriptor(eCSSFontDesc_UnicodeRange,
+ aDescriptors.mUnicodeRange,
+ mDescriptors->mUnicodeRange) ||
+ !ParseDescriptor(eCSSFontDesc_FontFeatureSettings,
+ aDescriptors.mFeatureSettings,
+ mDescriptors->mFontFeatureSettings)) {
+ // XXX Handle font-variant once we support it (bug 1055385).
+
+ // If any of the descriptors failed to parse, none of them should be set
+ // on the FontFace.
+ mDescriptors = new CSSFontFaceDescriptors;
+
+ if (mLoaded) {
+ mLoaded->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
+ }
+
+ SetStatus(FontFaceLoadStatus::Error);
+ return false;
+ }
+
+ return true;
+}
+
+void
+FontFace::OnInitialized()
+{
+ MOZ_ASSERT(!mInitialized);
+
+ mInitialized = true;
+
+ // For a FontFace that was created and immediately had Load() called on
+ // it, before it had a chance to be initialized, we kick off its load now.
+ if (mLoadWhenInitialized) {
+ mLoadWhenInitialized = false;
+ DoLoad();
+ }
+
+ if (mInFontFaceSet) {
+ mFontFaceSet->OnFontFaceInitialized(this);
+ }
+}
+
+void
+FontFace::GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const
+{
+ if (HasRule()) {
+ MOZ_ASSERT(mRule);
+ MOZ_ASSERT(!mDescriptors);
+ mRule->GetDesc(aDescID, aResult);
+ } else {
+ aResult = mDescriptors->Get(aDescID);
+ }
+}
+
+void
+FontFace::GetDesc(nsCSSFontDesc aDescID,
+ nsCSSProperty aPropID,
+ nsString& aResult) const
+{
+ nsCSSValue value;
+ GetDesc(aDescID, value);
+
+ aResult.Truncate();
+
+ // Fill in a default value for missing descriptors.
+ if (value.GetUnit() == eCSSUnit_Null) {
+ if (aDescID == eCSSFontDesc_UnicodeRange) {
+ aResult.AssignLiteral("U+0-10FFFF");
+ } else if (aDescID != eCSSFontDesc_Family &&
+ aDescID != eCSSFontDesc_Src) {
+ aResult.AssignLiteral("normal");
+ }
+ } else {
+ value.AppendToString(aPropID, aResult, nsCSSValue::eNormalized);
+ }
+}
+
+void
+FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry)
+{
+ if (mUserFontEntry) {
+ mUserFontEntry->mFontFaces.RemoveElement(this);
+ }
+
+ mUserFontEntry = static_cast<Entry*>(aEntry);
+ if (mUserFontEntry) {
+ mUserFontEntry->mFontFaces.AppendElement(this);
+
+ // Our newly assigned user font entry might be in the process of or
+ // finished loading, so set our status accordingly. But only do so
+ // if we're not going "backwards" in status, which could otherwise
+ // happen in this case:
+ //
+ // new FontFace("ABC", "url(x)").load();
+ //
+ // where the SetUserFontEntry call (from the after-initialization
+ // DoLoad call) comes after the author's call to load(), which set mStatus
+ // to Loading.
+ FontFaceLoadStatus newStatus =
+ LoadStateToStatus(mUserFontEntry->LoadState());
+ if (newStatus > mStatus) {
+ SetStatus(newStatus);
+ }
+ }
+}
+
+bool
+FontFace::GetFamilyName(nsString& aResult)
+{
+ nsCSSValue value;
+ GetDesc(eCSSFontDesc_Family, value);
+
+ if (value.GetUnit() == eCSSUnit_String) {
+ nsString familyname;
+ value.GetStringValue(familyname);
+ aResult.Append(familyname);
+ }
+
+ return !aResult.IsEmpty();
+}
+
+void
+FontFace::DisconnectFromRule()
+{
+ MOZ_ASSERT(HasRule());
+
+ // Make a copy of the descriptors.
+ mDescriptors = new CSSFontFaceDescriptors;
+ mRule->GetDescriptors(*mDescriptors);
+
+ mRule->SetFontFace(nullptr);
+ mRule = nullptr;
+ mInFontFaceSet = false;
+}
+
+bool
+FontFace::HasFontData() const
+{
+ return mSourceType == eSourceType_Buffer && mSourceBuffer;
+}
+
+void
+FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
+{
+ MOZ_ASSERT(HasFontData());
+
+ aBuffer = mSourceBuffer;
+ aLength = mSourceBufferLength;
+
+ mSourceBuffer = nullptr;
+ mSourceBufferLength = 0;
+}
+
+already_AddRefed<gfxFontFaceBufferSource>
+FontFace::CreateBufferSource()
+{
+ nsRefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
+ return bufferSource.forget();
+}
+
+// -- FontFace::Entry --------------------------------------------------------
+
+/* virtual */ void
+FontFace::Entry::SetLoadState(UserFontLoadState aLoadState)
+{
+ gfxUserFontEntry::SetLoadState(aLoadState);
+
+ for (size_t i = 0; i < mFontFaces.Length(); i++) {
+ mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
+ }
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/FontFace.h
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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_FontFace_h
+#define mozilla_dom_FontFace_h
+
+#include "mozilla/dom/FontFaceBinding.h"
+#include "gfxUserFontSet.h"
+#include "nsCSSProperty.h"
+#include "nsCSSValue.h"
+#include "nsWrapperCache.h"
+
+class gfxFontFaceBufferSource;
+class nsCSSFontFaceRule;
+class nsPresContext;
+
+namespace mozilla {
+struct CSSFontFaceDescriptors;
+namespace dom {
+class FontFaceBufferSource;
+struct FontFaceDescriptors;
+class FontFaceSet;
+class FontFaceInitializer;
+class FontFaceStatusSetter;
+class Promise;
+class StringOrArrayBufferOrArrayBufferView;
+}
+}
+
+namespace mozilla {
+namespace dom {
+
+class FontFace MOZ_FINAL : public nsISupports,
+ public nsWrapperCache
+{
+ friend class mozilla::dom::FontFaceBufferSource;
+ friend class mozilla::dom::FontFaceInitializer;
+ friend class mozilla::dom::FontFaceStatusSetter;
+ friend class Entry;
+
+public:
+ class Entry MOZ_FINAL : public gfxUserFontEntry {
+ friend class FontFace;
+
+ public:
+ Entry(gfxUserFontSet* aFontSet,
+ const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
+ uint32_t aWeight,
+ int32_t aStretch,
+ uint32_t aItalicStyle,
+ const nsTArray<gfxFontFeature>& aFeatureSettings,
+ uint32_t aLanguageOverride,
+ gfxSparseBitSet* aUnicodeRanges)
+ : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
+ aItalicStyle, aFeatureSettings, aLanguageOverride,
+ aUnicodeRanges) {}
+
+ virtual void SetLoadState(UserFontLoadState aLoadState) MOZ_OVERRIDE;
+
+ protected:
+ // The FontFace objects that use this user font entry. We need to store
+ // an array of these, not just a single pointer, since the user font
+ // cache can return the same entry for different FontFaces that have
+ // the same descriptor values and come from the same origin.
+ nsAutoTArray<FontFace*,1> mFontFaces;
+ };
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FontFace)
+
+ nsISupports* GetParentObject() const { return mParent; }
+ virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+ static already_AddRefed<FontFace> CreateForRule(
+ nsISupports* aGlobal,
+ nsPresContext* aPresContext,
+ nsCSSFontFaceRule* aRule,
+ gfxUserFontEntry* aUserFontEntry);
+
+ nsCSSFontFaceRule* GetRule() { return mRule; }
+
+ void GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const;
+
+ gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
+ void SetUserFontEntry(gfxUserFontEntry* aEntry);
+
+ /**
+ * Returns whether this object is in a FontFaceSet.
+ */
+ bool IsInFontFaceSet() { return mInFontFaceSet; }
+
+ /**
+ * Sets whether this object is in a FontFaceSet. This is called by the
+ * FontFaceSet when Add, Remove, etc. are called.
+ */
+ void SetIsInFontFaceSet(bool aInFontFaceSet) {
+ MOZ_ASSERT(!(!aInFontFaceSet && HasRule()),
+ "use DisconnectFromRule instead");
+ mInFontFaceSet = aInFontFaceSet;
+ }
+
+ /**
+ * Returns whether this FontFace is initialized. A rule backed
+ * FontFace is considered initialized at construction time. For
+ * FontFace objects created using the FontFace JS constructor, it
+ * is once all the descriptors have been parsed.
+ */
+ bool IsInitialized() const { return mInitialized; }
+
+ FontFaceSet* GetFontFaceSet() const { return mFontFaceSet; }
+
+ /**
+ * Gets the family name of the FontFace as a raw string (such as 'Times', as
+ * opposed to GetFamily, which returns a CSS-escaped string, such as
+ * '"Times"'). Returns whether a valid family name was available.
+ */
+ bool GetFamilyName(nsString& aResult);
+
+ /**
+ * Returns whether this object is CSS-connected, i.e. reflecting an
+ * @font-face rule.
+ */
+ bool HasRule() const { return mRule; }
+
+ /**
+ * Breaks the connection between this FontFace and its @font-face rule.
+ */
+ void DisconnectFromRule();
+
+ /**
+ * Returns whether there is an ArrayBuffer or ArrayBufferView of font
+ * data.
+ */
+ bool HasFontData() const;
+
+ /**
+ * Creates a gfxFontFaceBufferSource to represent the font data
+ * in this object.
+ */
+ already_AddRefed<gfxFontFaceBufferSource> CreateBufferSource();
+
+ /**
+ * Gets a pointer to and the length of the font data stored in the
+ * ArrayBuffer or ArrayBufferView.
+ */
+ bool GetData(uint8_t*& aBuffer, uint32_t& aLength);
+
+ // Web IDL
+ static already_AddRefed<FontFace>
+ Constructor(const GlobalObject& aGlobal,
+ const nsAString& aFamily,
+ const mozilla::dom::StringOrArrayBufferOrArrayBufferView& aSource,
+ const mozilla::dom::FontFaceDescriptors& aDescriptors,
+ ErrorResult& aRV);
+
+ void GetFamily(nsString& aResult);
+ void SetFamily(const nsAString& aValue, mozilla::ErrorResult& aRv);
+ void GetStyle(nsString& aResult);
+ void SetStyle(const nsAString& aValue, mozilla::ErrorResult& aRv);
+ void GetWeight(nsString& aResult);
+ void SetWeight(const nsAString& aValue, mozilla::ErrorResult& aRv);
+ void GetStretch(nsString& aResult);
+ void SetStretch(const nsAString& aValue, mozilla::ErrorResult& aRv);
+ void GetUnicodeRange(nsString& aResult);
+ void SetUnicodeRange(const nsAString& aValue, mozilla::ErrorResult& aRv);
+ void GetVariant(nsString& aResult);
+ void SetVariant(const nsAString& aValue, mozilla::ErrorResult& aRv);
+ void GetFeatureSettings(nsString& aResult);
+ void SetFeatureSettings(const nsAString& aValue, mozilla::ErrorResult& aRv);
+
+ mozilla::dom::FontFaceLoadStatus Status();
+ mozilla::dom::Promise* Load(mozilla::ErrorResult& aRv);
+ mozilla::dom::Promise* GetLoaded(mozilla::ErrorResult& aRv);
+
+private:
+ FontFace(nsISupports* aParent, nsPresContext* aPresContext);
+ ~FontFace();
+
+ /**
+ * Initializes the source and descriptors on this object based on values that
+ * were passed in to the JS constructor. If the source was specified as
+ * an ArrayBuffer or ArrayBufferView, parsing of the font data in there
+ * will be started.
+ */
+ void Initialize(FontFaceInitializer* aInitializer);
+
+ // Helper function for Load.
+ void DoLoad();
+
+ /**
+ * Parses a @font-face descriptor value, storing the result in aResult.
+ * Returns whether the parsing was successful.
+ */
+ bool ParseDescriptor(nsCSSFontDesc aDescID, const nsAString& aString,
+ nsCSSValue& aResult);
+
+ // Helper function for the descriptor setter methods.
+ void SetDescriptor(nsCSSFontDesc aFontDesc,
+ const nsAString& aValue,
+ mozilla::ErrorResult& aRv);
+
+ /**
+ * Sets all of the descriptor values in mDescriptors using values passed
+ * to the JS constructor.
+ */
+ bool SetDescriptors(const nsAString& aFamily,
+ const FontFaceDescriptors& aDescriptors);
+
+ /**
+ * Marks the FontFace as initialized and informs the FontFaceSet it is in,
+ * if any.
+ */
+ void OnInitialized();
+
+ /**
+ * Sets the current loading status.
+ */
+ void SetStatus(mozilla::dom::FontFaceLoadStatus aStatus);
+
+ void GetDesc(nsCSSFontDesc aDescID,
+ nsCSSProperty aPropID,
+ nsString& aResult) const;
+
+ /**
+ * Returns and takes ownership of the buffer storing the font data.
+ */
+ void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
+
+ nsCOMPtr<nsISupports> mParent;
+ nsPresContext* mPresContext;
+
+ // A Promise that is fulfilled once the font represented by this FontFace
+ // is loaded, and is rejected if the load fails.
+ nsRefPtr<mozilla::dom::Promise> mLoaded;
+
+ // The @font-face rule this FontFace object is reflecting, if it is a
+ // rule backed FontFace.
+ nsRefPtr<nsCSSFontFaceRule> mRule;
+
+ // The FontFace object's user font entry. This is initially null, but is set
+ // during FontFaceSet::UpdateRules and when a FontFace is explicitly loaded.
+ nsRefPtr<Entry> mUserFontEntry;
+
+ // The current load status of the font represented by this FontFace.
+ // Note that we can't just reflect the value of the gfxUserFontEntry's
+ // status, since the spec sometimes requires us to go through the event
+ // loop before updating the status, rather than doing it immediately.
+ mozilla::dom::FontFaceLoadStatus mStatus;
+
+ // Represents where a FontFace's data is coming from.
+ enum SourceType {
+ eSourceType_FontFaceRule = 1,
+ eSourceType_URLs,
+ eSourceType_Buffer
+ };
+
+ // Where the font data for this FontFace is coming from.
+ SourceType mSourceType;
+
+ // If the FontFace was constructed with an ArrayBuffer(View), this is a
+ // copy of the data from it.
+ uint8_t* mSourceBuffer;
+ uint32_t mSourceBufferLength;
+
+ // The values corresponding to the font face descriptors, if we are not
+ // a rule backed FontFace object. For rule backed objects, we use
+ // the descriptors stored in mRule.
+ nsAutoPtr<mozilla::CSSFontFaceDescriptors> mDescriptors;
+
+ // The FontFaceSet this FontFace is associated with, regardless of whether
+ // it is currently "in" the set.
+ nsRefPtr<FontFaceSet> mFontFaceSet;
+
+ // Whether this FontFace appears in the FontFaceSet.
+ bool mInFontFaceSet;
+
+ // Whether the FontFace has been fully initialized. This takes at least one
+ // run around the event loop, as the parsing of the src descriptor is done
+ // off an event queue task.
+ bool mInitialized;
+
+ // Records whether Load() was called on this FontFace before it was
+ // initialized. When the FontFace eventually does become initialized,
+ // mLoadPending is checked and Load() is called if needed.
+ bool mLoadWhenInitialized;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // !defined(mozilla_dom_FontFace_h)
new file mode 100644
--- /dev/null
+++ b/layout/style/FontFaceSet.cpp
@@ -0,0 +1,1594 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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/. */
+
+#include "FontFaceSet.h"
+
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG /* Allow logging in the release build */
+#endif /* MOZ_LOGGING */
+#include "prlog.h"
+
+#include "mozilla/css/Loader.h"
+#include "mozilla/dom/CSSFontFaceLoadEvent.h"
+#include "mozilla/dom/CSSFontFaceLoadEventBinding.h"
+#include "mozilla/dom/FontFaceSetBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/AsyncEventDispatcher.h"
+#include "nsCrossSiteListenerProxy.h"
+#include "nsFontFaceLoader.h"
+#include "nsIChannelPolicy.h"
+#include "nsIConsoleService.h"
+#include "nsIContentPolicy.h"
+#include "nsIContentSecurityPolicy.h"
+#include "nsIDocShell.h"
+#include "nsIDocument.h"
+#include "nsINetworkPredictor.h"
+#include "nsIPresShell.h"
+#include "nsIPrincipal.h"
+#include "nsISupportsPriority.h"
+#include "nsIWebNavigation.h"
+#include "nsNetUtil.h"
+#include "nsPresContext.h"
+#include "nsPrintfCString.h"
+#include "nsStyleSet.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo*
+GetFontFaceSetLog()
+{
+ static PRLogModuleInfo* sLog;
+ if (!sLog)
+ sLog = PR_NewLogModule("fontfaceset");
+ return sLog;
+}
+#endif /* PR_LOGGING */
+
+#define LOG(args) PR_LOG(GetFontFaceSetLog(), PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(GetFontFaceSetLog(), PR_LOG_DEBUG)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FontFaceSet)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReady);
+ for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleFaces[i].mFontFace);
+ }
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonRuleFaces);
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
+ tmp->Disconnect();
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mReady);
+ for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mRuleFaces[i].mFontFace);
+ }
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonRuleFaces);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ADDREF_INHERITED(FontFaceSet, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(FontFaceSet, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FontFaceSet)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
+ NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+FontFaceSet::FontFaceSet(nsPIDOMWindow* aWindow, nsPresContext* aPresContext)
+ : DOMEventTargetHelper(aWindow)
+ , mPresContext(aPresContext)
+ , mDocument(aPresContext->Document())
+ , mStatus(FontFaceSetLoadStatus::Loaded)
+ , mNonRuleFacesDirty(false)
+ , mReadyIsResolved(true)
+ , mDispatchedLoadingEvent(false)
+ , mHasLoadingFontFaces(false)
+ , mHasLoadingFontFacesIsDirty(false)
+{
+ MOZ_COUNT_CTOR(FontFaceSet);
+
+ nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
+
+ if (global) {
+ ErrorResult rv;
+ mReady = Promise::Create(global, rv);
+ }
+
+ if (mReady) {
+ mReady->MaybeResolve(this);
+ }
+
+ if (!mDocument->DidFireDOMContentLoaded()) {
+ mDocument->AddSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
+ this, false, false);
+ }
+
+ mDocument->CSSLoader()->AddObserver(this);
+}
+
+FontFaceSet::~FontFaceSet()
+{
+ MOZ_COUNT_DTOR(FontFaceSet);
+
+ NS_ASSERTION(mLoaders.Count() == 0, "mLoaders should have been emptied");
+
+ Disconnect();
+}
+
+JSObject*
+FontFaceSet::WrapObject(JSContext* aContext)
+{
+ return FontFaceSetBinding::Wrap(aContext, this);
+}
+
+void
+FontFaceSet::Disconnect()
+{
+ if (mDocument) {
+ mDocument->RemoveSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
+ this, false);
+ // We're null checking CSSLoader() since FontFaceSet::Disconnect() might be
+ // being called during unlink, at which time the loader amy already have
+ // been unlinked from the document.
+ if (mDocument->CSSLoader()) {
+ mDocument->CSSLoader()->RemoveObserver(this);
+ }
+ }
+}
+
+FontFaceSet::UserFontSet*
+FontFaceSet::EnsureUserFontSet(nsPresContext* aPresContext)
+{
+ if (!mUserFontSet) {
+ mUserFontSet = new UserFontSet(this);
+ mPresContext = aPresContext;
+ }
+ return mUserFontSet;
+}
+
+already_AddRefed<Promise>
+FontFaceSet::Load(const nsAString& aFont,
+ const nsAString& aText,
+ ErrorResult& aRv)
+{
+ aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+ return nullptr;
+}
+
+bool
+FontFaceSet::Check(const nsAString& aFont,
+ const nsAString& aText,
+ ErrorResult& aRv)
+{
+ aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+ return false;
+}
+
+Promise*
+FontFaceSet::GetReady(ErrorResult& aRv)
+{
+ if (!mReady) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ mPresContext->FlushUserFontSet();
+ return mReady;
+}
+
+FontFaceSetLoadStatus
+FontFaceSet::Status()
+{
+ mPresContext->FlushUserFontSet();
+ return mStatus;
+}
+
+#ifdef DEBUG
+bool
+FontFaceSet::HasRuleFontFace(FontFace* aFontFace)
+{
+ for (size_t i = 0; i < mRuleFaces.Length(); i++) {
+ if (mRuleFaces[i].mFontFace == aFontFace) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+FontFaceSet*
+FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+
+ // We currently only support FontFace objects being in a single FontFaceSet,
+ // and we also restrict the FontFaceSet to contain only FontFaces created
+ // in the same window.
+
+ if (aFontFace.GetFontFaceSet() != this) {
+ aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+ return nullptr;
+ }
+
+ if (aFontFace.HasRule()) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
+ return nullptr;
+ }
+
+ if (aFontFace.IsInFontFaceSet()) {
+ return this;
+ }
+
+ bool removed = mUnavailableFaces.RemoveElement(&aFontFace);
+ if (!removed) {
+ MOZ_ASSERT(false, "should have found aFontFace in mUnavailableFaces");
+ return this;
+ }
+
+ aFontFace.SetIsInFontFaceSet(true);
+
+ MOZ_ASSERT(!mNonRuleFaces.Contains(&aFontFace),
+ "FontFace should not occur in mNonRuleFaces twice");
+
+ mNonRuleFaces.AppendElement(&aFontFace);
+
+ mNonRuleFacesDirty = true;
+ mPresContext->RebuildUserFontSet();
+ mHasLoadingFontFacesIsDirty = true;
+ CheckLoadingStarted();
+ return this;
+}
+
+void
+FontFaceSet::Clear()
+{
+ mPresContext->FlushUserFontSet();
+
+ if (mNonRuleFaces.IsEmpty()) {
+ return;
+ }
+
+ for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
+ FontFace* f = mNonRuleFaces[i];
+ f->SetIsInFontFaceSet(false);
+
+ MOZ_ASSERT(!mUnavailableFaces.Contains(f),
+ "FontFace should not occur in mUnavailableFaces twice");
+
+ mUnavailableFaces.AppendElement(f);
+ }
+
+ mNonRuleFaces.Clear();
+ mNonRuleFacesDirty = true;
+ mPresContext->RebuildUserFontSet();
+ mHasLoadingFontFacesIsDirty = true;
+ CheckLoadingFinished();
+}
+
+bool
+FontFaceSet::Delete(FontFace& aFontFace, ErrorResult& aRv)
+{
+ mPresContext->FlushUserFontSet();
+
+ if (aFontFace.HasRule()) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
+ return nullptr;
+ }
+
+ if (!mNonRuleFaces.RemoveElement(&aFontFace)) {
+ return false;
+ }
+
+ aFontFace.SetIsInFontFaceSet(false);
+
+ MOZ_ASSERT(!mUnavailableFaces.Contains(&aFontFace),
+ "FontFace should not occur in mUnavailableFaces twice");
+
+ mUnavailableFaces.AppendElement(&aFontFace);
+
+ mNonRuleFacesDirty = true;
+ mPresContext->RebuildUserFontSet();
+ mHasLoadingFontFacesIsDirty = true;
+ CheckLoadingFinished();
+ return true;
+}
+
+bool
+FontFaceSet::HasAvailableFontFace(FontFace* aFontFace)
+{
+ return aFontFace->GetFontFaceSet() == this &&
+ aFontFace->IsInFontFaceSet();
+}
+
+bool
+FontFaceSet::Has(FontFace& aFontFace)
+{
+ mPresContext->FlushUserFontSet();
+
+ return HasAvailableFontFace(&aFontFace);
+}
+
+FontFace*
+FontFaceSet::IndexedGetter(uint32_t aIndex, bool& aFound)
+{
+ mPresContext->FlushUserFontSet();
+
+ if (aIndex < mRuleFaces.Length()) {
+ aFound = true;
+ return mRuleFaces[aIndex].mFontFace;
+ }
+
+ aIndex -= mRuleFaces.Length();
+ if (aIndex < mNonRuleFaces.Length()) {
+ aFound = true;
+ return mNonRuleFaces[aIndex];
+ }
+
+ aFound = false;
+ return nullptr;
+}
+
+uint32_t
+FontFaceSet::Length()
+{
+ mPresContext->FlushUserFontSet();
+
+ // Web IDL objects can only expose array index properties up to INT32_MAX.
+
+ size_t total = mRuleFaces.Length() + mNonRuleFaces.Length();
+ return std::min<size_t>(total, INT32_MAX);
+}
+
+static PLDHashOperator DestroyIterator(nsPtrHashKey<nsFontFaceLoader>* aKey,
+ void* aUserArg)
+{
+ aKey->GetKey()->Cancel();
+ return PL_DHASH_REMOVE;
+}
+
+void
+FontFaceSet::DestroyUserFontSet()
+{
+ Disconnect();
+ mDocument = nullptr;
+ mPresContext = nullptr;
+ mLoaders.EnumerateEntries(DestroyIterator, nullptr);
+ for (size_t i = 0; i < mRuleFaces.Length(); i++) {
+ mRuleFaces[i].mFontFace->DisconnectFromRule();
+ mRuleFaces[i].mFontFace->SetUserFontEntry(nullptr);
+ }
+ for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
+ mNonRuleFaces[i]->SetUserFontEntry(nullptr);
+ }
+ for (size_t i = 0; i < mUnavailableFaces.Length(); i++) {
+ mUnavailableFaces[i]->SetUserFontEntry(nullptr);
+ }
+ mRuleFaces.Clear();
+ mNonRuleFaces.Clear();
+ mUnavailableFaces.Clear();
+ mReady = nullptr;
+ mUserFontSet = nullptr;
+}
+
+void
+FontFaceSet::RemoveLoader(nsFontFaceLoader* aLoader)
+{
+ mLoaders.RemoveEntry(aLoader);
+}
+
+nsresult
+FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
+ const gfxFontFaceSrc* aFontFaceSrc)
+{
+ nsresult rv;
+
+ nsIPresShell* ps = mPresContext->PresShell();
+ if (!ps)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIStreamLoader> streamLoader;
+ nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
+
+ nsCOMPtr<nsIChannel> channel;
+ // get Content Security Policy from principal to pass into channel
+ nsCOMPtr<nsIChannelPolicy> channelPolicy;
+ nsCOMPtr<nsIContentSecurityPolicy> csp;
+ rv = aUserFontEntry->GetPrincipal()->GetCsp(getter_AddRefs(csp));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (csp) {
+ channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
+ channelPolicy->SetContentSecurityPolicy(csp);
+ channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
+ }
+ // Note we are calling NS_NewChannelInternal() with both a node and a
+ // principal. This is because the document where the font is being loaded
+ // might have a different origin from the principal of the stylesheet
+ // that initiated the font load.
+ rv = NS_NewChannelInternal(getter_AddRefs(channel),
+ aFontFaceSrc->mURI,
+ ps->GetDocument(),
+ aUserFontEntry->GetPrincipal(),
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_FONT,
+ channelPolicy,
+ loadGroup);
+
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsRefPtr<nsFontFaceLoader> fontLoader =
+ new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI, this, channel);
+
+ if (!fontLoader)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+#ifdef PR_LOGGING
+ if (LOG_ENABLED()) {
+ nsAutoCString fontURI, referrerURI;
+ aFontFaceSrc->mURI->GetSpec(fontURI);
+ if (aFontFaceSrc->mReferrer)
+ aFontFaceSrc->mReferrer->GetSpec(referrerURI);
+ LOG(("fontdownloader (%p) download start - font uri: (%s) "
+ "referrer uri: (%s)\n",
+ fontLoader.get(), fontURI.get(), referrerURI.get()));
+ }
+#endif
+
+ nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
+ if (httpChannel)
+ httpChannel->SetReferrer(aFontFaceSrc->mReferrer);
+ nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
+ if (priorityChannel) {
+ priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
+ }
+
+ rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIDocument *document = ps->GetDocument();
+ mozilla::net::PredictorLearn(aFontFaceSrc->mURI, document->GetDocumentURI(),
+ nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
+ loadGroup);
+
+ bool inherits = false;
+ rv = NS_URIChainHasFlags(aFontFaceSrc->mURI,
+ nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
+ &inherits);
+ if (NS_SUCCEEDED(rv) && inherits) {
+ // allow data, javascript, etc URI's
+ rv = channel->AsyncOpen(streamLoader, nullptr);
+ } else {
+ nsRefPtr<nsCORSListenerProxy> listener =
+ new nsCORSListenerProxy(streamLoader, aUserFontEntry->GetPrincipal(), false);
+ rv = listener->Init(channel);
+ if (NS_SUCCEEDED(rv)) {
+ rv = channel->AsyncOpen(listener, nullptr);
+ }
+ if (NS_FAILED(rv)) {
+ fontLoader->DropChannel(); // explicitly need to break ref cycle
+ }
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ mLoaders.PutEntry(fontLoader);
+ fontLoader->StartedLoading(streamLoader);
+ aUserFontEntry->SetLoader(fontLoader); // let the font entry remember the
+ // loader, in case we need to cancel it
+ }
+
+ return rv;
+}
+
+static PLDHashOperator DetachFontEntries(const nsAString& aKey,
+ nsRefPtr<gfxUserFontFamily>& aFamily,
+ void* aUserArg)
+{
+ aFamily->DetachFontEntries();
+ return PL_DHASH_NEXT;
+}
+
+static PLDHashOperator RemoveIfEmpty(const nsAString& aKey,
+ nsRefPtr<gfxUserFontFamily>& aFamily,
+ void* aUserArg)
+{
+ return aFamily->GetFontList().Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
+}
+
+bool
+FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
+{
+ MOZ_ASSERT(mUserFontSet);
+
+ // If there was a change to the mNonRuleFaces array, then there could
+ // have been a modification to the user font set.
+ bool modified = mNonRuleFacesDirty;
+ mNonRuleFacesDirty = false;
+
+ // The @font-face rules that make up the user font set have changed,
+ // so we need to update the set. However, we want to preserve existing
+ // font entries wherever possible, so that we don't discard and then
+ // re-download resources in the (common) case where at least some of the
+ // same rules are still present.
+
+ nsTArray<FontFaceRecord> oldRecords;
+ mRuleFaces.SwapElements(oldRecords);
+
+ // Remove faces from the font family records; we need to re-insert them
+ // because we might end up with faces in a different order even if they're
+ // the same font entries as before. (The order can affect font selection
+ // where multiple faces match the requested style, perhaps with overlapping
+ // unicode-range coverage.)
+ mUserFontSet->mFontFamilies.Enumerate(DetachFontEntries, nullptr);
+
+ // Sometimes aRules has duplicate @font-face rules in it; we should make
+ // that not happen, but in the meantime, don't try to insert the same
+ // FontFace object more than once into mRuleFaces. We track which
+ // ones we've handled in this table.
+ nsTHashtable<nsPtrHashKey<nsCSSFontFaceRule>> handledRules;
+
+ for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
+ // Insert each FontFace objects for each rule into our list, migrating old
+ // font entries if possible rather than creating new ones; set modified to
+ // true if we detect that rule ordering has changed, or if a new entry is
+ // created.
+ if (handledRules.Contains(aRules[i].mRule)) {