143 lines
5.7 KiB
HTML
143 lines
5.7 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Test that system font sizing is independent from ui.textScaleFactor</title>
|
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
|
<style>
|
|
p { width: max-content }
|
|
#menu { font: menu }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<p id="menu">"menu" text.</p>
|
|
<p id="default">Default text.</p>
|
|
</body>
|
|
<script>
|
|
"use strict";
|
|
|
|
const { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
|
|
"resource://gre/modules/AppConstants.sys.mjs"
|
|
);
|
|
|
|
// Returns a Number for the font size in CSS pixels.
|
|
function elementFontSize(element) {
|
|
return parseFloat(getComputedStyle(element).getPropertyValue("font-size"));
|
|
}
|
|
|
|
// "look-and-feel-changed" may be dispatched twice: once for the pref
|
|
// change and once after receiving the new values from
|
|
// ContentChild::RecvThemeChanged().
|
|
// pushPrefEnv() resolves after the former. This resolves after the latter.
|
|
function promiseNewFontSizeOnThemeChange(element) {
|
|
return new Promise(resolve => {
|
|
const lastSize = elementFontSize(element);
|
|
|
|
function ThemeChanged() {
|
|
const size = elementFontSize(element);
|
|
if (size != lastSize) {
|
|
resolve(size);
|
|
}
|
|
}
|
|
// "look-and-feel-changed" is dispatched before the style system is flushed,
|
|
// https://searchfox.org/mozilla-central/rev/380fc5571b039fd453b45bbb64ed13146fe9b066/layout/base/nsPresContext.cpp#1684,1703-1705
|
|
// so use an async observer to get a notification after style changes.
|
|
SpecialPowers.addAsyncObserver(ThemeChanged, "look-and-feel-changed");
|
|
SimpleTest.registerCleanupFunction(function() {
|
|
SpecialPowers.removeAsyncObserver(ThemeChanged, "look-and-feel-changed");
|
|
});
|
|
});
|
|
}
|
|
|
|
function fuzzyCompareLength(actual, expected, message, tolerance, expectFn) {
|
|
expectFn(Math.abs(actual-expected) <= tolerance,
|
|
`${message} - got ${actual}, expected ${expected} +/- ${tolerance}`);
|
|
}
|
|
|
|
add_task(async () => {
|
|
// MOZ_HEADLESS is set in content processes with GTK regardless of the
|
|
// headless state of the parent process. Check the parent state.
|
|
const headless = await SpecialPowers.spawnChrome([], function get_headless() {
|
|
return Services.env.get("MOZ_HEADLESS");
|
|
});
|
|
// LookAndFeel::TextScaleFactor::FloatID is implemented only for WINNT and
|
|
// GTK. ui.textScaleFactor happens to scale CSS pixels on other platforms
|
|
// but system font integration has not been implemented.
|
|
const expectSuccess = AppConstants.MOZ_WIDGET_TOOLKIT == "windows" ||
|
|
(AppConstants.MOZ_WIDGET_TOOLKIT == "gtk" &&
|
|
// Headless GTK doesn't get system font sizes from the system, but
|
|
// uses sizes fixed in CSS pixels.
|
|
!headless);
|
|
|
|
async function setScaleAndPromiseFontSize(scale, element) {
|
|
const prefPromise = SpecialPowers.pushPrefEnv({
|
|
set: [["ui.textScaleFactor", scale]],
|
|
});
|
|
if (!expectSuccess) {
|
|
// The size is not expected to change but get it afresh to check our
|
|
// assumption.
|
|
await prefPromise;
|
|
return elementFontSize(element);
|
|
}
|
|
const [size] = await Promise.all([
|
|
promiseNewFontSizeOnThemeChange(element),
|
|
prefPromise,
|
|
]);
|
|
return size;
|
|
}
|
|
|
|
const menu = document.getElementById("menu");
|
|
const def = document.getElementById("default");
|
|
// Choose a scaleFactor value different enough from possible default values
|
|
// that app unit rounding does not prevent a change in devicePixelRatio.
|
|
// A scaleFactor of 120 also has no rounding of app units per dev pixel.
|
|
const referenceScale = 120;
|
|
const menuSize1 = await setScaleAndPromiseFontSize(referenceScale, menu);
|
|
const menuRect1 = menu.getBoundingClientRect();
|
|
const defSize1 = elementFontSize(def);
|
|
const defRect1 = def.getBoundingClientRect();
|
|
|
|
const expectFn = expectSuccess ? ok : todo;
|
|
const menuSize2 = await setScaleAndPromiseFontSize(2*referenceScale, menu);
|
|
{
|
|
const singlePrecisionULP = Math.pow(2, -23);
|
|
// Precision seems to be lost in the conversion to decimal string for the
|
|
// property value.
|
|
const reltolerance = 30 * singlePrecisionULP;
|
|
fuzzyCompareLength(menuSize2, menuSize1/2, "size of menu font",
|
|
reltolerance*menuSize1/2, expectFn);
|
|
}
|
|
{
|
|
const menuRect2 = menu.getBoundingClientRect();
|
|
// The menu font text renders exactly the same and app-unit rects are
|
|
// equal, but the DOMRect conversion is rounded to 1/65536 CSS pixels.
|
|
// https://searchfox.org/mozilla-central/rev/380fc5571b039fd453b45bbb64ed13146fe9b066/dom/base/DOMRect.cpp#151-159
|
|
// See also https://bugzilla.mozilla.org/show_bug.cgi?id=1640441#c28
|
|
//
|
|
// Increased tolerance in https://bugzilla.mozilla.org/show_bug.cgi?id=1920733
|
|
// as the change to rendering mode seems to have perturbed results a bit, though
|
|
// it's still "basically the same".
|
|
const absTolerance = 0.05;
|
|
fuzzyCompareLength(menuRect2.width, menuRect1.width/2,
|
|
"width of menu font <p> in px", absTolerance, expectFn);
|
|
fuzzyCompareLength(menuRect2.height, menuRect1.height/2,
|
|
"height of menu font <p> in px", absTolerance, expectFn);
|
|
}
|
|
|
|
const defSize2 = elementFontSize(def);
|
|
is(defSize2, defSize1, "size of default font");
|
|
{
|
|
const defRect2 = def.getBoundingClientRect();
|
|
// Wider tolerance for hinting and snapping
|
|
const relTolerance = 1/12;
|
|
fuzzyCompareLength(defRect2.width, defRect1.width,
|
|
"width of default font <p> in px",
|
|
relTolerance*defRect1.width, ok);
|
|
fuzzyCompareLength(defRect2.height, defRect1.height,
|
|
"height of default font <p> in px",
|
|
relTolerance*defRect1.height, ok);
|
|
}
|
|
});
|
|
</script>
|
|
</html>
|