Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2014-11-13 16:27:00 +01:00
commit dc7a4ff8a2
120 changed files with 2236 additions and 1320 deletions

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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 -->

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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 -->

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "2e0f2f070a2265b537e6a2ff4e0f2e1f2aca49c6",
"revision": "c1bed74af46cb81a7092d6e80624134bae5d1bf0",
"repo_path": "integration/gaia-central"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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 -->

View File

@ -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"/>

View File

@ -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
},
/**

View File

@ -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),

View File

@ -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
},
/**

View File

@ -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),

View File

@ -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():

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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()
{

View File

@ -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();

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
};

View File

@ -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)

View File

@ -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));
}
}

View File

@ -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();
});

View File

@ -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]

View File

@ -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");

View File

@ -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;
});

View File

@ -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>

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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;"

View File

@ -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++) {

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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");

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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)) {

View File

@ -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

View File

@ -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);

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

Some files were not shown because too many files have changed in this diff Show More