зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to fx-team
This commit is contained in:
Коммит
b1214c5765
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<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="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
<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="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<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="67f2907bc340bad250b4ea6ce2902b52896c9ef0"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</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="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<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="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
<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="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<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="67f2907bc340bad250b4ea6ce2902b52896c9ef0"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<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="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</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="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "2e0f2f070a2265b537e6a2ff4e0f2e1f2aca49c6",
|
||||
"revision": "c1bed74af46cb81a7092d6e80624134bae5d1bf0",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
<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="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<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="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</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="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="be8b0151d2f9a4c41fc63952128e0b723cd1161d"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a222358a6210c0bb94e53e036ec8c73dc2e3d4d0"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
|
||||
<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="dfb7845803f3afcdcf157c5babec357bf9ce74eb"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0494efbb157e863dec6f1fd4d4652b0917ce263d"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
|
|
@ -219,13 +219,8 @@ var gPrivacyPane = {
|
|||
// select the remember forms history option
|
||||
document.getElementById("browser.formfill.enable").value = true;
|
||||
|
||||
#ifdef RELEASE_BUILD
|
||||
// select the allow cookies option
|
||||
document.getElementById("network.cookie.cookieBehavior").value = 0;
|
||||
#else
|
||||
// select the limit cookies option
|
||||
document.getElementById("network.cookie.cookieBehavior").value = 3;
|
||||
#endif
|
||||
// select the cookie lifetime policy option
|
||||
document.getElementById("network.cookie.lifetimePolicy").value = 0;
|
||||
|
||||
|
@ -421,19 +416,11 @@ var gPrivacyPane = {
|
|||
var accept = document.getElementById("acceptCookies");
|
||||
var acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
|
||||
|
||||
#ifdef RELEASE_BUILD
|
||||
// if we're enabling cookies, automatically select 'accept third party always'
|
||||
if (accept.checked)
|
||||
acceptThirdPartyMenu.selectedIndex = 0;
|
||||
|
||||
return accept.checked ? 0 : 2;
|
||||
#else
|
||||
// if we're enabling cookies, automatically select 'accept third party from visited'
|
||||
if (accept.checked)
|
||||
acceptThirdPartyMenu.selectedIndex = 1;
|
||||
|
||||
return accept.checked ? 3 : 2;
|
||||
#endif
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,14 +17,10 @@ function test() {
|
|||
test_custom_retention("acceptCookies", "remember"),
|
||||
test_custom_retention("acceptCookies", "custom")
|
||||
],
|
||||
(runtime.isReleaseBuild ? [
|
||||
[
|
||||
test_custom_retention("acceptThirdPartyMenu", "remember", "visited"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "custom", "always")
|
||||
]
|
||||
: [
|
||||
test_custom_retention("acceptThirdPartyMenu", "remember", "always"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "custom", "visited")
|
||||
]), [
|
||||
], [
|
||||
test_custom_retention("keepCookiesUntil", "remember", 1),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 2),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 0),
|
||||
|
|
|
@ -185,13 +185,8 @@ var gPrivacyPane = {
|
|||
// select the remember forms history option
|
||||
document.getElementById("browser.formfill.enable").value = true;
|
||||
|
||||
#ifdef RELEASE_BUILD
|
||||
// select the accept cookies option
|
||||
document.getElementById("network.cookie.cookieBehavior").value = 0;
|
||||
#else
|
||||
// select the limit cookies option
|
||||
document.getElementById("network.cookie.cookieBehavior").value = 3;
|
||||
#endif
|
||||
// select the cookie lifetime policy option
|
||||
document.getElementById("network.cookie.lifetimePolicy").value = 0;
|
||||
|
||||
|
@ -388,19 +383,11 @@ var gPrivacyPane = {
|
|||
var accept = document.getElementById("acceptCookies");
|
||||
var acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
|
||||
|
||||
#ifdef RELEASE_BUILD
|
||||
// if we're enabling cookies, automatically select 'accept third party always'
|
||||
if (accept.checked)
|
||||
acceptThirdPartyMenu.selectedIndex = 0;
|
||||
|
||||
return accept.checked ? 0 : 2;
|
||||
#else
|
||||
// if we're enabling cookies, automatically select 'accept third party from visited'
|
||||
if (accept.checked)
|
||||
acceptThirdPartyMenu.selectedIndex = 1;
|
||||
|
||||
return accept.checked ? 3 : 2;
|
||||
#endif
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,14 +18,10 @@ function test() {
|
|||
test_custom_retention("acceptCookies", "remember"),
|
||||
test_custom_retention("acceptCookies", "custom")
|
||||
],
|
||||
(runtime.isReleaseBuild ? [
|
||||
[
|
||||
test_custom_retention("acceptThirdPartyMenu", "remember", "visited"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "custom", "always")
|
||||
]
|
||||
: [
|
||||
test_custom_retention("acceptThirdPartyMenu", "remember", "always"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "custom", "visited")
|
||||
]), [
|
||||
], [
|
||||
test_custom_retention("keepCookiesUntil", "remember", 1),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 2),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 0),
|
||||
|
|
|
@ -14768,6 +14768,25 @@ class CGEventMethod(CGNativeMember):
|
|||
target += ".SetValue()"
|
||||
source += ".Value()"
|
||||
members += sequenceCopy % (target, source)
|
||||
elif m.type.isSpiderMonkeyInterface():
|
||||
srcname = "%s.%s" % (self.args[1].name, name)
|
||||
if m.type.nullable():
|
||||
members += fill(
|
||||
"""
|
||||
if (${srcname}.IsNull()) {
|
||||
e->${varname} = nullptr;
|
||||
} else {
|
||||
e->${varname} = ${srcname}.Value().Obj();
|
||||
}
|
||||
""",
|
||||
varname=name,
|
||||
srcname=srcname);
|
||||
else:
|
||||
members += fill(
|
||||
"""
|
||||
e->${varname}.set(${srcname}.Obj());
|
||||
""",
|
||||
varname=name, srcname=srcname);
|
||||
else:
|
||||
members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
|
||||
if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
|
||||
|
|
|
@ -1357,6 +1357,25 @@ CanvasRenderingContext2D::ClearTarget()
|
|||
state->colorStyles[Style::FILL] = NS_RGB(0,0,0);
|
||||
state->colorStyles[Style::STROKE] = NS_RGB(0,0,0);
|
||||
state->shadowColor = NS_RGBA(0,0,0,0);
|
||||
|
||||
// For vertical writing-mode, unless text-orientation is sideways,
|
||||
// we'll modify the initial value of textBaseline to 'middle'.
|
||||
nsRefPtr<nsStyleContext> canvasStyle;
|
||||
if (mCanvasElement && mCanvasElement->IsInDoc()) {
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
if (presShell) {
|
||||
canvasStyle =
|
||||
nsComputedDOMStyle::GetStyleContextForElement(mCanvasElement,
|
||||
nullptr,
|
||||
presShell);
|
||||
if (canvasStyle) {
|
||||
WritingMode wm(canvasStyle);
|
||||
if (wm.IsVertical() && !wm.IsSideways()) {
|
||||
state->textBaseline = TextBaseline::MIDDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -3149,6 +3168,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
|
|||
gfxPoint point = mPt;
|
||||
bool rtl = mTextRun->IsRightToLeft();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool centerBaseline = mTextRun->UseCenterBaseline();
|
||||
|
||||
gfxFloat& inlineCoord = verticalRun ? point.y : point.x;
|
||||
inlineCoord += xOffset;
|
||||
|
@ -3217,20 +3237,27 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
|
|||
if (runs[c].mOrientation ==
|
||||
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT) {
|
||||
sidewaysRestore.Init(mCtx->mTarget);
|
||||
// TODO: The baseline adjustment here is kinda ad-hoc; eventually
|
||||
// perhaps we should check for horizontal and vertical baseline data
|
||||
// in the font, and adjust accordingly.
|
||||
// (The same will be true for HTML text layout.)
|
||||
const gfxFont::Metrics& metrics = mTextRun->GetFontGroup()->
|
||||
GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal);
|
||||
mCtx->mTarget->SetTransform(mCtx->mTarget->GetTransform().Copy().
|
||||
|
||||
gfx::Matrix mat = mCtx->mTarget->GetTransform().Copy().
|
||||
PreTranslate(baselineOrigin). // translate origin for rotation
|
||||
PreRotate(gfx::Float(M_PI / 2.0)). // turn 90deg clockwise
|
||||
PreTranslate(-baselineOrigin). // undo the translation
|
||||
PreTranslate(Point(0, (metrics.emAscent - metrics.emDescent) / 2)));
|
||||
// and offset the (alphabetic) baseline of the
|
||||
PreTranslate(-baselineOrigin); // undo the translation
|
||||
|
||||
if (centerBaseline) {
|
||||
// TODO: The baseline adjustment here is kinda ad hoc; eventually
|
||||
// perhaps we should check for horizontal and vertical baseline data
|
||||
// in the font, and adjust accordingly.
|
||||
// (The same will be true for HTML text layout.)
|
||||
float offset = (metrics.emAscent - metrics.emDescent) / 2;
|
||||
mat = mat.PreTranslate(Point(0, offset));
|
||||
// offset the (alphabetic) baseline of the
|
||||
// horizontally-shaped text from the (centered)
|
||||
// default baseline used for vertical
|
||||
}
|
||||
|
||||
mCtx->mTarget->SetTransform(mat);
|
||||
}
|
||||
|
||||
RefPtr<GlyphRenderingOptions> renderingOptions = font->GetGlyphRenderingOptions();
|
||||
|
@ -3522,39 +3549,45 @@ CanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
|||
|
||||
processor.mPt.x -= anchorX * totalWidth;
|
||||
|
||||
// offset pt.y based on text baseline
|
||||
// offset pt.y (or pt.x, for vertical text) based on text baseline
|
||||
processor.mFontgrp->UpdateUserFonts(); // ensure user font generation is current
|
||||
const gfxFont::Metrics& fontMetrics =
|
||||
processor.mFontgrp->GetFirstValidFont()->GetMetrics(
|
||||
((processor.mTextRunFlags & gfxTextRunFactory::TEXT_ORIENT_MASK) ==
|
||||
gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL)
|
||||
? gfxFont::eHorizontal : gfxFont::eVertical);
|
||||
processor.mFontgrp->GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal);
|
||||
|
||||
gfxFloat anchorY;
|
||||
gfxFloat baselineAnchor;
|
||||
|
||||
switch (state.textBaseline)
|
||||
{
|
||||
case TextBaseline::HANGING:
|
||||
// fall through; best we can do with the information available
|
||||
case TextBaseline::TOP:
|
||||
anchorY = fontMetrics.emAscent;
|
||||
baselineAnchor = fontMetrics.emAscent;
|
||||
break;
|
||||
case TextBaseline::MIDDLE:
|
||||
anchorY = (fontMetrics.emAscent - fontMetrics.emDescent) * .5f;
|
||||
baselineAnchor = (fontMetrics.emAscent - fontMetrics.emDescent) * .5f;
|
||||
break;
|
||||
case TextBaseline::IDEOGRAPHIC:
|
||||
// fall through; best we can do with the information available
|
||||
case TextBaseline::ALPHABETIC:
|
||||
anchorY = 0;
|
||||
baselineAnchor = 0;
|
||||
break;
|
||||
case TextBaseline::BOTTOM:
|
||||
anchorY = -fontMetrics.emDescent;
|
||||
baselineAnchor = -fontMetrics.emDescent;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected TextBaseline");
|
||||
}
|
||||
|
||||
processor.mPt.y += anchorY;
|
||||
if (processor.mTextRun->IsVertical()) {
|
||||
if (processor.mTextRun->UseCenterBaseline()) {
|
||||
// Adjust to account for mTextRun being shaped using center baseline
|
||||
// rather than alphabetic.
|
||||
baselineAnchor -= (fontMetrics.emAscent - fontMetrics.emDescent) * .5f;
|
||||
}
|
||||
processor.mPt.x -= baselineAnchor;
|
||||
} else {
|
||||
processor.mPt.y += baselineAnchor;
|
||||
}
|
||||
|
||||
// correct bounding box to get it to be the correct size/position
|
||||
processor.mBoundingBox.width = totalWidth;
|
||||
|
|
|
@ -1793,28 +1793,31 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
|
|||
}
|
||||
#endif
|
||||
OutputMediaStream* out = mOutputStreams.AppendElement();
|
||||
#ifdef DEBUG
|
||||
// Estimate hints based on the type of the media element
|
||||
// under the preference media.capturestream_hints for the
|
||||
// debug builds only. This allows WebRTC Peer Connection
|
||||
// to behave appropriately when media streams generated
|
||||
// via mozCaptureStream*() are added to the Peer Connection.
|
||||
// This functionality is planned to be used as part of Audio
|
||||
// Quality Performance testing for WebRTC.
|
||||
// Bug932845: Revisit this once hints mechanism is dealt with
|
||||
// holistically.
|
||||
uint8_t hints = 0;
|
||||
if (Preferences::GetBool("media.capturestream_hints.enabled")) {
|
||||
if (IsVideo() && GetVideoFrameContainer()) {
|
||||
hints = DOMMediaStream::HINT_CONTENTS_VIDEO | DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
} else {
|
||||
hints = DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
||||
hints = (mHasAudio? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) |
|
||||
(mHasVideo? DOMMediaStream::HINT_CONTENTS_VIDEO : 0);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
// Estimate hints based on the type of the media element
|
||||
// under the preference media.capturestream_hints for the
|
||||
// debug builds only. This allows WebRTC Peer Connection
|
||||
// to behave appropriately when media streams generated
|
||||
// via mozCaptureStream*() are added to the Peer Connection.
|
||||
// This functionality is planned to be used as part of Audio
|
||||
// Quality Performance testing for WebRTC.
|
||||
// Bug932845: Revisit this once hints mechanism is dealt with
|
||||
// holistically.
|
||||
if (Preferences::GetBool("media.capturestream_hints.enabled")) {
|
||||
if (IsVideo() && GetVideoFrameContainer()) {
|
||||
hints = DOMMediaStream::HINT_CONTENTS_VIDEO | DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
} else {
|
||||
hints = DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
out->mStream = DOMMediaStream::CreateTrackUnionStream(window, hints);
|
||||
#else
|
||||
out->mStream = DOMMediaStream::CreateTrackUnionStream(window);
|
||||
#endif
|
||||
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
|
||||
out->mStream->CombineWithPrincipal(principal);
|
||||
out->mFinishWhenEnded = aFinishWhenEnded;
|
||||
|
|
|
@ -8734,16 +8734,15 @@ FileManager::Invalidate()
|
|||
{
|
||||
public:
|
||||
static PLDHashOperator
|
||||
CopyToTArray(const uint64_t& aKey, FileInfo* aValue, void* aUserArg)
|
||||
ClearDBRefs(const uint64_t& aKey, FileInfo*& aValue, void* aUserArg)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
|
||||
auto* array = static_cast<FallibleTArray<FileInfo*>*>(aUserArg);
|
||||
MOZ_ASSERT(array);
|
||||
if (aValue->LockedClearDBRefs()) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(array->AppendElement(aValue));
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8752,26 +8751,12 @@ FileManager::Invalidate()
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
FallibleTArray<FileInfo*> fileInfos;
|
||||
{
|
||||
MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
|
||||
MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
|
||||
|
||||
MOZ_ASSERT(!mInvalidated);
|
||||
mInvalidated = true;
|
||||
MOZ_ASSERT(!mInvalidated);
|
||||
mInvalidated = true;
|
||||
|
||||
if (NS_WARN_IF(!fileInfos.SetCapacity(mFileInfos.Count()))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mFileInfos.EnumerateRead(Helper::CopyToTArray, &fileInfos);
|
||||
}
|
||||
|
||||
for (uint32_t count = fileInfos.Length(), index = 0; index < count; index++) {
|
||||
FileInfo* fileInfo = fileInfos[index];
|
||||
MOZ_ASSERT(fileInfo);
|
||||
|
||||
fileInfo->ClearDBRefs();
|
||||
}
|
||||
mFileInfos.Enumerate(Helper::ClearDBRefs, nullptr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -130,15 +130,13 @@ FileInfo::GetReferences(int32_t* aRefCnt,
|
|||
|
||||
void
|
||||
FileInfo::UpdateReferences(ThreadSafeAutoRefCnt& aRefCount,
|
||||
int32_t aDelta,
|
||||
bool aClear)
|
||||
int32_t aDelta)
|
||||
{
|
||||
// XXX This can go away once DOM objects no longer hold FileInfo objects...
|
||||
// Looking at you, IDBMutableFile...
|
||||
if (IndexedDatabaseManager::IsClosed()) {
|
||||
MOZ_ASSERT(&aRefCount == &mRefCnt);
|
||||
MOZ_ASSERT(aDelta == 1 || aDelta == -1);
|
||||
MOZ_ASSERT(!aClear);
|
||||
|
||||
if (aDelta > 0) {
|
||||
++aRefCount;
|
||||
|
@ -158,7 +156,7 @@ FileInfo::UpdateReferences(ThreadSafeAutoRefCnt& aRefCount,
|
|||
{
|
||||
MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
|
||||
|
||||
aRefCount = aClear ? 0 : aRefCount + aDelta;
|
||||
aRefCount = aRefCount + aDelta;
|
||||
|
||||
if (mRefCnt + mDBRefCnt + mSliceRefCnt > 0) {
|
||||
return;
|
||||
|
@ -176,6 +174,29 @@ FileInfo::UpdateReferences(ThreadSafeAutoRefCnt& aRefCount,
|
|||
delete this;
|
||||
}
|
||||
|
||||
bool
|
||||
FileInfo::LockedClearDBRefs()
|
||||
{
|
||||
MOZ_ASSERT(!IndexedDatabaseManager::IsClosed());
|
||||
|
||||
IndexedDatabaseManager::FileMutex().AssertCurrentThreadOwns();
|
||||
|
||||
mDBRefCnt = 0;
|
||||
|
||||
if (mRefCnt || mSliceRefCnt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// In this case, we are not responsible for removing the file info from the
|
||||
// hashtable. It's up to FileManager which is the only caller of this method.
|
||||
|
||||
MOZ_ASSERT(mFileManager->Invalidated());
|
||||
|
||||
delete this;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
FileInfo::Cleanup()
|
||||
{
|
||||
|
|
|
@ -50,12 +50,6 @@ public:
|
|||
UpdateReferences(mDBRefCnt, aDelta);
|
||||
}
|
||||
|
||||
void
|
||||
ClearDBRefs()
|
||||
{
|
||||
UpdateReferences(mDBRefCnt, 0, true);
|
||||
}
|
||||
|
||||
void
|
||||
UpdateSliceRefs(int32_t aDelta)
|
||||
{
|
||||
|
@ -80,8 +74,10 @@ protected:
|
|||
private:
|
||||
void
|
||||
UpdateReferences(ThreadSafeAutoRefCnt& aRefCount,
|
||||
int32_t aDelta,
|
||||
bool aClear = false);
|
||||
int32_t aDelta);
|
||||
|
||||
bool
|
||||
LockedClearDBRefs();
|
||||
|
||||
void
|
||||
Cleanup();
|
||||
|
|
|
@ -158,6 +158,10 @@ OpusTrackEncoder::Init(int aChannels, int aSamplingRate)
|
|||
// let InterleaveTrackData downmix pcm data.
|
||||
mChannels = aChannels > MAX_CHANNELS ? MAX_CHANNELS : aChannels;
|
||||
|
||||
// Reject non-audio sample rates.
|
||||
NS_ENSURE_TRUE(aSamplingRate >= 8000, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aSamplingRate <= 192000, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// According to www.opus-codec.org, creating an opus encoder requires the
|
||||
// sampling rate of source signal be one of 8000, 12000, 16000, 24000, or
|
||||
// 48000. If this constraint is not satisfied, we resample the input to 48kHz.
|
||||
|
|
|
@ -49,10 +49,10 @@ VorbisTrackEncoder::~VorbisTrackEncoder()
|
|||
nsresult
|
||||
VorbisTrackEncoder::Init(int aChannels, int aSamplingRate)
|
||||
{
|
||||
if (aChannels <= 0 || aChannels > 8) {
|
||||
VORBISLOG("aChannels <= 0 || aChannels > 8");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
NS_ENSURE_TRUE(aChannels > 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aChannels <= 8, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aSamplingRate >= 8000, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aSamplingRate <= 192000, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// This monitor is used to wake up other methods that are waiting for encoder
|
||||
// to be completely initialized.
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "MP4Reader.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mp4_demuxer/Adts.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "nsIThread.h"
|
||||
|
@ -33,10 +32,11 @@ AppleATDecoder::AppleATDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
|||
, mCallback(aCallback)
|
||||
, mConverter(nullptr)
|
||||
, mStream(nullptr)
|
||||
, mCurrentAudioTimestamp(0)
|
||||
, mCurrentAudioTimestamp(-1)
|
||||
, mNextAudioTimestamp(-1)
|
||||
, mSamplePosition(0)
|
||||
, mHaveOutput(false)
|
||||
, mFlushed(false)
|
||||
, mSizeDecoded(0)
|
||||
, mLastError(noErr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(AppleATDecoder);
|
||||
LOG("Creating Apple AudioToolbox decoder");
|
||||
|
@ -238,8 +238,7 @@ AppleATDecoder::SampleCallback(uint32_t aNumBytes,
|
|||
// Pick a multiple of the frame size close to a power of two
|
||||
// for efficient allocation.
|
||||
const uint32_t MAX_AUDIO_FRAMES = 128;
|
||||
const uint32_t decodedSize = MAX_AUDIO_FRAMES * mConfig.channel_count *
|
||||
sizeof(AudioDataValue);
|
||||
const uint32_t maxDecodedSamples = MAX_AUDIO_FRAMES * mConfig.channel_count;
|
||||
|
||||
// Descriptions for _decompressed_ audio packets. ignored.
|
||||
nsAutoArrayPtr<AudioStreamPacketDescription>
|
||||
|
@ -251,14 +250,15 @@ AppleATDecoder::SampleCallback(uint32_t aNumBytes,
|
|||
PassthroughUserData userData =
|
||||
{ this, aNumPackets, aNumBytes, aData, aPackets, false };
|
||||
|
||||
do {
|
||||
// Decompressed audio buffer
|
||||
nsAutoArrayPtr<uint8_t> decoded(new uint8_t[decodedSize]);
|
||||
// Decompressed audio buffer
|
||||
nsAutoArrayPtr<AudioDataValue> decoded(new AudioDataValue[maxDecodedSamples]);
|
||||
|
||||
do {
|
||||
AudioBufferList decBuffer;
|
||||
decBuffer.mNumberBuffers = 1;
|
||||
decBuffer.mBuffers[0].mNumberChannels = mOutputFormat.mChannelsPerFrame;
|
||||
decBuffer.mBuffers[0].mDataByteSize = decodedSize;
|
||||
decBuffer.mBuffers[0].mDataByteSize =
|
||||
maxDecodedSamples * sizeof(AudioDataValue);
|
||||
decBuffer.mBuffers[0].mData = decoded.get();
|
||||
|
||||
// in: the max number of packets we can handle from the decoder.
|
||||
|
@ -274,50 +274,28 @@ AppleATDecoder::SampleCallback(uint32_t aNumBytes,
|
|||
|
||||
if (rv && rv != kNeedMoreData) {
|
||||
LOG("Error decoding audio stream: %d\n", rv);
|
||||
mCallback->Error();
|
||||
break;
|
||||
}
|
||||
LOG("%d frames decoded", numFrames);
|
||||
|
||||
// If we decoded zero frames then AudioConverterFillComplexBuffer is out
|
||||
// of data to provide. We drained its internal buffer completely on the
|
||||
// last pass.
|
||||
if (numFrames == 0 && rv == kNeedMoreData) {
|
||||
LOG("FillComplexBuffer out of data exactly\n");
|
||||
mCallback->InputExhausted();
|
||||
mLastError = rv;
|
||||
break;
|
||||
}
|
||||
|
||||
const int rate = mOutputFormat.mSampleRate;
|
||||
const int channels = mOutputFormat.mChannelsPerFrame;
|
||||
|
||||
int64_t time = mCurrentAudioTimestamp;
|
||||
int64_t duration = FramesToUsecs(numFrames, rate).value();
|
||||
|
||||
LOG("pushed audio at time %lfs; duration %lfs\n",
|
||||
(double)time / USECS_PER_S, (double)duration / USECS_PER_S);
|
||||
|
||||
AudioData* audio = new AudioData(mSamplePosition,
|
||||
time, duration, numFrames,
|
||||
reinterpret_cast<AudioDataValue*>(decoded.forget()),
|
||||
channels, rate);
|
||||
mCallback->Output(audio);
|
||||
mHaveOutput = true;
|
||||
mOutputData.AppendElements(decoded.get(),
|
||||
numFrames * mConfig.channel_count);
|
||||
|
||||
if (rv == kNeedMoreData) {
|
||||
// No error; we just need more data.
|
||||
LOG("FillComplexBuffer out of data\n");
|
||||
mCallback->InputExhausted();
|
||||
break;
|
||||
}
|
||||
LOG("%d frames decoded", numFrames);
|
||||
} while (true);
|
||||
|
||||
mSizeDecoded += aNumBytes;
|
||||
}
|
||||
|
||||
void
|
||||
AppleATDecoder::SetupDecoder()
|
||||
{
|
||||
LOG("Setting up Apple AudioToolbox decoder.");
|
||||
mHaveOutput = false;
|
||||
|
||||
AudioStreamBasicDescription inputFormat;
|
||||
nsresult rv = AppleUtils::GetRichestDecodableFormat(mStream, inputFormat);
|
||||
|
@ -368,23 +346,84 @@ AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
|
|||
return;
|
||||
}
|
||||
}
|
||||
// Push the sample to the AudioFileStream for parsing.
|
||||
mSamplePosition = aSample->byte_offset;
|
||||
mCurrentAudioTimestamp = aSample->composition_timestamp;
|
||||
uint32_t flags = mFlushed ? kAudioFileStreamParseFlag_Discontinuity : 0;
|
||||
|
||||
const Microseconds fuzz = 5;
|
||||
CheckedInt<Microseconds> upperFuzz = mNextAudioTimestamp + fuzz;
|
||||
CheckedInt<Microseconds> lowerFuzz = mNextAudioTimestamp - fuzz;
|
||||
bool discontinuity =
|
||||
!mNextAudioTimestamp.isValid() || mNextAudioTimestamp.value() < 0 ||
|
||||
!upperFuzz.isValid() || lowerFuzz.value() < 0 ||
|
||||
upperFuzz.value() < aSample->composition_timestamp ||
|
||||
lowerFuzz.value() > aSample->composition_timestamp;
|
||||
|
||||
if (discontinuity) {
|
||||
LOG("Discontinuity detected, expected %lld got %lld\n",
|
||||
mNextAudioTimestamp.value(), aSample->composition_timestamp);
|
||||
mCurrentAudioTimestamp = aSample->composition_timestamp;
|
||||
mSamplePosition = aSample->byte_offset;
|
||||
}
|
||||
|
||||
uint32_t flags = discontinuity ? kAudioFileStreamParseFlag_Discontinuity : 0;
|
||||
|
||||
OSStatus rv = AudioFileStreamParseBytes(mStream,
|
||||
aSample->size,
|
||||
aSample->data,
|
||||
flags);
|
||||
|
||||
if (!mOutputData.IsEmpty()) {
|
||||
int rate = mOutputFormat.mSampleRate;
|
||||
int channels = mOutputFormat.mChannelsPerFrame;
|
||||
size_t numFrames = mOutputData.Length() / channels;
|
||||
CheckedInt<Microseconds> duration = FramesToUsecs(numFrames, rate);
|
||||
if (!duration.isValid()) {
|
||||
NS_ERROR("Invalid count of accumulated audio samples");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("pushed audio at time %lfs; duration %lfs\n",
|
||||
(double)mCurrentAudioTimestamp.value() / USECS_PER_S,
|
||||
(double)duration.value() / USECS_PER_S);
|
||||
|
||||
nsAutoArrayPtr<AudioDataValue>
|
||||
data(new AudioDataValue[mOutputData.Length()]);
|
||||
PodCopy(data.get(), &mOutputData[0], mOutputData.Length());
|
||||
mOutputData.Clear();
|
||||
AudioData* audio = new AudioData(mSamplePosition,
|
||||
mCurrentAudioTimestamp.value(),
|
||||
duration.value(),
|
||||
numFrames,
|
||||
data.forget(),
|
||||
channels,
|
||||
rate);
|
||||
mCallback->Output(audio);
|
||||
mCurrentAudioTimestamp += duration.value();
|
||||
if (!mCurrentAudioTimestamp.isValid()) {
|
||||
NS_ERROR("Invalid count of accumulated audio samples");
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
mSamplePosition += mSizeDecoded;
|
||||
mSizeDecoded = 0;
|
||||
}
|
||||
|
||||
// This is the timestamp of the next sample we should be receiving
|
||||
mNextAudioTimestamp =
|
||||
CheckedInt<Microseconds>(aSample->composition_timestamp) + aSample->duration;
|
||||
|
||||
if (rv != noErr) {
|
||||
LOG("Error %d parsing audio data", rv);
|
||||
mCallback->Error();
|
||||
return;
|
||||
}
|
||||
if (mLastError != noErr) {
|
||||
LOG("Error %d during decoding", mLastError);
|
||||
mCallback->Error();
|
||||
mLastError = noErr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sometimes we need multiple input samples before AudioToolbox
|
||||
// starts decoding. If we haven't seen any output yet, ask for
|
||||
// more data here.
|
||||
if (!mHaveOutput) {
|
||||
if (mTaskQueue->IsEmpty()) {
|
||||
mCallback->InputExhausted();
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +431,9 @@ AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
|
|||
void
|
||||
AppleATDecoder::SignalFlush()
|
||||
{
|
||||
mFlushed = true;
|
||||
mOutputData.Clear();
|
||||
mNextAudioTimestamp = -1;
|
||||
mSizeDecoded = 0;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -49,12 +49,20 @@ private:
|
|||
MediaDataDecoderCallback* mCallback;
|
||||
AudioConverterRef mConverter;
|
||||
AudioFileStreamID mStream;
|
||||
Microseconds mCurrentAudioTimestamp;
|
||||
// Timestamp of the next audio frame going to be output by the decoder.
|
||||
CheckedInt<Microseconds> mCurrentAudioTimestamp;
|
||||
// Estimated timestamp of the next compressed audio packet to be supplied by
|
||||
// the MP4 demuxer.
|
||||
CheckedInt<Microseconds> mNextAudioTimestamp;
|
||||
int64_t mSamplePosition;
|
||||
bool mHaveOutput;
|
||||
bool mFlushed;
|
||||
// Compressed data size that has been processed by the decoder since the last
|
||||
// output.
|
||||
int64_t mSizeDecoded;
|
||||
AudioStreamBasicDescription mOutputFormat;
|
||||
AudioFileTypeID mFileType;
|
||||
// Array containing the queued decoded audio frames, about to be output.
|
||||
nsTArray<AudioDataValue> mOutputData;
|
||||
OSStatus mLastError;
|
||||
|
||||
void SetupDecoder();
|
||||
void SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample);
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace mozilla
|
|||
{
|
||||
|
||||
bool FFmpegDataDecoder<LIBAV_VER>::sFFmpegInitDone = false;
|
||||
StaticMutex FFmpegDataDecoder<LIBAV_VER>::sMonitor;
|
||||
|
||||
FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(MediaTaskQueue* aTaskQueue,
|
||||
AVCodecID aCodecID)
|
||||
|
@ -58,6 +59,8 @@ ChoosePixelFormat(AVCodecContext* aCodecContext, const PixelFormat* aFormats)
|
|||
nsresult
|
||||
FFmpegDataDecoder<LIBAV_VER>::Init()
|
||||
{
|
||||
StaticMutexAutoLock mon(sMonitor);
|
||||
|
||||
FFMPEG_LOG("Initialising FFmpeg decoder.");
|
||||
|
||||
if (!sFFmpegInitDone) {
|
||||
|
@ -130,6 +133,8 @@ FFmpegDataDecoder<LIBAV_VER>::Flush()
|
|||
nsresult
|
||||
FFmpegDataDecoder<LIBAV_VER>::Shutdown()
|
||||
{
|
||||
StaticMutexAutoLock mon(sMonitor);
|
||||
|
||||
if (sFFmpegInitDone) {
|
||||
avcodec_close(mCodecContext);
|
||||
av_freep(&mCodecContext);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "PlatformDecoderModule.h"
|
||||
#include "FFmpegLibs.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
@ -44,6 +45,7 @@ protected:
|
|||
|
||||
private:
|
||||
static bool sFFmpegInitDone;
|
||||
static StaticMutex sMonitor;
|
||||
|
||||
AVCodecID mCodecID;
|
||||
};
|
||||
|
|
|
@ -66,6 +66,15 @@ TEST(Media, OpusEncoder_Init)
|
|||
// Expect false with 0 or negative sampling rate of input signal.
|
||||
EXPECT_FALSE(TestOpusInit(1, 0));
|
||||
EXPECT_FALSE(TestOpusInit(1, -1));
|
||||
|
||||
// Verify sample rate bounds checking.
|
||||
EXPECT_FALSE(TestOpusInit(2, 2000));
|
||||
EXPECT_FALSE(TestOpusInit(2, 4000));
|
||||
EXPECT_FALSE(TestOpusInit(2, 7999));
|
||||
EXPECT_TRUE(TestOpusInit(2, 8000));
|
||||
EXPECT_TRUE(TestOpusInit(2, 192000));
|
||||
EXPECT_FALSE(TestOpusInit(2, 192001));
|
||||
EXPECT_FALSE(TestOpusInit(2, 200000));
|
||||
}
|
||||
|
||||
TEST(Media, OpusEncoder_Resample)
|
||||
|
|
|
@ -130,6 +130,9 @@ TEST(VorbisTrackEncoder, Init)
|
|||
// Sample rate and channel range test.
|
||||
for (int i = 1; i <= 8; i++) {
|
||||
EXPECT_FALSE(TestVorbisInit(i, -1));
|
||||
EXPECT_FALSE(TestVorbisInit(i, 2000));
|
||||
EXPECT_FALSE(TestVorbisInit(i, 4000));
|
||||
EXPECT_FALSE(TestVorbisInit(i, 7999));
|
||||
EXPECT_TRUE(TestVorbisInit(i, 8000));
|
||||
EXPECT_TRUE(TestVorbisInit(i, 11000));
|
||||
EXPECT_TRUE(TestVorbisInit(i, 16000));
|
||||
|
@ -138,6 +141,8 @@ TEST(VorbisTrackEncoder, Init)
|
|||
EXPECT_TRUE(TestVorbisInit(i, 44100));
|
||||
EXPECT_TRUE(TestVorbisInit(i, 48000));
|
||||
EXPECT_TRUE(TestVorbisInit(i, 96000));
|
||||
EXPECT_TRUE(TestVorbisInit(i, 192000));
|
||||
EXPECT_FALSE(TestVorbisInit(i, 192001));
|
||||
EXPECT_FALSE(TestVorbisInit(i, 200000 + 1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ runWithMSE(function (ms, v) {
|
|||
|
||||
v.addEventListener("loadedmetadata", function () {
|
||||
ok(true, "Got loadedmetadata event");
|
||||
is(v.videoWidth, 320, "videoWidth has correct initial value");
|
||||
is(v.videoHeight, 240, "videoHeight has correct initial value");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
|||
skip-if = toolkit == 'gonk' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
|
||||
[test_peerConnection_bug1042791.html]
|
||||
skip-if = buildapp == 'b2g' || os == 'android' # bug 1043403
|
||||
[test_peerConnection_capturedVideo.html]
|
||||
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_close.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_errorCallbacks.html]
|
||||
|
|
|
@ -2354,10 +2354,11 @@ PeerConnectionWrapper.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
verifySdp : function PCW_verifySdp(desc, expectedType, constraints,
|
||||
offerOptions, trickleIceCallback) {
|
||||
verifySdp : function PCW_verifySdp(desc, expectedType, offerConstraintsList,
|
||||
answerConstraintsList, offerOptions, trickleIceCallback) {
|
||||
info("Examining this SessionDescription: " + JSON.stringify(desc));
|
||||
info("constraints: " + JSON.stringify(constraints));
|
||||
info("offerConstraintsList: " + JSON.stringify(offerConstraintsList));
|
||||
info("answerConstraintsList: " + JSON.stringify(answerConstraintsList));
|
||||
info("offerOptions: " + JSON.stringify(offerOptions));
|
||||
ok(desc, "SessionDescription is not null");
|
||||
is(desc.type, expectedType, "SessionDescription type is " + expectedType);
|
||||
|
@ -2376,11 +2377,11 @@ PeerConnectionWrapper.prototype = {
|
|||
}
|
||||
//TODO: how can we check for absence/presence of m=application?
|
||||
|
||||
//TODO: how to handle media contraints + offer options
|
||||
var audioTracks = this.countAudioTracksInMediaConstraint(constraints);
|
||||
if (constraints.length === 0) {
|
||||
audioTracks = this.audioInOfferOptions(offerOptions);
|
||||
}
|
||||
var audioTracks =
|
||||
Math.max(this.countAudioTracksInMediaConstraint(offerConstraintsList),
|
||||
this.countAudioTracksInMediaConstraint(answerConstraintsList)) ||
|
||||
this.audioInOfferOptions(offerOptions);
|
||||
|
||||
info("expected audio tracks: " + audioTracks);
|
||||
if (audioTracks == 0) {
|
||||
ok(!desc.sdp.contains("m=audio"), "audio m-line is absent from SDP");
|
||||
|
@ -2393,11 +2394,11 @@ PeerConnectionWrapper.prototype = {
|
|||
|
||||
}
|
||||
|
||||
//TODO: how to handle media contraints + offer options
|
||||
var videoTracks = this.countVideoTracksInMediaConstraint(constraints);
|
||||
if (constraints.length === 0) {
|
||||
videoTracks = this.videoInOfferOptions(offerOptions);
|
||||
}
|
||||
var videoTracks =
|
||||
Math.max(this.countVideoTracksInMediaConstraint(offerConstraintsList),
|
||||
this.countVideoTracksInMediaConstraint(answerConstraintsList)) ||
|
||||
this.videoInOfferOptions(offerOptions);
|
||||
|
||||
info("expected video tracks: " + videoTracks);
|
||||
if (videoTracks == 0) {
|
||||
ok(!desc.sdp.contains("m=video"), "video m-line is absent from SDP");
|
||||
|
|
|
@ -220,7 +220,7 @@ var commandsPeerConnection = [
|
|||
'PC_LOCAL_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function(trickle) {
|
||||
test.pcLocal.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -231,7 +231,7 @@ var commandsPeerConnection = [
|
|||
'PC_REMOTE_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -344,7 +344,7 @@ var commandsPeerConnection = [
|
|||
'PC_REMOTE_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._remote_answer, "answer",
|
||||
test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -355,7 +355,7 @@ var commandsPeerConnection = [
|
|||
'PC_LOCAL_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._remote_answer, "answer",
|
||||
test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcLocal.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -837,7 +837,7 @@ var commandsDataChannel = [
|
|||
'PC_LOCAL_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function(trickle) {
|
||||
test.pcLocal.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -848,7 +848,7 @@ var commandsDataChannel = [
|
|||
'PC_REMOTE_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -941,7 +941,7 @@ var commandsDataChannel = [
|
|||
'PC_REMOTE_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._remote_answer, "answer",
|
||||
test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
@ -952,7 +952,7 @@ var commandsDataChannel = [
|
|||
'PC_LOCAL_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._remote_answer, "answer",
|
||||
test._answer_constraints, test._offer_options,
|
||||
test._offer_constraints, test._answer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcLocal.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<video id="v1" src="../../test/vp9cake.webm" height="120" width="160" autoplay muted></video>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
createHTML({
|
||||
bug: "1081409",
|
||||
title: "Captured video-only over peer connection",
|
||||
visible: true
|
||||
});
|
||||
|
||||
var domLoaded = new Promise(r => addEventListener("DOMContentLoaded", e => r()));
|
||||
var test;
|
||||
var stream;
|
||||
var waitUntil = func => new Promise(resolve => {
|
||||
var ival = setInterval(() => func() && resolve(clearInterval(ival)), 200);
|
||||
});
|
||||
|
||||
runNetworkTest(function() {
|
||||
test = new PeerConnectionTest();
|
||||
test.setOfferOptions({ offerToReceiveVideo: false,
|
||||
offerToReceiveAudio: false });
|
||||
test.chain.insertAfter("PC_LOCAL_GUM", [["PC_LOCAL_CAPTUREVIDEO", function (test) {
|
||||
domLoaded
|
||||
.then(() => waitUntil(() => v1.videoWidth > 0)) // TODO: Bug 1096723
|
||||
.then(function() {
|
||||
stream = v1.mozCaptureStreamUntilEnded();
|
||||
is(stream.getTracks().length, 2, "Captured stream has 2 tracks");
|
||||
stream.getTracks().forEach(tr => test.pcLocal._pc.addTrack(tr, stream));
|
||||
test.pcLocal.constraints = [{ video: true, audio:true }]; // fool tests
|
||||
test.next();
|
||||
})
|
||||
.catch(function(reason) {
|
||||
ok(false, "unexpected failure: " + reason);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
]]);
|
||||
test.chain.removeAfter("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -227,8 +227,14 @@ InternalSetAudioRoutesICS(SwitchState aState)
|
|||
AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "");
|
||||
sHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
|
||||
} else if (aState == SWITCH_STATE_OFF) {
|
||||
AudioSystem::setDeviceConnectionState(static_cast<audio_devices_t>(sHeadsetState),
|
||||
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "");
|
||||
if (sHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
|
||||
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADSET,
|
||||
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "");
|
||||
}
|
||||
if (sHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
|
||||
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
|
||||
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "");
|
||||
}
|
||||
sHeadsetState = 0;
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -89,8 +89,6 @@ startTest(function() {
|
|||
.then(() => check(PHONE_STATE_NORMAL))
|
||||
|
||||
// End
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -64,8 +64,6 @@ function testConferenceAddError() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceAddError()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -41,8 +41,6 @@ function testConferenceTwoCallsTwice() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceTwoCallsTwice()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -61,8 +61,6 @@ function testConferenceRemoveError() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceRemoveError()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -30,8 +30,6 @@ function testConferenceThreeAndHangupOne() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceThreeAndHangupOne()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -34,8 +34,6 @@ function testConferenceThreeAndRemoveOne() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceThreeAndRemoveOne()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -23,8 +23,6 @@ function testConferenceTwoCalls() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceTwoCalls()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -49,8 +49,6 @@ function testConferenceHangUpBackground() {
|
|||
startTest(function() {
|
||||
testConferenceHangUpForeground()
|
||||
.then(() => testConferenceHangUpBackground())
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -28,8 +28,6 @@ function testConferenceTwoAndHangupOne() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceTwoAndHangupOne()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -35,8 +35,6 @@ function testConferenceHoldAndResume() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceHoldAndResume()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -30,8 +30,6 @@ function testConferenceTwoAndRemoveOne() {
|
|||
// Start the test
|
||||
startTest(function() {
|
||||
testConferenceTwoAndRemoveOne()
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -46,8 +46,6 @@ startDSDSTest(function() {
|
|||
testNewCallWhenOtherConnectionInUse(0, 1)
|
||||
.then(() => testNewCallWhenOtherConnectionInUse(1, 0))
|
||||
.then(() => muxModem(0))
|
||||
.then(null, () => {
|
||||
ok(false, "promise rejects during test.");
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -73,8 +73,6 @@ function testIncomingCall() {
|
|||
startDSDSTest(function() {
|
||||
testOutgoingCall()
|
||||
.then(testIncomingCall)
|
||||
.then(null, () => {
|
||||
ok(false, "promise rejects during test.");
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -78,8 +78,6 @@ startTest(function() {
|
|||
.then(() => testEmergencyLabel("119", eccList))
|
||||
.then(() => testEmergencyLabel("112", eccList))
|
||||
.then(() => setEccListProperty(origEccList))
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test: ' + error);
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -21,8 +21,6 @@ function testGettingIMEI() {
|
|||
// Start test
|
||||
startTest(function() {
|
||||
testGettingIMEI()
|
||||
.then(null, cause => {
|
||||
ok(false, 'promise rejects during test: ' + cause);
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -185,8 +185,6 @@ startTestWithPermissions(['mobileconnection'], function() {
|
|||
|
||||
// reset call forwarding settings.
|
||||
return promise.then(() => clearAllCallForwardingSettings())
|
||||
.then(null, cause => {
|
||||
ok(false, 'promise rejects during test: ' + cause);
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -108,8 +108,6 @@ startTest(function() {
|
|||
}
|
||||
|
||||
return promise
|
||||
.then(null, cause => {
|
||||
ok(false, 'promise rejects during test: ' + cause);
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -98,8 +98,6 @@ function testOutgoingCallRadioOff() {
|
|||
// Start test
|
||||
startTestWithPermissions(['mobileconnection'], function() {
|
||||
testOutgoingCallRadioOff()
|
||||
.then(null, () => {
|
||||
ok(false, "promise rejects during test.");
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -45,8 +45,6 @@ function testAutoHoldConferenceCall() {
|
|||
startTest(function() {
|
||||
testAutoHoldCall()
|
||||
.then(() => testAutoHoldConferenceCall())
|
||||
.then(null, () => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -36,8 +36,6 @@ startTestWithPermissions(['mobileconnection'], function() {
|
|||
.then(() => gRemoteAnswer(outCall))
|
||||
.then(() => gDelay(1000)) // See Bug 1018051 for the purpose of the delay.
|
||||
.then(() => gRemoteHangUp(outCall))
|
||||
.then(null, () => {
|
||||
ok(false, "promise rejects during test.");
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -6,57 +6,22 @@ MARIONETTE_HEAD_JS = 'head.js';
|
|||
|
||||
let connection;
|
||||
|
||||
function setRadioEnabled(enabled, callback) {
|
||||
let request = connection.setRadioEnabled(enabled);
|
||||
function setRadioEnabled(enabled) {
|
||||
let desiredRadioState = enabled ? 'enabled' : 'disabled';
|
||||
log("Set radio: " + desiredRadioState);
|
||||
|
||||
let pending = ['onradiostatechange', 'onsuccess'];
|
||||
let done = callback;
|
||||
let promises = [];
|
||||
|
||||
connection.onradiostatechange = function() {
|
||||
let promise = gWaitForEvent(connection, "radiostatechange", event => {
|
||||
let state = connection.radioState;
|
||||
log("Received 'radiostatechange' event, radioState: " + state);
|
||||
|
||||
if (state == desiredRadioState) {
|
||||
gReceivedPending('onradiostatechange', pending, done);
|
||||
}
|
||||
};
|
||||
|
||||
request.onsuccess = function onsuccess() {
|
||||
gReceivedPending('onsuccess', pending, done);
|
||||
};
|
||||
|
||||
request.onerror = function onerror() {
|
||||
ok(false, "setRadioEnabled should be ok");
|
||||
};
|
||||
}
|
||||
|
||||
function dial(number) {
|
||||
// Verify initial state before dial.
|
||||
ok(telephony);
|
||||
is(telephony.active, null);
|
||||
ok(telephony.calls);
|
||||
is(telephony.calls.length, 0);
|
||||
|
||||
log("Make an outgoing call.");
|
||||
|
||||
telephony.dial(number).then(null, cause => {
|
||||
log("Received promise 'reject'");
|
||||
|
||||
is(telephony.active, null);
|
||||
is(telephony.calls.length, 0);
|
||||
is(cause, "RadioNotAvailable");
|
||||
|
||||
emulator.runCmdWithCallback("gsm list", function(result) {
|
||||
log("Initial call list: " + result);
|
||||
|
||||
setRadioEnabled(true, cleanUp);
|
||||
});
|
||||
log("current radioState: " + state);
|
||||
return state == desiredRadioState;
|
||||
});
|
||||
}
|
||||
promises.push(promise);
|
||||
|
||||
function cleanUp() {
|
||||
finish();
|
||||
promises.push(connection.setRadioEnabled(enabled));
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
startTestWithPermissions(['mobileconnection'], function() {
|
||||
|
@ -64,7 +29,14 @@ startTestWithPermissions(['mobileconnection'], function() {
|
|||
ok(connection instanceof MozMobileConnection,
|
||||
"connection is instanceof " + connection.constructor);
|
||||
|
||||
setRadioEnabled(false, function() {
|
||||
dial("0912345678");
|
||||
});
|
||||
setRadioEnabled(false)
|
||||
.then(() => gDial("0912345678"))
|
||||
.catch(cause => {
|
||||
is(telephony.active, null);
|
||||
is(telephony.calls.length, 0);
|
||||
is(cause, "RadioNotAvailable");
|
||||
})
|
||||
.then(() => setRadioEnabled(true))
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -27,8 +27,6 @@ function testReject3rdCall() {
|
|||
|
||||
startTest(function() {
|
||||
testReject3rdCall()
|
||||
.then(null, () => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -29,9 +29,6 @@ startTest(function() {
|
|||
return deferred.promise;
|
||||
})
|
||||
.then(() => gRemoteHangUp(outCall))
|
||||
// End
|
||||
.then(null, error => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
|
|
@ -1902,22 +1902,28 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
|||
gfxPoint p(aPt->x * aRunParams.devPerApp,
|
||||
aPt->y * aRunParams.devPerApp);
|
||||
const Metrics& metrics = GetMetrics(eHorizontal);
|
||||
// Adjust the matrix to draw the (horizontally-shaped) textrun with
|
||||
// 90-degree CW rotation, and adjust position so that the rotated
|
||||
// horizontal text (which uses a standard alphabetic baseline) will
|
||||
// Get a matrix we can use to draw the (horizontally-shaped) textrun
|
||||
// with 90-degree CW rotation.
|
||||
gfxMatrix mat = aRunParams.context->CurrentMatrix().
|
||||
Translate(p). // translate origin for rotation
|
||||
Rotate(M_PI / 2.0). // turn 90deg clockwise
|
||||
Translate(-p); // undo the translation
|
||||
|
||||
// If we're drawing rotated horizontal text for an element styled
|
||||
// text-orientation:mixed, the dominant baseline will be vertical-
|
||||
// centered. So in this case, we need to adjust the position so that
|
||||
// the rotated horizontal text (which uses an alphabetic baseline) will
|
||||
// look OK when juxtaposed with upright glyphs (rendered on a centered
|
||||
// vertical baseline). The adjustment here is somewhat ad hoc; we
|
||||
// should eventually look for baseline tables[1] in the fonts and use
|
||||
// those if available.
|
||||
// [1] http://www.microsoft.com/typography/otspec/base.htm
|
||||
aRunParams.context->SetMatrix(aRunParams.context->CurrentMatrix().
|
||||
Translate(p). // translate origin for rotation
|
||||
Rotate(M_PI / 2.0). // turn 90deg clockwise
|
||||
Translate(-p). // undo the translation
|
||||
Translate(gfxPoint(0, (metrics.emAscent - metrics.emDescent) / 2)));
|
||||
// and offset the (alphabetic) baseline of the
|
||||
// horizontally-shaped text from the (centered)
|
||||
// default baseline used for vertical
|
||||
// [1] See http://www.microsoft.com/typography/otspec/base.htm
|
||||
if (aTextRun->UseCenterBaseline()) {
|
||||
gfxPoint baseAdj(0, (metrics.emAscent - metrics.emDescent) / 2);
|
||||
mat.Translate(baseAdj);
|
||||
}
|
||||
|
||||
aRunParams.context->SetMatrix(mat);
|
||||
}
|
||||
|
||||
nsAutoPtr<gfxTextContextPaint> contextPaint;
|
||||
|
@ -2138,15 +2144,33 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
|||
// Current position in appunits
|
||||
gfxFont::Orientation orientation =
|
||||
aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT
|
||||
? gfxFont::eVertical : gfxFont::eHorizontal;
|
||||
? eVertical : eHorizontal;
|
||||
const gfxFont::Metrics& fontMetrics = GetMetrics(orientation);
|
||||
|
||||
gfxFloat baselineOffset = 0;
|
||||
if (aTextRun->UseCenterBaseline() && orientation == eHorizontal) {
|
||||
// For a horizontal font being used in vertical writing mode with
|
||||
// text-orientation:mixed, the overall metrics we're accumulating
|
||||
// will be aimed at a center baseline. But this font's metrics were
|
||||
// based on the alphabetic baseline. So we compute a baseline offset
|
||||
// that will be applied to ascent/descent values and glyph rects
|
||||
// to effectively shift them relative to the baseline.
|
||||
// XXX Eventually we should probably use the BASE table, if present.
|
||||
// But it usually isn't, so we need an ad hoc adjustment for now.
|
||||
baselineOffset = appUnitsPerDevUnit *
|
||||
(fontMetrics.emAscent - fontMetrics.emDescent) / 2;
|
||||
}
|
||||
|
||||
RunMetrics metrics;
|
||||
metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
|
||||
metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
|
||||
metrics.mAscent = fontMetrics.maxAscent * appUnitsPerDevUnit;
|
||||
metrics.mDescent = fontMetrics.maxDescent * appUnitsPerDevUnit;
|
||||
|
||||
if (aStart == aEnd) {
|
||||
// exit now before we look at aSpacing[0], which is undefined
|
||||
metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent);
|
||||
metrics.mAscent -= baselineOffset;
|
||||
metrics.mDescent += baselineOffset;
|
||||
metrics.mBoundingBox = gfxRect(0, -metrics.mAscent,
|
||||
0, metrics.mAscent + metrics.mDescent);
|
||||
return metrics;
|
||||
}
|
||||
|
||||
|
@ -2247,6 +2271,12 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
|||
metrics.mBoundingBox -= gfxPoint(x, 0);
|
||||
}
|
||||
|
||||
if (baselineOffset != 0) {
|
||||
metrics.mAscent -= baselineOffset;
|
||||
metrics.mDescent += baselineOffset;
|
||||
metrics.mBoundingBox.y += baselineOffset;
|
||||
}
|
||||
|
||||
metrics.mAdvanceWidth = x*direction;
|
||||
return metrics;
|
||||
}
|
||||
|
|
|
@ -945,6 +945,12 @@ public:
|
|||
gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL;
|
||||
}
|
||||
|
||||
bool UseCenterBaseline() const {
|
||||
uint32_t orient = GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK;
|
||||
return orient == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED ||
|
||||
orient == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
|
||||
}
|
||||
|
||||
bool IsRightToLeft() const {
|
||||
return (GetFlags() & gfxTextRunFactory::TEXT_IS_RTL) != 0;
|
||||
}
|
||||
|
|
|
@ -1072,7 +1072,6 @@ DisableFMRadio() {
|
|||
|
||||
void
|
||||
FMRadioSeek(const FMRadioSeekDirection& aDirection) {
|
||||
AssertMainThread();
|
||||
PROXY_IF_SANDBOXED(FMRadioSeek(aDirection));
|
||||
}
|
||||
|
||||
|
@ -1084,7 +1083,6 @@ GetFMRadioSettings(FMRadioSettings* aInfo) {
|
|||
|
||||
void
|
||||
SetFMRadioFrequency(const uint32_t aFrequency) {
|
||||
AssertMainThread();
|
||||
PROXY_IF_SANDBOXED(SetFMRadioFrequency(aFrequency));
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,11 @@ CPUInfo::SetSSEVersion()
|
|||
);
|
||||
# else
|
||||
// On x86, preserve ebx. The compiler needs it for PIC mode.
|
||||
// Some older processors don't fill the ecx register with cpuid, so clobber
|
||||
// it before calling cpuid, so that there's no risk of picking random bits
|
||||
// indicating SSE3/SSE4 are present.
|
||||
asm (
|
||||
"xor %%ecx, %%ecx;"
|
||||
"movl $0x1, %%eax;"
|
||||
"pushl %%ebx;"
|
||||
"cpuid;"
|
||||
|
|
|
@ -1453,9 +1453,12 @@ RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
|
|||
// Until we get rid of these phases in bug 960465, we need to skip
|
||||
// animation restyles during the non-animation phase, and post
|
||||
// animation restyles so that we restyle those elements again in the
|
||||
// animation phase.
|
||||
// animation phase. Furthermore, we need to add
|
||||
// eRestyle_ChangeAnimationPhaseDescendants so that we actually honor
|
||||
// these booleans in all cases.
|
||||
mSkipAnimationRules = true;
|
||||
mPostAnimationRestyles = true;
|
||||
aRestyleHint |= eRestyle_ChangeAnimationPhaseDescendants;
|
||||
|
||||
DoRebuildAllStyleData(mPendingRestyles, aExtraHint, aRestyleHint);
|
||||
|
||||
|
@ -1495,8 +1498,12 @@ RestyleManager::DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
|
|||
// different styles). If we use up the hint for one of the
|
||||
// ancestors that we hit first, then we'll fail to do the restyling
|
||||
// we need to do.
|
||||
aRestyleTracker.AddPendingRestyle(mPresContext->Document()->GetRootElement(),
|
||||
aRestyleHint, nsChangeHint(0));
|
||||
Element* root = mPresContext->Document()->GetRootElement();
|
||||
if (root) {
|
||||
// If the root element is gone, dropping the hint on the floor
|
||||
// should be fine.
|
||||
aRestyleTracker.AddPendingRestyle(root, aRestyleHint, nsChangeHint(0));
|
||||
}
|
||||
aRestyleHint = nsRestyleHint(0);
|
||||
}
|
||||
|
||||
|
@ -2515,11 +2522,13 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
|||
}
|
||||
}
|
||||
|
||||
// If we are restyling this frame with eRestyle_Self, we restyle
|
||||
// children with nsRestyleHint(0). But we pass the eRestyle_ForceDescendants
|
||||
// flag down too.
|
||||
// If we are restyling this frame with eRestyle_Self or weaker hints,
|
||||
// we restyle children with nsRestyleHint(0). But we pass the
|
||||
// eRestyle_ChangeAnimationPhaseDescendants and eRestyle_ForceDescendants
|
||||
// flags down too.
|
||||
nsRestyleHint childRestyleHint =
|
||||
nsRestyleHint(aRestyleHint & (eRestyle_Subtree |
|
||||
eRestyle_ChangeAnimationPhaseDescendants |
|
||||
eRestyle_ForceDescendants));
|
||||
|
||||
nsRefPtr<nsStyleContext> oldContext = mFrame->StyleContext();
|
||||
|
@ -3736,7 +3745,9 @@ RestyleManager::RestyleHintToString(nsRestyleHint aHint)
|
|||
bool any = false;
|
||||
const char* names[] = { "Self", "Subtree", "LaterSiblings", "CSSTransitions",
|
||||
"CSSAnimations", "SVGAttrAnimations", "StyleAttribute",
|
||||
"ChangeAnimationPhase", "Force", "ForceDescendants" };
|
||||
"ChangeAnimationPhase",
|
||||
"ChangeAnimationPhaseDescendants",
|
||||
"Force", "ForceDescendants" };
|
||||
uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
|
||||
uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
|
||||
for (uint32_t i = 0; i < ArrayLength(names); i++) {
|
||||
|
|
|
@ -4162,8 +4162,12 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
|||
return;
|
||||
}
|
||||
|
||||
// The y position should be set to the middle of the line.
|
||||
rect.y += lineThickness / 2;
|
||||
// The block-direction position should be set to the middle of the line.
|
||||
if (aVertical) {
|
||||
rect.x -= lineThickness / 2;
|
||||
} else {
|
||||
rect.y += lineThickness / 2;
|
||||
}
|
||||
|
||||
switch (aStyle) {
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
|
||||
|
@ -4360,12 +4364,18 @@ nsCSSRendering::DecorationLineToPath(nsIFrame* aFrame,
|
|||
|
||||
gfxFloat lineThickness = std::max(NS_round(aLineSize.height), 1.0);
|
||||
|
||||
// The y position should be set to the middle of the line.
|
||||
rect.y += lineThickness / 2;
|
||||
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)),
|
||||
gfxSize(rect.Width(), lineThickness)));
|
||||
// The block-direction position should be set to the middle of the line.
|
||||
if (aVertical) {
|
||||
rect.x -= lineThickness / 2;
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(lineThickness / 2, 0.0)),
|
||||
gfxSize(lineThickness, rect.Height())));
|
||||
} else {
|
||||
rect.y += lineThickness / 2;
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)),
|
||||
gfxSize(rect.Width(), lineThickness)));
|
||||
}
|
||||
}
|
||||
|
||||
nsRect
|
||||
|
|
|
@ -309,9 +309,14 @@ nsCaret::GetGeometryForFrame(nsIFrame* aFrame,
|
|||
descent = fm->MaxDescent();
|
||||
}
|
||||
nscoord height = ascent + descent;
|
||||
bool vertical = aFrame->GetWritingMode().IsVertical();
|
||||
WritingMode wm = aFrame->GetWritingMode();
|
||||
bool vertical = wm.IsVertical();
|
||||
if (vertical) {
|
||||
framePos.x = baseline - ascent;
|
||||
if (wm.IsLineInverted()) {
|
||||
framePos.x = baseline - descent;
|
||||
} else {
|
||||
framePos.x = baseline - ascent;
|
||||
}
|
||||
} else {
|
||||
framePos.y = baseline - ascent;
|
||||
}
|
||||
|
|
|
@ -346,16 +346,20 @@ enum nsRestyleHint {
|
|||
// FIXME: Remove this as part of bug 960465.
|
||||
eRestyle_ChangeAnimationPhase = (1 << 7),
|
||||
|
||||
// Same as the previous, except this applies to the entire subtree.
|
||||
// FIXME: Remove this as part of bug 960465.
|
||||
eRestyle_ChangeAnimationPhaseDescendants = (1 << 8),
|
||||
|
||||
// Continue the restyling process to the current frame's children even
|
||||
// if this frame's restyling resulted in no style changes.
|
||||
eRestyle_Force = (1<<8),
|
||||
eRestyle_Force = (1<<9),
|
||||
|
||||
// Continue the restyling process to all of the current frame's
|
||||
// descendants, even if any frame's restyling resulted in no style
|
||||
// changes. (Implies eRestyle_Force.) Note that this is weaker than
|
||||
// eRestyle_Subtree, which makes us rerun selector matching on all
|
||||
// descendants rather than just continuing the restyling process.
|
||||
eRestyle_ForceDescendants = (1<<9),
|
||||
eRestyle_ForceDescendants = (1<<10),
|
||||
};
|
||||
|
||||
// The functions below need an integral type to cast to to avoid
|
||||
|
|
|
@ -3468,10 +3468,11 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
|
|||
if (aInflation != 1.0f) {
|
||||
font.size = NSToCoordRound(font.size * aInflation);
|
||||
}
|
||||
WritingMode wm(aStyleContext->StyleVisibility());
|
||||
WritingMode wm(aStyleContext);
|
||||
return pc->DeviceContext()->GetMetricsFor(
|
||||
font, aStyleContext->StyleFont()->mLanguage,
|
||||
wm.IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal,
|
||||
wm.IsVertical() && !wm.IsSideways()
|
||||
? gfxFont::eVertical : gfxFont::eHorizontal,
|
||||
fs, tp, *aFontMetrics);
|
||||
}
|
||||
|
||||
|
@ -4868,9 +4869,11 @@ nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
|
|||
|
||||
/* static */ nscoord
|
||||
nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
|
||||
nscoord aLineHeight)
|
||||
nscoord aLineHeight,
|
||||
bool aIsInverted)
|
||||
{
|
||||
nscoord fontAscent = aFontMetrics->MaxAscent();
|
||||
nscoord fontAscent = aIsInverted ? aFontMetrics->MaxDescent()
|
||||
: aFontMetrics->MaxAscent();
|
||||
nscoord fontHeight = aFontMetrics->MaxHeight();
|
||||
|
||||
nscoord leading = aLineHeight - fontHeight;
|
||||
|
@ -5846,7 +5849,7 @@ nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
WritingMode wm(aStyleContext->StyleVisibility());
|
||||
WritingMode wm(aStyleContext);
|
||||
if (wm.IsVertical()) {
|
||||
switch (aStyleText->mTextOrientation) {
|
||||
case NS_STYLE_TEXT_ORIENTATION_MIXED:
|
||||
|
@ -7323,7 +7326,8 @@ nsLayoutUtils::SetBSizeFromFontMetrics(const nsIFrame* aFrame,
|
|||
// The height of our box is the sum of our font size plus the top
|
||||
// and bottom border and padding. The height of children do not
|
||||
// affect our height.
|
||||
aMetrics.SetBlockStartAscent(fm->MaxAscent());
|
||||
aMetrics.SetBlockStartAscent(aLineWM.IsLineInverted() ? fm->MaxDescent()
|
||||
: fm->MaxAscent());
|
||||
aMetrics.BSize(aLineWM) = fm->MaxHeight();
|
||||
} else {
|
||||
NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
|
||||
|
|
|
@ -1391,11 +1391,15 @@ public:
|
|||
/**
|
||||
* Gets the baseline to vertically center text from a font within a
|
||||
* line of specified height.
|
||||
* aIsInverted: true if the text is inverted relative to the block
|
||||
* direction, so that the block-dir "ascent" corresponds to font
|
||||
* descent. (Applies to sideways text in vertical-lr mode.)
|
||||
*
|
||||
* Returns the baseline position relative to the top of the line.
|
||||
*/
|
||||
static nscoord GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
|
||||
nscoord aLineHeight);
|
||||
nscoord aLineHeight,
|
||||
bool aIsInverted);
|
||||
|
||||
/**
|
||||
* Derive a baseline of |aFrame| (measured from its top border edge)
|
||||
|
|
|
@ -519,7 +519,8 @@ nsTextControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
inflation);
|
||||
// now adjust for our borders and padding
|
||||
aDesiredSize.SetBlockStartAscent(
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight) +
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight,
|
||||
wm.IsLineInverted()) +
|
||||
aReflowState.ComputedLogicalBorderPadding().BStart(wm));
|
||||
|
||||
// overflow handling
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#define WritingModes_h_
|
||||
|
||||
#include "nsRect.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsStyleContext.h"
|
||||
|
||||
// If WRITING_MODE_VERTICAL_ENABLED is defined, we will attempt to support
|
||||
// the vertical writing-mode values; if it is not defined, then
|
||||
|
@ -168,12 +168,17 @@ public:
|
|||
/**
|
||||
* Return true if LTR. (Convenience method)
|
||||
*/
|
||||
bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); }
|
||||
bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); }
|
||||
|
||||
/**
|
||||
* True if vertical-mode block direction is LR (convenience method).
|
||||
*/
|
||||
bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); }
|
||||
bool IsVerticalLR() const { return eBlockLR == GetBlockDir(); }
|
||||
|
||||
/**
|
||||
* True if vertical-mode block direction is RL (convenience method).
|
||||
*/
|
||||
bool IsVerticalRL() const { return eBlockRL == GetBlockDir(); }
|
||||
|
||||
/**
|
||||
* True if vertical writing mode, i.e. when
|
||||
|
@ -208,6 +213,20 @@ public:
|
|||
return IsLineInverted() ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the text-orientation will force all text to be rendered sideways
|
||||
* in vertical lines, in which case we should prefer an alphabetic baseline;
|
||||
* otherwise, the default is centered.
|
||||
* Note that some glyph runs may be rendered sideways even if this is false,
|
||||
* due to text-orientation:mixed resolution, but in that case the dominant
|
||||
* baseline remains centered.
|
||||
*/
|
||||
#ifdef WRITING_MODE_VERTICAL_ENABLED
|
||||
bool IsSideways() const { return !!(mWritingMode & eSidewaysMask); }
|
||||
#else
|
||||
bool IsSideways() const { return false; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Default constructor gives us a horizontal, LTR writing mode.
|
||||
* XXX We will probably eliminate this and require explicit initialization
|
||||
|
@ -220,25 +239,49 @@ public:
|
|||
/**
|
||||
* Construct writing mode based on a style context
|
||||
*/
|
||||
explicit WritingMode(const nsStyleVisibility* aStyleVisibility)
|
||||
explicit WritingMode(nsStyleContext* aStyleContext)
|
||||
{
|
||||
NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here");
|
||||
NS_ASSERTION(aStyleContext, "we need an nsStyleContext here");
|
||||
|
||||
const nsStyleVisibility* styleVisibility = aStyleContext->StyleVisibility();
|
||||
|
||||
#ifdef WRITING_MODE_VERTICAL_ENABLED
|
||||
switch (aStyleVisibility->mWritingMode) {
|
||||
switch (styleVisibility->mWritingMode) {
|
||||
case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
|
||||
mWritingMode = 0;
|
||||
break;
|
||||
|
||||
case NS_STYLE_WRITING_MODE_VERTICAL_LR:
|
||||
{
|
||||
mWritingMode = eBlockFlowMask |
|
||||
eLineOrientMask | //XXX needs update when text-orientation added
|
||||
eLineOrientMask |
|
||||
eOrientationMask;
|
||||
uint8_t textOrientation = aStyleContext->StyleText()->mTextOrientation;
|
||||
#if 0 // not yet implemented
|
||||
if (textOrientation == NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_LEFT) {
|
||||
mWritingMode &= ~eLineOrientMask;
|
||||
}
|
||||
#endif
|
||||
if (textOrientation >= NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_RIGHT) {
|
||||
mWritingMode |= eSidewaysMask;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NS_STYLE_WRITING_MODE_VERTICAL_RL:
|
||||
{
|
||||
mWritingMode = eOrientationMask;
|
||||
uint8_t textOrientation = aStyleContext->StyleText()->mTextOrientation;
|
||||
#if 0 // not yet implemented
|
||||
if (textOrientation == NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_LEFT) {
|
||||
mWritingMode |= eLineOrientMask;
|
||||
}
|
||||
#endif
|
||||
if (textOrientation >= NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_RIGHT) {
|
||||
mWritingMode |= eSidewaysMask;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("unknown writing mode!");
|
||||
|
@ -249,7 +292,7 @@ public:
|
|||
mWritingMode = 0;
|
||||
#endif
|
||||
|
||||
if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) {
|
||||
if (NS_STYLE_DIRECTION_RTL == styleVisibility->mDirection) {
|
||||
mWritingMode |= eInlineFlowMask | //XXX needs update when text-orientation added
|
||||
eBidiMask;
|
||||
}
|
||||
|
@ -325,6 +368,10 @@ private:
|
|||
// Note: We have one excess bit of info; WritingMode can pack into 4 bits.
|
||||
// But since we have space, we're caching interesting things for fast access.
|
||||
|
||||
eSidewaysMask = 0x20, // true means text-orientation is sideways-*,
|
||||
// which means we'll use alphabetic instead of
|
||||
// centered default baseline for vertical text
|
||||
|
||||
// Masks for output enums
|
||||
eInlineMask = 0x03,
|
||||
eBlockMask = 0x05
|
||||
|
|
|
@ -122,7 +122,8 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
|||
if (fm) {
|
||||
nscoord logicalHeight = aReflowState.CalcLineHeight();
|
||||
finalSize.BSize(wm) = logicalHeight;
|
||||
aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(fm, logicalHeight));
|
||||
aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(
|
||||
fm, logicalHeight, wm.IsLineInverted()));
|
||||
}
|
||||
else {
|
||||
aMetrics.SetBlockStartAscent(aMetrics.BSize(wm) = 0);
|
||||
|
|
|
@ -515,7 +515,9 @@ nsBlockFrame::GetCaretBaseline() const
|
|||
nscoord lineHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
|
||||
contentRect.height, inflation);
|
||||
return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight) + bp.top;
|
||||
const WritingMode wm = GetWritingMode();
|
||||
return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight,
|
||||
wm.IsLineInverted()) + bp.top;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1231,6 +1233,42 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
// Compute our final size
|
||||
nscoord blockEndEdgeOfChildren;
|
||||
ComputeFinalSize(*reflowState, state, aMetrics, &blockEndEdgeOfChildren);
|
||||
|
||||
// If the block direction is right-to-left, we need to update the bounds of
|
||||
// lines that were placed relative to mContainerWidth during reflow, as
|
||||
// we typically do not know the true container width (block-dir size of the
|
||||
// finished paragraph/block) until we've reflowed all its children. So we
|
||||
// use a "fake" mContainerWidth during reflow (see nsBlockReflowState's
|
||||
// constructor) and then fix up the positions of the lines here, once the
|
||||
// final block size is known.
|
||||
//
|
||||
// Note that writing-mode:vertical-rl is the only case where the block
|
||||
// logical direction progresses in a negative physical direction, and
|
||||
// therefore block-dir coordinate conversion depends on knowing the width
|
||||
// of the coordinate space in order to translate between the logical and
|
||||
// physical origins.
|
||||
if (wm.GetBlockDir() == WritingMode::BlockDir::eBlockRL) {
|
||||
nscoord deltaX = aMetrics.Width() - state.mContainerWidth;
|
||||
if (deltaX) {
|
||||
for (line_iterator line = begin_lines(), end = end_lines();
|
||||
line != end; line++) {
|
||||
SlideLine(state, line, -deltaX);
|
||||
}
|
||||
for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
|
||||
nsPoint physicalDelta(deltaX, 0);
|
||||
f->MovePositionBy(physicalDelta);
|
||||
}
|
||||
nsFrameList* bulletList = GetOutsideBulletList();
|
||||
if (bulletList) {
|
||||
nsPoint physicalDelta(deltaX, 0);
|
||||
for (nsIFrame* f = bulletList->FirstChild(); f;
|
||||
f = f->GetNextSibling()) {
|
||||
f->MovePositionBy(physicalDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsRect areaBounds = nsRect(0, 0, aMetrics.Width(), aMetrics.Height());
|
||||
ComputeOverflowAreas(areaBounds, reflowState->mStyleDisplay,
|
||||
blockEndEdgeOfChildren, aMetrics.mOverflowAreas);
|
||||
|
@ -2516,7 +2554,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsLayoutUtils::FontSizeInflationFor(this));
|
||||
|
||||
nscoord minAscent =
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight);
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight,
|
||||
wm.IsLineInverted());
|
||||
nscoord minDescent = aState.mMinLineHeight - minAscent;
|
||||
|
||||
aState.mBCoord += std::max(minAscent, metrics.BlockStartAscent()) +
|
||||
|
@ -2731,12 +2770,12 @@ nsBlockFrame::PullFrameFrom(nsLineBox* aLine,
|
|||
|
||||
void
|
||||
nsBlockFrame::SlideLine(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine, nscoord aDY)
|
||||
nsLineBox* aLine, nscoord aDeltaBCoord)
|
||||
{
|
||||
NS_PRECONDITION(aDY != 0, "why slide a line nowhere?");
|
||||
NS_PRECONDITION(aDeltaBCoord != 0, "why slide a line nowhere?");
|
||||
|
||||
// Adjust line state
|
||||
aLine->SlideBy(aDY, aState.mContainerWidth);
|
||||
aLine->SlideBy(aDeltaBCoord, aState.mContainerWidth);
|
||||
|
||||
// Adjust the frames in the line
|
||||
nsIFrame* kid = aLine->mFirstChild;
|
||||
|
@ -2744,23 +2783,26 @@ nsBlockFrame::SlideLine(nsBlockReflowState& aState,
|
|||
return;
|
||||
}
|
||||
|
||||
WritingMode wm = GetWritingMode();
|
||||
LogicalPoint translation(wm, 0, aDeltaBCoord);
|
||||
|
||||
if (aLine->IsBlock()) {
|
||||
if (aDY) {
|
||||
kid->MovePositionBy(nsPoint(0, aDY));
|
||||
if (aDeltaBCoord) {
|
||||
kid->MovePositionBy(wm, translation);
|
||||
}
|
||||
|
||||
// Make sure the frame's view and any child views are updated
|
||||
nsContainerFrame::PlaceFrameView(kid);
|
||||
}
|
||||
else {
|
||||
// Adjust the Y coordinate of the frames in the line.
|
||||
// Note: we need to re-position views even if aDY is 0, because
|
||||
// Adjust the block-dir coordinate of the frames in the line.
|
||||
// Note: we need to re-position views even if aDeltaBCoord is 0, because
|
||||
// one of our parent frames may have moved and so the view's position
|
||||
// relative to its parent may have changed
|
||||
// relative to its parent may have changed.
|
||||
int32_t n = aLine->GetChildCount();
|
||||
while (--n >= 0) {
|
||||
if (aDY) {
|
||||
kid->MovePositionBy(nsPoint(0, aDY));
|
||||
if (aDeltaBCoord) {
|
||||
kid->MovePositionBy(wm, translation);
|
||||
}
|
||||
// Make sure the frame's view and any child views are updated
|
||||
nsContainerFrame::PlaceFrameView(kid);
|
||||
|
|
|
@ -408,11 +408,11 @@ protected:
|
|||
mState |= aFlags;
|
||||
}
|
||||
|
||||
/** move the frames contained by aLine by aDY
|
||||
/** move the frames contained by aLine by aDeltaBCoord
|
||||
* if aLine is a block, its child floats are added to the state manager
|
||||
*/
|
||||
void SlideLine(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine, nscoord aDY);
|
||||
nsLineBox* aLine, nscoord aDeltaBCoord);
|
||||
|
||||
void ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nsBlockReflowState& aState,
|
||||
|
|
|
@ -54,8 +54,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
aFrame->GetLogicalSkipSides(&aReflowState);
|
||||
mBorderPadding.ApplySkipSides(logicalSkipSides);
|
||||
|
||||
// Note that mContainerWidth is the physical width!
|
||||
mContainerWidth = aReflowState.ComputedWidth() + mBorderPadding.LeftRight(wm);
|
||||
// Note that mContainerWidth is the physical width, needed to convert
|
||||
// logical block-coordinates in vertical-rl writing mode (measured from a
|
||||
// RHS origin) to physical coordinates within the containing block.
|
||||
// If aReflowState doesn't have a constrained ComputedWidth(), we set it to
|
||||
// zero, which means lines will be positioned (physically) incorrectly;
|
||||
// we will fix them up at the end of nsBlockFrame::Reflow, after we know
|
||||
// the total block-size of the frame.
|
||||
mContainerWidth = aReflowState.ComputedWidth();
|
||||
if (mContainerWidth == NS_UNCONSTRAINEDSIZE) {
|
||||
mContainerWidth = 0;
|
||||
}
|
||||
|
||||
mContainerWidth += mBorderPadding.LeftRight(wm);
|
||||
|
||||
if ((aBStartMarginRoot && !logicalSkipSides.BStart()) ||
|
||||
0 != mBorderPadding.BStart(wm)) {
|
||||
|
|
|
@ -203,6 +203,8 @@ public:
|
|||
mozilla::WritingMode wm = mReflowState.GetWritingMode();
|
||||
return mContentArea.Size(wm).ConvertTo(aWM, wm);
|
||||
}
|
||||
|
||||
// Physical width. Use only for physical <-> logical coordinate conversion.
|
||||
nscoord mContainerWidth;
|
||||
|
||||
// Continuation out-of-flow float frames that need to move to our
|
||||
|
|
|
@ -1339,7 +1339,12 @@ nsFrame::GetLogicalBaseline(WritingMode aWritingMode) const
|
|||
{
|
||||
NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
|
||||
"frame must not be dirty");
|
||||
// Default to the bottom margin edge, per CSS2.1's definition of the
|
||||
// Baseline for inverted line content is the top (block-start) margin edge,
|
||||
// as the frame is in effect "flipped" for alignment purposes.
|
||||
if (aWritingMode.IsLineInverted()) {
|
||||
return -GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode);
|
||||
}
|
||||
// Otherwise, the bottom margin edge, per CSS2.1's definition of the
|
||||
// 'baseline' value of 'vertical-align'.
|
||||
return BSize(aWritingMode) +
|
||||
GetLogicalUsedMargin(aWritingMode).BEnd(aWritingMode);
|
||||
|
|
|
@ -608,7 +608,7 @@ public:
|
|||
* The frame's writing-mode, used for logical layout computations.
|
||||
*/
|
||||
mozilla::WritingMode GetWritingMode() const {
|
||||
return mozilla::WritingMode(StyleVisibility());
|
||||
return mozilla::WritingMode(StyleContext());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -744,6 +744,15 @@ public:
|
|||
*/
|
||||
void MovePositionBy(const nsPoint& aTranslation);
|
||||
|
||||
/**
|
||||
* As above, using a logical-point delta in a given writing mode.
|
||||
*/
|
||||
void MovePositionBy(mozilla::WritingMode aWritingMode,
|
||||
const mozilla::LogicalPoint& aTranslation)
|
||||
{
|
||||
MovePositionBy(aTranslation.GetPhysicalPoint(aWritingMode, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return frame's position without relative positioning
|
||||
*/
|
||||
|
|
|
@ -473,8 +473,10 @@ public:
|
|||
mContainerWidth = aContainerWidth;
|
||||
mBounds.BStart(mWritingMode) += aDBCoord;
|
||||
if (mData) {
|
||||
nsPoint physicalDelta = mozilla::LogicalPoint(mWritingMode, 0, aDBCoord).
|
||||
GetPhysicalPoint(mWritingMode, 0);
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
mData->mOverflowAreas.Overflow(otype).y += aDBCoord;
|
||||
mData->mOverflowAreas.Overflow(otype) += physicalDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -585,9 +587,13 @@ public:
|
|||
nsIFrame* mFirstChild;
|
||||
|
||||
mozilla::WritingMode mWritingMode;
|
||||
|
||||
// Physical width. Use only for physical <-> logical coordinate conversion.
|
||||
nscoord mContainerWidth;
|
||||
|
||||
private:
|
||||
mozilla::LogicalRect mBounds;
|
||||
|
||||
public:
|
||||
const mozilla::LogicalRect& GetBounds() { return mBounds; }
|
||||
nsRect GetPhysicalBounds() const
|
||||
|
|
|
@ -608,8 +608,8 @@ nsLineLayout::NewPerFrameData(nsIFrame* aFrame)
|
|||
WritingMode frameWM = aFrame->GetWritingMode();
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
pfd->mBounds = LogicalRect(lineWM);
|
||||
pfd->mMargin = LogicalMargin(frameWM);
|
||||
pfd->mBorderPadding = LogicalMargin(frameWM);
|
||||
pfd->mMargin = LogicalMargin(lineWM);
|
||||
pfd->mBorderPadding = LogicalMargin(lineWM);
|
||||
pfd->mOffsets = LogicalMargin(frameWM);
|
||||
|
||||
pfd->mJustificationInfo = JustificationInfo();
|
||||
|
@ -809,9 +809,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
}
|
||||
WritingMode stateWM = reflowState.GetWritingMode();
|
||||
pfd->mMargin =
|
||||
reflowState.ComputedLogicalMargin().ConvertTo(frameWM, stateWM);
|
||||
reflowState.ComputedLogicalMargin().ConvertTo(lineWM, stateWM);
|
||||
pfd->mBorderPadding =
|
||||
reflowState.ComputedLogicalBorderPadding().ConvertTo(frameWM, stateWM);
|
||||
reflowState.ComputedLogicalBorderPadding().ConvertTo(lineWM, stateWM);
|
||||
pfd->SetFlag(PFD_RELATIVEPOS,
|
||||
reflowState.mStyleDisplay->IsRelativelyPositionedStyle());
|
||||
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
||||
|
@ -1086,7 +1086,7 @@ nsLineLayout::AllowForStartMargin(PerFrameData* pfd,
|
|||
"How'd we get a floated inline frame? "
|
||||
"The frame ctor should've dealt with this.");
|
||||
|
||||
WritingMode frameWM = pfd->mFrame->GetWritingMode();
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
|
||||
// Only apply start-margin on the first-in flow for inline frames,
|
||||
// and make sure to not apply it to any inline other than the first
|
||||
|
@ -1101,7 +1101,7 @@ nsLineLayout::AllowForStartMargin(PerFrameData* pfd,
|
|||
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
|
||||
// Zero this out so that when we compute the max-element-width of
|
||||
// the frame we will properly avoid adding in the starting margin.
|
||||
pfd->mMargin.IStart(frameWM) = 0;
|
||||
pfd->mMargin.IStart(lineWM) = 0;
|
||||
} else {
|
||||
NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.AvailableISize(),
|
||||
"have unconstrained inline-size; this should only result "
|
||||
|
@ -1112,7 +1112,9 @@ nsLineLayout::AllowForStartMargin(PerFrameData* pfd,
|
|||
// in the reflow state), adjust available inline-size to account for the
|
||||
// start margin. The end margin will be accounted for when we
|
||||
// finish flowing the frame.
|
||||
aReflowState.AvailableISize() -= pfd->mMargin.IStart(frameWM);
|
||||
WritingMode wm = aReflowState.GetWritingMode();
|
||||
aReflowState.AvailableISize() -=
|
||||
pfd->mMargin.ConvertTo(wm, lineWM).IStart(wm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1151,7 +1153,6 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
|
||||
*aOptionalBreakAfterFits = true;
|
||||
|
||||
WritingMode frameWM = pfd->mFrame->GetWritingMode();
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
/*
|
||||
* We want to only apply the end margin if we're the last continuation and
|
||||
|
@ -1176,14 +1177,12 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
!pfd->GetFlag(PFD_ISLETTERFRAME) &&
|
||||
pfd->mFrame->StyleBorder()->mBoxDecorationBreak ==
|
||||
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
|
||||
pfd->mMargin.IEnd(frameWM) = 0;
|
||||
pfd->mMargin.IEnd(lineWM) = 0;
|
||||
}
|
||||
|
||||
// Convert the frame's margins to the line's writing mode and apply
|
||||
// the start margin to the frame bounds.
|
||||
LogicalMargin usedMargins = pfd->mMargin.ConvertTo(lineWM, frameWM);
|
||||
nscoord startMargin = usedMargins.IStart(lineWM);
|
||||
nscoord endMargin = usedMargins.IEnd(lineWM);
|
||||
// Apply the start margin to the frame bounds.
|
||||
nscoord startMargin = pfd->mMargin.IStart(lineWM);
|
||||
nscoord endMargin = pfd->mMargin.IEnd(lineWM);
|
||||
|
||||
pfd->mBounds.IStart(lineWM) += startMargin;
|
||||
|
||||
|
@ -1310,7 +1309,6 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
void
|
||||
nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
{
|
||||
WritingMode frameWM = pfd->mFrame->GetWritingMode();
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
|
||||
// Record ascent and update max-ascent and max-descent values
|
||||
|
@ -1322,7 +1320,7 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
|||
|
||||
// Advance to next inline coordinate
|
||||
mCurrentSpan->mICoord = pfd->mBounds.IEnd(lineWM) +
|
||||
pfd->mMargin.ConvertTo(lineWM, frameWM).IEnd(lineWM);
|
||||
pfd->mMargin.IEnd(lineWM);
|
||||
|
||||
// Count the number of non-placeholder frames on the line...
|
||||
if (pfd->mFrame->GetType() == nsGkAtoms::placeholderFrame) {
|
||||
|
@ -1509,7 +1507,6 @@ nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
|
|||
#ifdef DEBUG
|
||||
NS_ASSERTION(0xFF != pfd->mBlockDirAlign, "umr");
|
||||
#endif
|
||||
WritingMode frameWM = pfd->mFrame->GetWritingMode();
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
nscoord containerWidth = ContainerWidthForSpan(psd);
|
||||
switch (pfd->mBlockDirAlign) {
|
||||
|
@ -1519,7 +1516,7 @@ nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
|
|||
}
|
||||
else {
|
||||
pfd->mBounds.BStart(lineWM) =
|
||||
-aDistanceFromStart + pfd->mMargin.BStart(frameWM);
|
||||
-aDistanceFromStart + pfd->mMargin.BStart(lineWM);
|
||||
}
|
||||
pfd->mFrame->SetRect(lineWM, pfd->mBounds, containerWidth);
|
||||
#ifdef NOISY_BLOCKDIR_ALIGN
|
||||
|
@ -1527,7 +1524,7 @@ nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
|
|||
nsFrame::ListTag(stdout, pfd->mFrame);
|
||||
printf(": y=%d dTop=%d [bp.top=%d topLeading=%d]\n",
|
||||
pfd->mBounds.BStart(lineWM), aDistanceFromStart,
|
||||
span ? pfd->mBorderPadding.BStart(frameWM) : 0,
|
||||
span ? pfd->mBorderPadding.BStart(lineWM) : 0,
|
||||
span ? span->mBStartLeading : 0);
|
||||
#endif
|
||||
break;
|
||||
|
@ -1539,7 +1536,7 @@ nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
|
|||
}
|
||||
else {
|
||||
pfd->mBounds.BStart(lineWM) = -aDistanceFromStart + aLineBSize -
|
||||
pfd->mMargin.BEnd(frameWM) - pfd->mBounds.BSize(lineWM);
|
||||
pfd->mMargin.BEnd(lineWM) - pfd->mBounds.BSize(lineWM);
|
||||
}
|
||||
pfd->mFrame->SetRect(lineWM, pfd->mBounds, containerWidth);
|
||||
#ifdef NOISY_BLOCKDIR_ALIGN
|
||||
|
@ -1598,7 +1595,6 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
// - it has a prev-in-flow
|
||||
// - it has no next in flow
|
||||
// - it's zero sized
|
||||
WritingMode frameWM = spanFramePFD->mFrame->GetWritingMode();
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
bool emptyContinuation = psd != mRootSpan &&
|
||||
spanFrame->GetPrevInFlow() && !spanFrame->GetNextInFlow() &&
|
||||
|
@ -1616,14 +1612,14 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
if (psd != mRootSpan) {
|
||||
WritingMode frameWM = spanFramePFD->mFrame->GetWritingMode();
|
||||
printf(" bp=%d,%d,%d,%d margin=%d,%d,%d,%d",
|
||||
spanFramePFD->mBorderPadding.Top(frameWM),
|
||||
spanFramePFD->mBorderPadding.Right(frameWM),
|
||||
spanFramePFD->mBorderPadding.Bottom(frameWM),
|
||||
spanFramePFD->mBorderPadding.Left(frameWM),
|
||||
spanFramePFD->mMargin.Top(frameWM),
|
||||
spanFramePFD->mMargin.Right(frameWM),
|
||||
spanFramePFD->mMargin.Bottom(frameWM),
|
||||
spanFramePFD->mMargin.Left(frameWM));
|
||||
spanFramePFD->mBorderPadding.Top(lineWM),
|
||||
spanFramePFD->mBorderPadding.Right(lineWM),
|
||||
spanFramePFD->mBorderPadding.Bottom(lineWM),
|
||||
spanFramePFD->mBorderPadding.Left(lineWM),
|
||||
spanFramePFD->mMargin.Top(lineWM),
|
||||
spanFramePFD->mMargin.Right(lineWM),
|
||||
spanFramePFD->mMargin.Bottom(lineWM),
|
||||
spanFramePFD->mMargin.Left(lineWM));
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
@ -1725,8 +1721,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
mBlockReflowState->ComputedHeight(),
|
||||
inflation);
|
||||
nscoord contentBSize = spanFramePFD->mBounds.BSize(lineWM) -
|
||||
spanFramePFD->mBorderPadding.BStart(frameWM) -
|
||||
spanFramePFD->mBorderPadding.BEnd(frameWM);
|
||||
spanFramePFD->mBorderPadding.BStartEnd(lineWM);
|
||||
|
||||
// Special-case for a ::first-letter frame, set the line height to
|
||||
// the frame block size if the user has left line-height == normal
|
||||
|
@ -1759,7 +1754,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
// If there are child frames in this span that stick out of this area
|
||||
// then the minBCoord and maxBCoord are updated by the amount of logical
|
||||
// blockSize that is outside this range.
|
||||
minBCoord = spanFramePFD->mBorderPadding.BStart(frameWM) -
|
||||
minBCoord = spanFramePFD->mBorderPadding.BStart(lineWM) -
|
||||
psd->mBStartLeading;
|
||||
maxBCoord = minBCoord + psd->mLogicalBSize;
|
||||
}
|
||||
|
@ -1776,8 +1771,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
printf(": baseLine=%d logicalBSize=%d topLeading=%d h=%d bp=%d,%d zeroEffectiveSpanBox=%s\n",
|
||||
baselineBCoord, psd->mLogicalBSize, psd->mBStartLeading,
|
||||
spanFramePFD->mBounds.BSize(lineWM),
|
||||
spanFramePFD->mBorderPadding.Top(frameWM),
|
||||
spanFramePFD->mBorderPadding.Bottom(frameWM),
|
||||
spanFramePFD->mBorderPadding.Top(lineWM),
|
||||
spanFramePFD->mBorderPadding.Bottom(lineWM),
|
||||
zeroEffectiveSpanBox ? "yes" : "no");
|
||||
#endif
|
||||
}
|
||||
|
@ -1787,7 +1782,6 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nullptr != pfd) {
|
||||
nsIFrame* frame = pfd->mFrame;
|
||||
WritingMode frameWM = frame->GetWritingMode();
|
||||
|
||||
// sanity check (see bug 105168, non-reproducible crashes from null frame)
|
||||
NS_ASSERTION(frame, "null frame in PerFrameData - something is very very bad");
|
||||
|
@ -1807,7 +1801,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
// For other elements the logical block size is the same as the
|
||||
// frame's block size plus its margins.
|
||||
logicalBSize = pfd->mBounds.BSize(lineWM) +
|
||||
pfd->mMargin.BStartEnd(frameWM);
|
||||
pfd->mMargin.BStartEnd(lineWM);
|
||||
if (logicalBSize < 0 &&
|
||||
mPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
|
||||
pfd->mAscent -= logicalBSize;
|
||||
|
@ -1915,7 +1909,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
else {
|
||||
pfd->mBounds.BStart(lineWM) = baselineBCoord -
|
||||
(parentXHeight + logicalBSize)/2 +
|
||||
pfd->mMargin.BStart(frameWM);
|
||||
pfd->mMargin.BStart(lineWM);
|
||||
}
|
||||
pfd->mBlockDirAlign = VALIGN_OTHER;
|
||||
break;
|
||||
|
@ -1930,11 +1924,11 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
nscoord parentAscent = fm->MaxAscent();
|
||||
if (frameSpan) {
|
||||
pfd->mBounds.BStart(lineWM) = baselineBCoord - parentAscent -
|
||||
pfd->mBorderPadding.BStart(frameWM) + frameSpan->mBStartLeading;
|
||||
pfd->mBorderPadding.BStart(lineWM) + frameSpan->mBStartLeading;
|
||||
}
|
||||
else {
|
||||
pfd->mBounds.BStart(lineWM) = baselineBCoord - parentAscent +
|
||||
pfd->mMargin.BStart(frameWM);
|
||||
pfd->mMargin.BStart(lineWM);
|
||||
}
|
||||
pfd->mBlockDirAlign = VALIGN_OTHER;
|
||||
break;
|
||||
|
@ -1948,13 +1942,13 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
if (frameSpan) {
|
||||
pfd->mBounds.BStart(lineWM) = baselineBCoord + parentDescent -
|
||||
pfd->mBounds.BSize(lineWM) +
|
||||
pfd->mBorderPadding.BEnd(frameWM) -
|
||||
pfd->mBorderPadding.BEnd(lineWM) -
|
||||
frameSpan->mBEndLeading;
|
||||
}
|
||||
else {
|
||||
pfd->mBounds.BStart(lineWM) = baselineBCoord + parentDescent -
|
||||
pfd->mBounds.BSize(lineWM) -
|
||||
pfd->mMargin.BEnd(frameWM);
|
||||
pfd->mMargin.BEnd(lineWM);
|
||||
}
|
||||
pfd->mBlockDirAlign = VALIGN_OTHER;
|
||||
break;
|
||||
|
@ -1969,7 +1963,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
}
|
||||
else {
|
||||
pfd->mBounds.BStart(lineWM) = baselineBCoord - logicalBSize/2 +
|
||||
pfd->mMargin.BStart(frameWM);
|
||||
pfd->mMargin.BStart(lineWM);
|
||||
}
|
||||
pfd->mBlockDirAlign = VALIGN_OTHER;
|
||||
break;
|
||||
|
@ -2035,7 +2029,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
}
|
||||
else {
|
||||
blockStart = pfd->mBounds.BStart(lineWM) -
|
||||
pfd->mMargin.BStart(frameWM);
|
||||
pfd->mMargin.BStart(lineWM);
|
||||
blockEnd = blockStart + logicalBSize;
|
||||
}
|
||||
if (!preMode &&
|
||||
|
@ -2054,8 +2048,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
#ifdef NOISY_BLOCKDIR_ALIGN
|
||||
printf(" [frame]raw: a=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minBCoord=%d maxBCoord=%d\n",
|
||||
pfd->mAscent, pfd->mBounds.BSize(lineWM),
|
||||
pfd->mBorderPadding.Top(frameWM),
|
||||
pfd->mBorderPadding.Bottom(frameWM),
|
||||
pfd->mBorderPadding.Top(lineWM),
|
||||
pfd->mBorderPadding.Bottom(lineWM),
|
||||
logicalBSize,
|
||||
frameSpan ? frameSpan->mBStartLeading : 0,
|
||||
pfd->mBounds.BStart(lineWM), minBCoord, maxBCoord);
|
||||
|
@ -2104,7 +2098,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
#endif
|
||||
nscoord minimumLineBSize = mMinLineBSize;
|
||||
nscoord blockStart =
|
||||
-nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize);
|
||||
-nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize,
|
||||
lineWM.IsLineInverted());
|
||||
nscoord blockEnd = blockStart + minimumLineBSize;
|
||||
|
||||
if (blockStart < minBCoord) minBCoord = blockStart;
|
||||
|
@ -2146,8 +2141,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
spanFramePFD->mAscent,
|
||||
psd->mLogicalBSize, psd->mBStartLeading, psd->mBEndLeading);
|
||||
#endif
|
||||
nscoord goodMinBCoord = spanFramePFD->mBorderPadding.BStart(frameWM) -
|
||||
psd->mBStartLeading;
|
||||
nscoord goodMinBCoord =
|
||||
spanFramePFD->mBorderPadding.BStart(lineWM) - psd->mBStartLeading;
|
||||
nscoord goodMaxBCoord = goodMinBCoord + psd->mLogicalBSize;
|
||||
|
||||
// For cases like the one in bug 714519 (text-decoration placement
|
||||
|
|
|
@ -385,9 +385,9 @@ protected:
|
|||
nsOverflowAreas mOverflowAreas;
|
||||
|
||||
// From reflow-state
|
||||
mozilla::LogicalMargin mMargin;
|
||||
mozilla::LogicalMargin mBorderPadding;
|
||||
mozilla::LogicalMargin mOffsets;
|
||||
mozilla::LogicalMargin mMargin; // in *line* writing mode
|
||||
mozilla::LogicalMargin mBorderPadding; // in *line* writing mode
|
||||
mozilla::LogicalMargin mOffsets; // in *frame* writing mode
|
||||
|
||||
// state for text justification
|
||||
mozilla::JustificationInfo mJustificationInfo;
|
||||
|
@ -537,6 +537,7 @@ protected:
|
|||
// frame, if any
|
||||
nscoord mTrimmableISize;
|
||||
|
||||
// Physical width. Use only for physical <-> logical coordinate conversion.
|
||||
nscoord mContainerWidth;
|
||||
|
||||
bool mFirstLetterStyleOK : 1;
|
||||
|
|
|
@ -1790,13 +1790,13 @@ GetHyphenTextRun(gfxTextRun* aTextRun, gfxContext* aContext, nsTextFrame* aTextF
|
|||
}
|
||||
|
||||
static gfxFont::Metrics
|
||||
GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVertical)
|
||||
GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVerticalMetrics)
|
||||
{
|
||||
if (!aFontGroup)
|
||||
return gfxFont::Metrics();
|
||||
gfxFont* font = aFontGroup->GetFirstValidFont();
|
||||
return font->GetMetrics(aVertical ? gfxFont::eVertical :
|
||||
gfxFont::eHorizontal);
|
||||
return font->GetMetrics(aVerticalMetrics ? gfxFont::eVertical
|
||||
: gfxFont::eHorizontal);
|
||||
}
|
||||
|
||||
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NORMAL == 0);
|
||||
|
@ -3161,7 +3161,7 @@ ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
|
|||
// textruns do
|
||||
gfxFloat spaceWidthAppUnits =
|
||||
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
|
||||
aTextRun->IsVertical()).spaceWidth *
|
||||
aTextRun->UseCenterBaseline()).spaceWidth *
|
||||
aTextRun->GetAppUnitsPerDevUnit());
|
||||
return textStyle->mTabSize * spaceWidthAppUnits;
|
||||
}
|
||||
|
@ -4768,15 +4768,16 @@ nsTextFrame::GetTextDecorations(
|
|||
bool useOverride = false;
|
||||
nscolor overrideColor = NS_RGBA(0, 0, 0, 0);
|
||||
|
||||
// frameTopOffset represents the offset to f's top from our baseline in our
|
||||
// frameBStartOffset represents the offset to f's BStart from our baseline in our
|
||||
// coordinate space
|
||||
// baselineOffset represents the offset from our baseline to f's baseline or
|
||||
// the nearest block's baseline, in our coordinate space, whichever is closest
|
||||
// during the particular iteration
|
||||
nscoord frameTopOffset = mAscent,
|
||||
nscoord frameBStartOffset = mAscent,
|
||||
baselineOffset = 0;
|
||||
|
||||
bool nearestBlockFound = false;
|
||||
bool vertical = GetWritingMode().IsVertical();
|
||||
|
||||
for (nsIFrame* f = this, *fChild = nullptr;
|
||||
f;
|
||||
|
@ -4819,18 +4820,20 @@ nsTextFrame::GetTextDecorations(
|
|||
const nscoord lineBaselineOffset = LazyGetLineBaselineOffset(fChild,
|
||||
fBlock);
|
||||
|
||||
baselineOffset =
|
||||
frameTopOffset - fChild->GetNormalPosition().y - lineBaselineOffset;
|
||||
baselineOffset = frameBStartOffset - lineBaselineOffset -
|
||||
(vertical ? fChild->GetNormalPosition().x
|
||||
: fChild->GetNormalPosition().y);
|
||||
}
|
||||
}
|
||||
else if (!nearestBlockFound) {
|
||||
// use a dummy WritingMode, because nsTextFrame::GetLogicalBaseLine
|
||||
// doesn't use it anyway
|
||||
baselineOffset = frameTopOffset - f->GetLogicalBaseline(WritingMode());
|
||||
baselineOffset = frameBStartOffset - f->GetLogicalBaseline(WritingMode());
|
||||
}
|
||||
|
||||
nearestBlockFound = nearestBlockFound || firstBlock;
|
||||
frameTopOffset += f->GetNormalPosition().y;
|
||||
frameBStartOffset +=
|
||||
vertical ? f->GetNormalPosition().x : f->GetNormalPosition().y;
|
||||
|
||||
const uint8_t style = styleText->GetDecorationStyle();
|
||||
if (textDecorations) {
|
||||
|
@ -4915,7 +4918,9 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
nsRect shadowRect =
|
||||
nsLayoutUtils::GetTextShadowRectsUnion(*aVisualOverflowRect, this);
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, shadowRect);
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
|
||||
bool inverted = GetWritingMode().IsLineInverted();
|
||||
|
||||
if (IsFloatingFirstLetterChild()) {
|
||||
// The underline/overline drawable area must be contained in the overflow
|
||||
|
@ -4932,11 +4937,13 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
nsFontMetrics* fontMetrics = aProvider.GetFontMetrics();
|
||||
nscoord underlineOffset, underlineSize;
|
||||
fontMetrics->GetUnderline(underlineOffset, underlineSize);
|
||||
nscoord maxAscent = fontMetrics->MaxAscent();
|
||||
nscoord maxAscent = inverted ? fontMetrics->MaxDescent()
|
||||
: fontMetrics->MaxAscent();
|
||||
|
||||
gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel();
|
||||
gfxFloat gfxWidth =
|
||||
(vertical ? aVisualOverflowRect->height : aVisualOverflowRect->width) /
|
||||
(verticalRun ? aVisualOverflowRect->height
|
||||
: aVisualOverflowRect->width) /
|
||||
appUnitsPerDevUnit;
|
||||
gfxFloat gfxAscent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
gfxFloat gfxMaxAscent = maxAscent / appUnitsPerDevUnit;
|
||||
|
@ -4945,11 +4952,11 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
nsRect underlineRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxUnderlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, vertical);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, verticalRun);
|
||||
nsRect overlineRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxMaxAscent,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, vertical);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, verticalRun);
|
||||
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, underlineRect);
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, overlineRect);
|
||||
|
@ -4969,11 +4976,16 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
nscoord inflationMinFontSize =
|
||||
nsLayoutUtils::InflationMinFontSizeFor(aBlock);
|
||||
|
||||
const nscoord measure = vertical ? GetSize().height : GetSize().width;
|
||||
const nscoord measure = verticalRun ? GetSize().height : GetSize().width;
|
||||
const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(),
|
||||
gfxWidth = measure / appUnitsPerDevUnit,
|
||||
ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
nscoord top(nscoord_MAX), bottom(nscoord_MIN);
|
||||
gfxWidth = measure / appUnitsPerDevUnit;
|
||||
gfxFloat ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
const WritingMode wm = GetWritingMode();
|
||||
if (wm.IsVerticalRL()) {
|
||||
ascent = -ascent;
|
||||
}
|
||||
|
||||
nscoord topOrLeft(nscoord_MAX), bottomOrRight(nscoord_MIN);
|
||||
// Below we loop through all text decorations and compute the rectangle
|
||||
// containing all of them, in this frame's coordinate space
|
||||
for (uint32_t i = 0; i < textDecs.mUnderlines.Length(); ++i) {
|
||||
|
@ -4990,18 +5002,23 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.underlineSize),
|
||||
ascent, metrics.underlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle,
|
||||
vertical) +
|
||||
verticalRun) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
if (verticalRun) {
|
||||
topOrLeft = std::min(decorationRect.x, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
|
||||
} else {
|
||||
topOrLeft = std::min(decorationRect.y, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < textDecs.mOverlines.Length(); ++i) {
|
||||
const LineDecoration& dec = textDecs.mOverlines[i];
|
||||
|
@ -5017,18 +5034,23 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.underlineSize),
|
||||
ascent, metrics.maxAscent,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle,
|
||||
vertical) +
|
||||
verticalRun) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
if (verticalRun) {
|
||||
topOrLeft = std::min(decorationRect.x, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
|
||||
} else {
|
||||
topOrLeft = std::min(decorationRect.y, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < textDecs.mStrikes.Length(); ++i) {
|
||||
const LineDecoration& dec = textDecs.mStrikes[i];
|
||||
|
@ -5044,23 +5066,29 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.strikeoutSize),
|
||||
ascent, metrics.strikeoutOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationStyle,
|
||||
vertical) +
|
||||
verticalRun) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
|
||||
if (verticalRun) {
|
||||
topOrLeft = std::min(decorationRect.x, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
|
||||
} else {
|
||||
topOrLeft = std::min(decorationRect.y, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
|
||||
}
|
||||
}
|
||||
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect,
|
||||
vertical ?
|
||||
nsRect(top, 0, bottom - top, measure) :
|
||||
nsRect(0, top, measure, bottom - top));
|
||||
aVisualOverflowRect->UnionRect(
|
||||
*aVisualOverflowRect,
|
||||
verticalRun ? nsRect(topOrLeft, 0, bottomOrRight - topOrLeft, measure)
|
||||
: nsRect(0, topOrLeft, measure, bottomOrRight - topOrLeft));
|
||||
}
|
||||
}
|
||||
// When this frame is not selected, the text-decoration area must be in
|
||||
|
@ -5720,19 +5748,20 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
|||
}
|
||||
|
||||
gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont();
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
|
||||
gfxFont::Metrics
|
||||
decorationMetrics(firstFont->GetMetrics(vertical ?
|
||||
decorationMetrics(firstFont->GetMetrics(useVerticalMetrics ?
|
||||
gfxFont::eVertical : gfxFont::eHorizontal));
|
||||
if (!vertical) {
|
||||
if (!useVerticalMetrics) {
|
||||
// The potential adjustment from using gfxFontGroup::GetUnderlineOffset
|
||||
// is only valid for horizontal text.
|
||||
// is only valid for horizontal font metrics.
|
||||
decorationMetrics.underlineOffset =
|
||||
aProvider.GetFontGroup()->GetUnderlineOffset();
|
||||
}
|
||||
|
||||
gfxFloat startIOffset =
|
||||
vertical ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
|
||||
verticalRun ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
|
||||
SelectionIterator iterator(selectedChars, aContentOffset, aContentLength,
|
||||
aProvider, mTextRun, startIOffset);
|
||||
gfxFloat iOffset, hyphenWidth;
|
||||
|
@ -5740,7 +5769,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
|||
int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
|
||||
// XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
|
||||
gfxPoint pt;
|
||||
if (vertical) {
|
||||
if (verticalRun) {
|
||||
pt.x = (aTextBaselinePt.x - mAscent) / app;
|
||||
} else {
|
||||
pt.y = (aTextBaselinePt.y - mAscent) / app;
|
||||
|
@ -5754,7 +5783,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
|||
gfxFloat advance = hyphenWidth +
|
||||
mTextRun->GetAdvanceWidth(offset, length, &aProvider);
|
||||
if (type == aSelectionType) {
|
||||
if (vertical) {
|
||||
if (verticalRun) {
|
||||
pt.y = (aFramePt.y + iOffset -
|
||||
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
|
||||
} else {
|
||||
|
@ -5766,7 +5795,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
|||
DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this,
|
||||
aTextPaintStyle, selectedStyle, pt, xInFrame,
|
||||
width, mAscent / app, decorationMetrics,
|
||||
aCallbacks, vertical);
|
||||
aCallbacks, verticalRun);
|
||||
}
|
||||
iterator.UpdateWithAdvance(advance);
|
||||
}
|
||||
|
@ -6010,13 +6039,15 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
|
|||
|
||||
gfxContext* ctx = aRenderingContext->ThebesContext();
|
||||
const bool rtl = mTextRun->IsRightToLeft();
|
||||
const bool vertical = mTextRun->IsVertical();
|
||||
const bool verticalRun = mTextRun->IsVertical();
|
||||
WritingMode wm = GetWritingMode();
|
||||
const nscoord frameWidth = GetSize().width;
|
||||
gfxPoint framePt(aPt.x, aPt.y);
|
||||
gfxPoint textBaselinePt;
|
||||
if (vertical) {
|
||||
textBaselinePt = gfxPoint(aPt.x + mAscent,
|
||||
rtl ? gfxFloat(aPt.y + GetSize().height) : aPt.y);
|
||||
if (verticalRun) {
|
||||
textBaselinePt = // XXX sideways-left will need different handling here
|
||||
gfxPoint(aPt.x + (wm.IsVerticalLR() ? mAscent : frameWidth - mAscent),
|
||||
rtl ? aPt.y + GetSize().height : aPt.y);
|
||||
} else {
|
||||
textBaselinePt = gfxPoint(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x,
|
||||
nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));
|
||||
|
@ -6028,7 +6059,7 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
|
|||
&startOffset, &maxLength, &snappedLeftEdge, &snappedRightEdge)) {
|
||||
return;
|
||||
}
|
||||
if (vertical) {
|
||||
if (verticalRun) {
|
||||
textBaselinePt.y += rtl ? -snappedRightEdge : snappedLeftEdge;
|
||||
} else {
|
||||
textBaselinePt.x += rtl ? -snappedRightEdge : snappedLeftEdge;
|
||||
|
@ -6153,17 +6184,43 @@ nsTextFrame::DrawTextRunAndDecorations(
|
|||
nsTextFrame::DrawPathCallbacks* aCallbacks)
|
||||
{
|
||||
const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel();
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
|
||||
|
||||
// XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
|
||||
nscoord x = NSToCoordRound(aFramePt.x);
|
||||
nscoord width = vertical ? GetRect().height : GetRect().width;
|
||||
aClipEdges.Intersect(&x, &width);
|
||||
nscoord y = NSToCoordRound(aFramePt.y);
|
||||
|
||||
gfxPoint decPt(x / app, 0);
|
||||
gfxSize decSize(width / app, 0);
|
||||
const gfxFloat ascent = gfxFloat(mAscent) / app;
|
||||
const gfxFloat frameTop = aFramePt.y;
|
||||
// 'measure' here is textrun-relative, so for a horizontal run it's the
|
||||
// width, while for a vertical run it's the height of the decoration
|
||||
const nsSize frameSize = GetSize();
|
||||
nscoord measure = verticalRun ? frameSize.height : frameSize.width;
|
||||
|
||||
// XXX todo: probably should have a vertical version of this...
|
||||
if (!verticalRun) {
|
||||
aClipEdges.Intersect(&x, &measure);
|
||||
}
|
||||
|
||||
// decPt is the physical point where the decoration is to be drawn,
|
||||
// relative to the frame; one of its coordinates will be updated below.
|
||||
gfxPoint decPt(x / app, y / app);
|
||||
gfxFloat& bCoord = verticalRun ? decPt.x : decPt.y;
|
||||
|
||||
// decSize is a textrun-relative size, so its 'width' field is actually
|
||||
// the run-relative measure, and 'height' will be the line thickness
|
||||
gfxSize decSize(measure / app, 0);
|
||||
gfxFloat ascent = gfxFloat(mAscent) / app;
|
||||
|
||||
// The starting edge of the frame in block direction
|
||||
gfxFloat frameBStart = verticalRun ? aFramePt.x : aFramePt.y;
|
||||
|
||||
// In vertical-rl mode, block coordinates are measured from the right,
|
||||
// so we need to adjust here.
|
||||
const WritingMode wm = GetWritingMode();
|
||||
if (wm.IsVerticalRL()) {
|
||||
frameBStart += frameSize.width;
|
||||
ascent = -ascent;
|
||||
}
|
||||
|
||||
gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app,
|
||||
aDirtyRect.Width() / app, aDirtyRect.Height() / app);
|
||||
|
@ -6182,15 +6239,15 @@ nsTextFrame::DrawTextRunAndDecorations(
|
|||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
decSize.height = metrics.underlineSize;
|
||||
decPt.y = (frameTop - dec.mBaselineOffset) / app;
|
||||
bCoord = (frameBStart - dec.mBaselineOffset) / app;
|
||||
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, vertical);
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
|
||||
}
|
||||
// Overlines
|
||||
for (uint32_t i = aDecorations.mOverlines.Length(); i-- > 0; ) {
|
||||
|
@ -6203,15 +6260,15 @@ nsTextFrame::DrawTextRunAndDecorations(
|
|||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
decSize.height = metrics.underlineSize;
|
||||
decPt.y = (frameTop - dec.mBaselineOffset) / app;
|
||||
bCoord = (frameBStart - dec.mBaselineOffset) / app;
|
||||
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
|
||||
eNormalDecoration, aCallbacks, vertical);
|
||||
eNormalDecoration, aCallbacks, verticalRun);
|
||||
}
|
||||
|
||||
// CSS 2.1 mandates that text be painted after over/underlines, and *then*
|
||||
|
@ -6230,15 +6287,15 @@ nsTextFrame::DrawTextRunAndDecorations(
|
|||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
decSize.height = metrics.strikeoutSize;
|
||||
decPt.y = (frameTop - dec.mBaselineOffset) / app;
|
||||
bCoord = (frameBStart - dec.mBaselineOffset) / app;
|
||||
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, vertical);
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6437,9 +6494,12 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
|||
GetFontSizeInflation());
|
||||
gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
|
||||
gfxFont* firstFont = fontGroup->GetFirstValidFont();
|
||||
bool vertical = GetWritingMode().IsVertical();
|
||||
WritingMode wm = GetWritingMode();
|
||||
bool verticalRun = wm.IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && !wm.IsSideways();
|
||||
const gfxFont::Metrics& metrics =
|
||||
firstFont->GetMetrics(vertical ? gfxFont::eVertical : gfxFont::eHorizontal);
|
||||
firstFont->GetMetrics(useVerticalMetrics ? gfxFont::eVertical
|
||||
: gfxFont::eHorizontal);
|
||||
gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
|
||||
gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent);
|
||||
gfxFloat descentLimit =
|
||||
|
@ -6484,7 +6544,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
|||
decorationArea =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext, size,
|
||||
ascent, underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
|
||||
style, vertical, descentLimit);
|
||||
style, verticalRun, descentLimit);
|
||||
aRect.UnionRect(aRect, decorationArea);
|
||||
}
|
||||
DestroySelectionDetails(details);
|
||||
|
@ -7596,7 +7656,11 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const
|
|||
aContext, &provider);
|
||||
// mAscent should be the same as metrics.mAscent, but it's what we use to
|
||||
// paint so that's the one we'll use.
|
||||
nsRect boundingBox = RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent);
|
||||
nsRect boundingBox = RoundOut(metrics.mBoundingBox);
|
||||
if (GetWritingMode().IsLineInverted()) {
|
||||
boundingBox.y = -boundingBox.YMost();
|
||||
}
|
||||
boundingBox += nsPoint(0, mAscent);
|
||||
if (mTextRun->IsVertical()) {
|
||||
// Swap line-relative textMetrics dimensions to physical coordinates.
|
||||
Swap(boundingBox.x, boundingBox.y);
|
||||
|
@ -8281,9 +8345,15 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||
finalSize.BSize(wm) = 0;
|
||||
} else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) {
|
||||
// Use actual text metrics for floating first letter frame.
|
||||
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
|
||||
NSToCoordCeil(textMetrics.mDescent);
|
||||
if (wm.IsLineInverted()) {
|
||||
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mDescent));
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
|
||||
NSToCoordCeil(textMetrics.mAscent);
|
||||
} else {
|
||||
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
|
||||
NSToCoordCeil(textMetrics.mDescent);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, ascent should contain the overline drawable area.
|
||||
// And also descent should contain the underline drawable area.
|
||||
|
@ -8291,9 +8361,15 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||
nsFontMetrics* fm = provider.GetFontMetrics();
|
||||
nscoord fontAscent = fm->MaxAscent();
|
||||
nscoord fontDescent = fm->MaxDescent();
|
||||
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
|
||||
nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
|
||||
if (wm.IsLineInverted()) {
|
||||
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent));
|
||||
nscoord descent = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent);
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
|
||||
} else {
|
||||
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
|
||||
nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
|
||||
}
|
||||
}
|
||||
aMetrics.SetSize(wm, finalSize);
|
||||
|
||||
|
@ -8306,13 +8382,17 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||
mAscent = aMetrics.BlockStartAscent();
|
||||
|
||||
// Handle text that runs outside its normal bounds.
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent);
|
||||
aMetrics.SetOverflowAreasToDesiredBounds();
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
|
||||
if (wm.IsLineInverted()) {
|
||||
boundingBox.y = -boundingBox.YMost();
|
||||
}
|
||||
boundingBox += nsPoint(0, mAscent);
|
||||
if (mTextRun->IsVertical()) {
|
||||
// Swap line-relative textMetrics dimensions to physical coordinates.
|
||||
Swap(boundingBox.x, boundingBox.y);
|
||||
Swap(boundingBox.width, boundingBox.height);
|
||||
}
|
||||
aMetrics.SetOverflowAreasToDesiredBounds();
|
||||
aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox);
|
||||
|
||||
// When we have text decorations, we don't need to compute their overflow now
|
||||
|
@ -8528,18 +8608,23 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState)
|
|||
ComputeTransformedLength(provider),
|
||||
gfxFont::LOOSE_INK_EXTENTS, nullptr,
|
||||
&provider);
|
||||
nsRect &vis = result.VisualOverflow();
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent);
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
|
||||
if (GetWritingMode().IsLineInverted()) {
|
||||
boundingBox.y = -boundingBox.YMost();
|
||||
}
|
||||
boundingBox += nsPoint(0, mAscent);
|
||||
if (mTextRun->IsVertical()) {
|
||||
// Swap line-relative textMetrics dimensions to physical coordinates.
|
||||
Swap(boundingBox.x, boundingBox.y);
|
||||
Swap(boundingBox.width, boundingBox.height);
|
||||
}
|
||||
nsRect &vis = result.VisualOverflow();
|
||||
vis.UnionRect(vis, boundingBox);
|
||||
UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider,
|
||||
&vis, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char16_t TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
|
||||
uint32_t aSkippedOffset, char16_t aChar)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1083892</title>
|
||||
<style>
|
||||
div {
|
||||
width:300px;
|
||||
height:300px;
|
||||
padding:10px;
|
||||
border:1px solid black;
|
||||
writing-mode:vertical-rl;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
This is the <b><i>first</i> paragraph</b>. It's long enough to wrap onto multiple lines.<br>
|
||||
<b>Paragraph <i>two</i></b>.<br>
|
||||
<b><i>Third and final</i> paragraph</b> of this simple testcase. That's all, folks!
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1083892</title>
|
||||
<style>
|
||||
div {
|
||||
width:300px;
|
||||
height:300px;
|
||||
padding:10px;
|
||||
border:1px solid black;
|
||||
writing-mode:vertical-rl;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<p>This is the <b><i>first</i> paragraph</b>. It's long enough to wrap onto multiple lines.
|
||||
<p><b>Paragraph <i>two</i></b>.
|
||||
<p><b><i>Third and final</i> paragraph</b> of this simple testcase. That's all, folks!
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.v-lr { writing-mode:vertical-lr; }
|
||||
.v-rl { writing-mode:vertical-rl; }
|
||||
|
||||
div {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background: #ddd;
|
||||
margin: 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="v-lr">
|
||||
First part of the block.
|
||||
<i id="test">New text inserted by script, to cause a reflow that slides the following lines.</i>
|
||||
We will insert enough new content that it wraps onto additional lines.
|
||||
<br><br>
|
||||
Here is some more text that follows a forced break.
|
||||
Observe what happens to it when text is added earlier.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.v-lr { writing-mode:vertical-lr; }
|
||||
.v-rl { writing-mode:vertical-rl; }
|
||||
|
||||
div {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background: #ddd;
|
||||
margin: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function doTest() {
|
||||
document.getElementById("test").textContent =
|
||||
"New text inserted by script, to cause a reflow that slides the following lines.";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="doTest()">
|
||||
|
||||
<div class="v-lr">
|
||||
First part of the block.
|
||||
<i id="test"></i>
|
||||
We will insert enough new content that it wraps onto additional lines.
|
||||
<br><br>
|
||||
Here is some more text that follows a forced break.
|
||||
Observe what happens to it when text is added earlier.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.v-lr { writing-mode:vertical-lr; }
|
||||
.v-rl { writing-mode:vertical-rl; }
|
||||
|
||||
div {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background: #ddd;
|
||||
margin: 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="v-rl">
|
||||
First part of the block.
|
||||
<i id="test">New text inserted by script, to cause a reflow that slides the following lines.</i>
|
||||
We will insert enough new content that it wraps onto additional lines.
|
||||
<br><br>
|
||||
Here is some more text that follows a forced break.
|
||||
Observe what happens to it when text is added earlier.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.v-lr { writing-mode:vertical-lr; }
|
||||
.v-rl { writing-mode:vertical-rl; }
|
||||
|
||||
div {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background: #ddd;
|
||||
margin: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function doTest() {
|
||||
document.getElementById("test").textContent =
|
||||
"New text inserted by script, to cause a reflow that slides the following lines.";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="doTest()">
|
||||
|
||||
<div class="v-rl">
|
||||
First part of the block.
|
||||
<i id="test"></i>
|
||||
We will insert enough new content that it wraps onto additional lines.
|
||||
<br><br>
|
||||
Here is some more text that follows a forced break.
|
||||
Observe what happens to it when text is added earlier.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.h { writing-mode:horizontal-tb; }
|
||||
.v-lr { writing-mode:vertical-lr; text-orientation:sideways-right; }
|
||||
.v-rl { writing-mode:vertical-rl; text-orientation:sideways-right; }
|
||||
|
||||
div {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
border: 1px solid red;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
font: 16px monospace;
|
||||
line-height: 32px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
你好吗? hello
|
||||
</div>
|
||||
|
||||
<div class="v-lr">
|
||||
你好吗? hello
|
||||
</div>
|
||||
|
||||
<div class="v-rl">
|
||||
你好吗? hello
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.h { writing-mode:horizontal-tb; }
|
||||
.v-lr { writing-mode:vertical-lr; text-orientation:sideways-right; }
|
||||
.v-rl { writing-mode:vertical-rl; text-orientation:sideways-right; }
|
||||
|
||||
div {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
border: 1px solid red;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
font: 16px monospace;
|
||||
line-height: 32px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
你好吗? <span>hello</span>
|
||||
</div>
|
||||
|
||||
<div class="v-lr">
|
||||
你好吗? <span>hello</span>
|
||||
</div>
|
||||
|
||||
<div class="v-rl">
|
||||
你好吗? <span>hello</span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with orientation:sideways-right
|
||||
// test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:sideways-right', 0);
|
||||
|
||||
// Reference: horizontal text with 90° rotation
|
||||
// test(100, 50, 'Hello', 'writing-mode:horizontal-tb', Math.PI/2);
|
||||
|
||||
// Non-reference: vertical text with orientation:mixed
|
||||
test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:mixed', 0);
|
||||
|
||||
</script>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with orientation:sideways-right
|
||||
// test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:sideways-right', 0);
|
||||
|
||||
// Reference: horizontal text with 90° rotation
|
||||
test(100, 50, 'Hello', 'writing-mode:horizontal-tb', Math.PI/2);
|
||||
|
||||
// Non-reference: vertical text with orientation:mixed
|
||||
// test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:mixed', 0);
|
||||
|
||||
</script>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with orientation:sideways-right
|
||||
test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:sideways-right', 0);
|
||||
|
||||
// Reference: horizontal text with 90° rotation
|
||||
// test(100, 50, 'Hello', 'writing-mode:horizontal-tb', Math.PI/2);
|
||||
|
||||
// Non-reference: vertical text with orientation:mixed
|
||||
// test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:mixed', 0);
|
||||
|
||||
</script>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation, baseline) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
if (baseline != '') {
|
||||
ctx.textBaseline = baseline;
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with orientation:mixed
|
||||
// test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:mixed', 0, '');
|
||||
|
||||
// Reference: horizontal text with 90° rotation and textBaseline=middle
|
||||
test(100, 50, 'Hello', 'writing-mode:horizontal-tb', Math.PI/2, 'middle');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation, baseline) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
if (baseline != '') {
|
||||
ctx.textBaseline = baseline;
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with orientation:mixed
|
||||
test(100, 50, 'Hello', 'writing-mode:vertical-lr;text-orientation:mixed', 0, '');
|
||||
|
||||
// Reference: horizontal text with 90° rotation and textBaseline=middle
|
||||
// test(100, 50, 'Hello', 'writing-mode:horizontal-tb', Math.PI/2, 'middle');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation, baseline) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
if (baseline != '') {
|
||||
ctx.textBaseline = baseline;
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with various textBaselines
|
||||
// test(100, 50, 'Top', 'writing-mode:vertical-lr', 0, 'top');
|
||||
// test(150, 50, 'Middle', 'writing-mode:vertical-lr', 0, 'middle');
|
||||
// test(200, 50, 'Alphabetic', 'writing-mode:vertical-lr', 0, 'alphabetic');
|
||||
// test(250, 50, 'Bottom', 'writing-mode:vertical-lr', 0, 'bottom');
|
||||
|
||||
// Reference: horizontal text with 90° rotation and the same baselines
|
||||
test(100, 50, 'Top', 'writing-mode:horizontal-tb', Math.PI/2, 'top');
|
||||
test(150, 50, 'Middle', 'writing-mode:horizontal-tb', Math.PI/2, 'middle');
|
||||
test(200, 50, 'Alphabetic', 'writing-mode:horizontal-tb', Math.PI/2, 'alphabetic');
|
||||
test(250, 50, 'Bottom', 'writing-mode:horizontal-tb', Math.PI/2, 'bottom');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var testFont = '40px sans-serif';
|
||||
|
||||
function test(x, y, text, style, rotation, baseline) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 400;
|
||||
canvas.height = 400;
|
||||
canvas.style.cssText = 'position:absolute;' + style;
|
||||
document.getElementsByTagName('body')[0].appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - 20, y); ctx.lineTo(x + 20, y);
|
||||
ctx.moveTo(x, y - 20); ctx.lineTo(x, y + 20);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1.0;
|
||||
ctx.font = testFont;
|
||||
if (rotation != 0) {
|
||||
ctx.translate(x,y);
|
||||
ctx.rotate(rotation);
|
||||
ctx.translate(-x,-y);
|
||||
}
|
||||
if (baseline != '') {
|
||||
ctx.textBaseline = baseline;
|
||||
}
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
|
||||
// Testcase: vertical text with various textBaselines
|
||||
test(100, 50, 'Top', 'writing-mode:vertical-lr', 0, 'top');
|
||||
test(150, 50, 'Middle', 'writing-mode:vertical-lr', 0, 'middle');
|
||||
test(200, 50, 'Alphabetic', 'writing-mode:vertical-lr', 0, 'alphabetic');
|
||||
test(250, 50, 'Bottom', 'writing-mode:vertical-lr', 0, 'bottom');
|
||||
|
||||
// Reference: horizontal text with 90° rotation and the same baselines
|
||||
// test(100, 50, 'Top', 'writing-mode:horizontal-tb', Math.PI/2, 'top');
|
||||
// test(150, 50, 'Middle', 'writing-mode:horizontal-tb', Math.PI/2, 'middle');
|
||||
// test(200, 50, 'Alphabetic', 'writing-mode:horizontal-tb', Math.PI/2, 'alphabetic');
|
||||
// test(250, 50, 'Bottom', 'writing-mode:horizontal-tb', Math.PI/2, 'bottom');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.h { writing-mode:horizontal-tb; }
|
||||
.v-lr { writing-mode:vertical-lr; }
|
||||
.v-rl { writing-mode:vertical-rl; }
|
||||
|
||||
div {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
border: 1px solid red;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
<u>方ABC方方</u><i><u>abc</u></i><u>方方方</u><b><u>xyz</u></b><u>方</u>
|
||||
</div>
|
||||
|
||||
<div class="v-lr">
|
||||
<u>方ABC方方</u><i><u>abc</u></i><u>方方方</u><b><u>xyz</u></b><u>方</u>
|
||||
</div>
|
||||
|
||||
<div class="v-rl">
|
||||
<u>方ABC方方</u><i><u>abc</u></i><u>方方方</u><b><u>xyz</u></b><u>方</u>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.h { writing-mode:horizontal-tb; }
|
||||
.v-lr { writing-mode:vertical-lr; }
|
||||
.v-rl { writing-mode:vertical-rl; }
|
||||
|
||||
div {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
border: 1px solid red;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
<u>方ABC方方<i>abc</i>方方方<b>xyz</b>方</u>
|
||||
</div>
|
||||
|
||||
<div class="v-lr">
|
||||
<u>方ABC方方<i>abc</i>方方方<b>xyz</b>方</u>
|
||||
</div>
|
||||
|
||||
<div class="v-rl">
|
||||
<u>方ABC方方<i>abc</i>方方方<b>xyz</b>方</u>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче