mirror of
https://github.com/servo/servo.git
synced 2025-06-28 11:03:39 +01:00
195 lines
11 KiB
HTML
195 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Testing @font-face font matching logic introduced in CSS Fonts level 4</title>
|
|
<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-matching-algorithm" />
|
|
<meta name="timeout" content="long">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<style>
|
|
.test
|
|
{
|
|
float:left;
|
|
border:1px solid red;
|
|
font-size:24pt;
|
|
white-space: nowrap;
|
|
clear:both;
|
|
}
|
|
|
|
@font-face { font-family: W100; src: url('./resources/csstest-weights-100-kerned.ttf'); }
|
|
@font-face { font-family: W200; src: url('./resources/csstest-weights-200-kerned.ttf'); }
|
|
@font-face { font-family: W300; src: url('./resources/csstest-weights-300-kerned.ttf'); }
|
|
|
|
|
|
@font-face { font-family: descriptorPriorityTest; src: url('./resources/csstest-weights-100-kerned.ttf'); font-stretch : 125%; }
|
|
@font-face { font-family: descriptorPriorityTest; src: url('./resources/csstest-weights-200-kerned.ttf'); font-style: italic; }
|
|
@font-face { font-family: descriptorPriorityTest; src: url('./resources/csstest-weights-300-kerned.ttf'); font-weight: 350; }
|
|
</style>
|
|
<style id="dynamicStyles">
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<span style="position: absolute; top: -100vh;">
|
|
<span style="font-family: 'W100';">A</span>
|
|
<span style="font-family: 'W200';">A</span>
|
|
<span style="font-family: 'W300';">A</span>
|
|
<span style="font-family: 'descriptorPriorityTest'; font-stretch: 125%;">A</span>
|
|
<span style="font-family: 'descriptorPriorityTest'; font-style: italic;">A</span>
|
|
<span style="font-family: 'descriptorPriorityTest'; font-weight: 350;">A</span>
|
|
</span>
|
|
|
|
<div id="master" class="test">A1 A2 A2 A3 A3 A3</div>
|
|
<div id="test" class="test">A1 A2 A2 A3 A3 A3</div>
|
|
<div style="clear:both"></div>
|
|
<script>
|
|
|
|
// wait for the fonts to load
|
|
// -- this should not be necessary if the fonts are installed as required
|
|
// -- but if they are not, the test is otherwise unstable
|
|
var once_fonts_are_ready = (document.fonts ? document.fonts.ready : new Promise(function(ready) { window.onload = time => [...document.querySelectorAll('body > span:nth-child(1) > span')].every(e => e.offsetWidth > 20) ? ready() : requestAnimationFrame(window.onload) }));
|
|
|
|
var masterElement = document.getElementById("master");
|
|
var testElement = document.getElementById("test");
|
|
var dynamicStyles = document.getElementById("dynamicStyles");
|
|
|
|
function verifyFont(testFamily, testWeight, testStyle, testStretch, expectedFamily) {
|
|
|
|
testElement.style.fontWeight = "normal";
|
|
testElement.style.fontStyle = "normal";
|
|
testElement.style.fontStretch = "normal";
|
|
|
|
masterElement.style.fontFamily = expectedFamily;
|
|
let masterWidth = masterElement.offsetWidth;
|
|
|
|
testElement.style.fontFamily = expectedFamily;
|
|
assert_equals(masterWidth, testElement.offsetWidth, "Sanity test: same family name gets same width" + dynamicStyles.innerHTML);
|
|
|
|
testElement.style.fontFamily = "serif";
|
|
assert_not_equals(masterWidth, testElement.offsetWidth, "Sanity test: different family get different width");
|
|
|
|
testElement.style.fontWeight = testWeight;
|
|
testElement.style.fontStyle = testStyle;
|
|
testElement.style.fontStretch = testStretch;
|
|
testElement.style.fontFamily = testFamily;
|
|
|
|
assert_equals(masterWidth, testElement.offsetWidth, "Unexpected font on test element");
|
|
}
|
|
|
|
var descriptorPriorityCases = [
|
|
{ weight: "normal", style: "oblique -5deg", stretch: "125%", expectedFamily: "'W100'", description: "Stretch has higher priority than style"},
|
|
{ weight: "350", style: "normal", stretch: "125%", expectedFamily: "'W100'", description: "Stretch has higher priority than weight"},
|
|
{ weight: "350", style: "oblique -5deg", stretch: "normal", expectedFamily: "'W200'", description: "Style has higher priority than weight"}
|
|
];
|
|
|
|
descriptorPriorityCases.forEach(function (testCase) {
|
|
promise_test(() => {
|
|
return once_fonts_are_ready
|
|
.then(() => verifyFont("descriptorPriorityTest", testCase.weight, testCase.style, testCase.stretch, testCase.expectedFamily));
|
|
},
|
|
"Descriptor matching priority: " + testCase.description
|
|
);
|
|
});
|
|
|
|
function load(family, name, value) {
|
|
const el1 = document.createElement("span");
|
|
const el2 = document.createElement("span");
|
|
el1.innerText = "A";
|
|
el2.innerText = "A";
|
|
let value1, value2;
|
|
if (value.indexOf("deg") > 0) {
|
|
value1 = "oblique " + value.split(" ")[1];
|
|
value2 = "oblique " + (value.split(" ")[2] || value.split(" ")[1]);
|
|
} else {
|
|
value1 = value.split(" ")[0];
|
|
value2 = value.split(" ")[1] || value1;
|
|
}
|
|
el1.style[name] = value1;
|
|
el2.style[name] = value2;
|
|
document.body.appendChild(el1);
|
|
document.body.appendChild(el2);
|
|
const initialWidth1 = el1.offsetWidth;
|
|
const initialWidth2 = el2.offsetWidth;
|
|
return new Promise((resolve) => {
|
|
el1.style.fontFamily = family;
|
|
el2.style.fontFamily = family;
|
|
(function check() {
|
|
if (el1.offsetWidth !== initialWidth1 && el2.offsetWidth !== initialWidth2) {
|
|
el1.remove();
|
|
el2.remove();
|
|
resolve();
|
|
} else {
|
|
requestAnimationFrame(check);
|
|
}
|
|
}());
|
|
});
|
|
}
|
|
function createFontFaceRules(fontFaceFamily, descriptorName, expectedMatch, unexpectedMatch) {
|
|
dynamicStyles.innerHTML =
|
|
"@font-face { font-family: " + fontFaceFamily + "; src: url('./resources/csstest-weights-100-kerned.ttf'); "+ descriptorName + ": " + expectedMatch + "; }" +
|
|
"@font-face { font-family: " + fontFaceFamily + "; src: url('./resources/csstest-weights-200-kerned.ttf'); " + descriptorName + ": " + unexpectedMatch + "; }";
|
|
|
|
return Promise.all([
|
|
load(fontFaceFamily, descriptorName, expectedMatch),
|
|
load(fontFaceFamily, descriptorName, unexpectedMatch)
|
|
]);
|
|
}
|
|
|
|
let familyId = 0;
|
|
|
|
function testDescriptor(descriptorName, testCases) {
|
|
testCases.forEach(function (testCase) {
|
|
// Go though test cases, checking each descriptor has higher priority than next in the list
|
|
for(let i = 0; i < testCase.testDescriptors.length - 1; i++) {
|
|
let expectedMatch = testCase.testDescriptors[i];
|
|
let unexpectedMatch = testCase.testDescriptors[i + 1];
|
|
familyId += 1;
|
|
const family = "MatchTestFamily" + familyId;
|
|
|
|
promise_test(
|
|
() => {
|
|
return createFontFaceRules(family, descriptorName, expectedMatch, unexpectedMatch)
|
|
.then(() => {
|
|
let testWeight = (descriptorName == "font-weight") ? testCase.value : "normal";
|
|
let testStyle = (descriptorName == "font-style") ? testCase.value : "normal";
|
|
let testStretch = (descriptorName == "font-stretch") ? testCase.value : "normal";
|
|
|
|
verifyFont(family, testWeight, testStyle, testStretch, "'W100'");
|
|
});
|
|
},
|
|
"Matching " + descriptorName + ": '" + testCase.value + "' should prefer '" + expectedMatch + "' over '" + unexpectedMatch + "'");
|
|
}
|
|
});
|
|
}
|
|
|
|
// Each case defines property value being tested and set of descriptor values in order of matching priority from highest to lowest
|
|
|
|
testDescriptor("font-weight", [
|
|
{ value: "400", testDescriptors: ["400", "450 460", "500", "350 399", "351 398", "501 550", "502 560"] },
|
|
{ value: "430", testDescriptors: ["420 440", "450 460", "500", "400 425", "350 399", "340 398", "501 550", "502 560"] },
|
|
{ value: "500", testDescriptors: ["500", "450 460", "400", "350 399", "351 398", "501 550", "502 560"] },
|
|
{ value: "501", testDescriptors: ["501", "502 510", "503 520", "500", "450 460", "390 410", "300 350"] },
|
|
{ value: "399", testDescriptors: ["350 399", "340 360", "200 300", "400", "450 460", "500 501", "502 510"] }
|
|
]);
|
|
|
|
testDescriptor("font-stretch", [
|
|
{ value: "100%", testDescriptors: ["100%", "110% 120%", "115% 116%"] },
|
|
{ value: "110%", testDescriptors: ["110% 120%", "115% 116%", "105%", "100%", "50% 80%", "60% 70%"] },
|
|
{ value: "90%", testDescriptors: ["90% 100%", "50% 80%", "60% 70%", "110% 140%", "120% 130%"] },
|
|
]);
|
|
|
|
testDescriptor("font-style", [
|
|
{ value: "normal", testDescriptors: ["normal", "oblique 0deg", "oblique 10deg 40deg", "oblique 20deg 30deg", "oblique -50deg -20deg", "oblique -40deg -30deg" ] },
|
|
{ value: "italic", testDescriptors: ["italic", "oblique 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 5deg 10deg", "oblique 5deg", "normal", "oblique 0deg", "oblique -60deg -30deg", "oblique -50deg -40deg" ] },
|
|
{ value: "oblique 20deg", testDescriptors: ["oblique 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 10deg", "italic", "oblique 0deg", "oblique -50deg -20deg", "oblique -40deg -30deg" ] },
|
|
{ value: "oblique 21deg", testDescriptors: ["oblique 21deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 20deg", "oblique 10deg", "italic", "oblique 0deg", "oblique -50deg -20deg", "oblique -40deg -30deg" ] },
|
|
{ value: "oblique 10deg", testDescriptors: ["oblique 10deg", "oblique 5deg", "oblique 15deg 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "italic", "oblique 0deg", "oblique -50deg -20deg", "oblique -40deg -30deg" ] },
|
|
{ value: "oblique 0deg", testDescriptors: ["oblique 0deg", "oblique 5deg", "oblique 15deg 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "italic", "oblique -50deg -20deg", "oblique -40deg -30deg" ] },
|
|
{ value: "oblique -10deg", testDescriptors: ["oblique -10deg", "oblique -5deg", "oblique -1deg 0deg", "oblique -20deg -15deg", "oblique -60deg -30deg", "oblique -50deg -40deg", "italic", "oblique 0deg 10deg", "oblique 40deg 50deg" ] },
|
|
{ value: "oblique -20deg", testDescriptors: ["oblique -20deg", "oblique -60deg -40deg", "oblique -10deg", "italic", "oblique 0deg", "oblique 30deg 60deg", "oblique 40deg 50deg"] },
|
|
{ value: "oblique -21deg", testDescriptors: ["oblique -21deg", "oblique -60deg -40deg", "oblique -10deg", "italic", "oblique 0deg", "oblique 30deg 60deg", "oblique 40deg 50deg"] },
|
|
]);
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|