tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

at-font-face-font-matching.html (11592B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4    <title>Testing @font-face font matching logic introduced in CSS Fonts level 4</title>
      5    <link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-matching-algorithm" />
      6    <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9389#issuecomment-2625314278">
      7    <meta name="timeout" content="long">
      8    <script src="/resources/testharness.js"></script>
      9    <script src="/resources/testharnessreport.js"></script>
     10    <style>
     11        .test
     12        {
     13            float:left;
     14            border:1px solid red;
     15            font-size:24pt;
     16            white-space: nowrap;
     17            clear:both;
     18        }
     19 
     20        @font-face { font-family: W100; src: url('./resources/csstest-weights-100-kerned.ttf'); }
     21        @font-face { font-family: W200; src: url('./resources/csstest-weights-200-kerned.ttf'); }
     22        @font-face { font-family: W300; src: url('./resources/csstest-weights-300-kerned.ttf'); }
     23 
     24 
     25        @font-face { font-family: descriptorPriorityTest; src: url('./resources/csstest-weights-100-kerned.ttf'); font-stretch: 125%; }
     26        @font-face { font-family: descriptorPriorityTest; src: url('./resources/csstest-weights-200-kerned.ttf'); font-style: italic; }
     27        @font-face { font-family: descriptorPriorityTest; src: url('./resources/csstest-weights-300-kerned.ttf'); font-weight: 350; }
     28    </style>
     29    <style id="dynamicStyles">
     30    </style>
     31 </head>
     32 <body>
     33 
     34    <span style="position: absolute; top: -100vh;">
     35        <span style="font-family: 'W100';">A</span>
     36        <span style="font-family: 'W200';">A</span>
     37        <span style="font-family: 'W300';">A</span>
     38        <span style="font-family: 'descriptorPriorityTest'; font-stretch: 125%;">A</span>
     39        <span style="font-family: 'descriptorPriorityTest'; font-style: italic;">A</span>
     40        <span style="font-family: 'descriptorPriorityTest'; font-weight: 350;">A</span>
     41    </span>
     42 
     43    <div id="master" class="test">A1 A2 A2 A3 A3 A3</div>
     44    <div id="test" class="test">A1 A2 A2 A3 A3 A3</div>
     45    <div style="clear:both"></div>
     46    <script>
     47 
     48        // wait for the fonts to load
     49        // -- this should not be necessary if the fonts are installed as required
     50        // -- but if they are not, the test is otherwise unstable
     51        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) }));
     52 
     53        var masterElement = document.getElementById("master");
     54        var testElement = document.getElementById("test");
     55        var dynamicStyles = document.getElementById("dynamicStyles");
     56 
     57        function verifyFont(testFamily, testWeight, testStyle, testStretch, expectedFamily) {
     58 
     59            testElement.style.fontWeight  = "normal";
     60            testElement.style.fontStyle   = "normal";
     61            testElement.style.fontStretch = "normal";
     62 
     63            masterElement.style.fontFamily = expectedFamily;
     64            let masterWidth = masterElement.offsetWidth;
     65 
     66            testElement.style.fontFamily = expectedFamily;
     67            assert_equals(masterWidth, testElement.offsetWidth, "Sanity test: same family name gets same width" + dynamicStyles.innerHTML);
     68 
     69            testElement.style.fontFamily = "serif";
     70            assert_not_equals(masterWidth, testElement.offsetWidth, "Sanity test: different family get different width");
     71 
     72            testElement.style.fontWeight = testWeight;
     73            testElement.style.fontStyle  = testStyle;
     74            testElement.style.fontStretch = testStretch;
     75            testElement.style.fontFamily = testFamily;
     76 
     77            assert_equals(masterWidth, testElement.offsetWidth, "Unexpected font on test element");
     78        }
     79 
     80        var descriptorPriorityCases = [
     81            { weight: "normal", style: "italic", stretch: "125%",   expectedFamily: "'W100'", description: "Stretch has higher priority than style"},
     82            { weight: "350",    style: "normal", stretch: "125%",   expectedFamily: "'W100'", description: "Stretch has higher priority than weight"},
     83            { weight: "350",    style: "italic", stretch: "normal", expectedFamily: "'W200'", description: "Style has higher priority than weight"}
     84        ];
     85 
     86        descriptorPriorityCases.forEach(function (testCase) {
     87            promise_test(() => {
     88                return once_fonts_are_ready
     89                    .then(() => verifyFont("descriptorPriorityTest", testCase.weight, testCase.style, testCase.stretch, testCase.expectedFamily));
     90                },
     91                "Descriptor matching priority: " + testCase.description
     92            );
     93        });
     94 
     95        function load(family, name, value) {
     96            const el1 = document.createElement("span");
     97            const el2 = document.createElement("span");
     98            el1.innerText = "A";
     99            el2.innerText = "A";
    100            let value1, value2;
    101            if (value.indexOf("deg") > 0) {
    102                value1 = "oblique " + value.split(" ")[1];
    103                value2 = "oblique " + (value.split(" ")[2] || value.split(" ")[1]);
    104            } else {
    105                value1 = value.split(" ")[0];
    106                value2 = value.split(" ")[1] || value1;
    107            }
    108            el1.style[name] = value1;
    109            el2.style[name] = value2;
    110            document.body.appendChild(el1);
    111            document.body.appendChild(el2);
    112            const initialWidth1 = el1.offsetWidth;
    113            const initialWidth2 = el2.offsetWidth;
    114            return new Promise((resolve) => {
    115                el1.style.fontFamily = family;
    116                el2.style.fontFamily = family;
    117                (function check() {
    118                    if (el1.offsetWidth !== initialWidth1 && el2.offsetWidth !== initialWidth2) {
    119                        el1.remove();
    120                        el2.remove();
    121                        resolve();
    122                    } else {
    123                        requestAnimationFrame(check);
    124                    }
    125                }());
    126            });
    127        }
    128        function createFontFaceRules(fontFaceFamily, descriptorName, expectedMatch, unexpectedMatch) {
    129            dynamicStyles.innerHTML =
    130                "@font-face { font-family: " + fontFaceFamily + "; src: url('./resources/csstest-weights-100-kerned.ttf'); " + descriptorName + ": " + expectedMatch   + "; }" +
    131                "@font-face { font-family: " + fontFaceFamily + "; src: url('./resources/csstest-weights-200-kerned.ttf'); " + descriptorName + ": " + unexpectedMatch + "; }";
    132 
    133            return Promise.all([
    134                load(fontFaceFamily, descriptorName, expectedMatch),
    135                load(fontFaceFamily, descriptorName, unexpectedMatch)
    136            ]);
    137        }
    138 
    139        let familyId = 0;
    140 
    141        function testDescriptor(descriptorName, testCases) {
    142            testCases.forEach(function (testCase) {
    143                    // Go though test cases, checking each descriptor has higher priority than next in the list
    144                    for(let i = 0; i < testCase.testDescriptors.length - 1; i++) {
    145                        let expectedMatch   = testCase.testDescriptors[i];
    146                        let unexpectedMatch = testCase.testDescriptors[i + 1];
    147                        familyId += 1;
    148                        const family = "MatchTestFamily" + familyId;
    149 
    150                        promise_test(
    151                            () => {
    152                                return createFontFaceRules(family, descriptorName, expectedMatch, unexpectedMatch)
    153                                    .then(() => {
    154                                        let testWeight  = (descriptorName == "font-weight")  ? testCase.value : "normal";
    155                                        let testStyle   = (descriptorName == "font-style")   ? testCase.value : "normal";
    156                                        let testStretch = (descriptorName == "font-stretch") ? testCase.value : "normal";
    157 
    158                                        verifyFont(family, testWeight, testStyle, testStretch, "'W100'");
    159                                    });
    160                            },
    161                            "Matching " + descriptorName + ": '" + testCase.value + "' should prefer '" + expectedMatch + "' over '" + unexpectedMatch + "'");
    162                    }
    163            });
    164        }
    165 
    166        // Each case defines property value being tested and set of descriptor values in order of matching priority from highest to lowest
    167 
    168        testDescriptor("font-weight", [
    169            { value: "400", testDescriptors: ["400", "450 460", "500", "350 399", "351 398", "501 550", "502 560"] },
    170            { value: "430", testDescriptors: ["420 440", "450 460", "500", "400 425", "350 399", "340 398", "501 550", "502 560"] },
    171            { value: "500", testDescriptors: ["500", "450 460", "400", "350 399", "351 398", "501 550", "502 560"] },
    172            { value: "501", testDescriptors: ["501", "502 510", "503 520", "500", "450 460", "390 410", "300 350"] },
    173            { value: "399", testDescriptors: ["350 399", "340 360", "200 300", "400", "450 460", "500 501", "502 510"] }
    174        ]);
    175 
    176        testDescriptor("font-stretch", [
    177            { value: "100%", testDescriptors: ["100%", "110% 120%", "115% 116%"] },
    178            { value: "110%", testDescriptors: ["110% 120%", "115% 116%", "105%", "100%", "50% 80%", "60% 70%"] },
    179            { value: "90%",  testDescriptors: ["90% 100%", "50% 80%", "60% 70%", "110% 140%", "120% 130%"] },
    180        ]);
    181 
    182        testDescriptor("font-style", [
    183            { value: "normal",         testDescriptors: ["normal", "oblique 10deg 40deg", "oblique 20deg 30deg", "oblique -50deg -20deg", "oblique -40deg -30deg" ] },
    184            { value: "italic",         testDescriptors: ["italic", "oblique 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 5deg 10deg", "oblique 5deg", "normal", "oblique -60deg -30deg", "oblique -50deg -40deg" ] },
    185            { value: "oblique 20deg",  testDescriptors: ["oblique 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 10deg", "oblique 0deg", "oblique -50deg -20deg", "oblique -40deg -30deg", "italic" ] },
    186            { value: "oblique 21deg",  testDescriptors: ["oblique 21deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 20deg", "oblique 10deg", "oblique 0deg",  "oblique -50deg -20deg", "oblique -40deg -30deg", "italic" ] },
    187            { value: "oblique 10deg",  testDescriptors: ["oblique 10deg", "oblique 5deg", "oblique 15deg 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique 0deg", "oblique -50deg -20deg", "oblique -40deg -30deg", "italic" ] },
    188            { value: "oblique 0deg",   testDescriptors: ["oblique 0deg", "oblique 5deg", "oblique 15deg 20deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "oblique -50deg -20deg", "oblique -40deg -30deg", "italic" ] },
    189            { value: "oblique -10deg", testDescriptors: ["oblique -10deg", "oblique -5deg", "oblique -1deg 0deg", "oblique -20deg -15deg", "oblique -60deg -30deg", "oblique -50deg -40deg", "oblique 0deg 10deg", "oblique 40deg 50deg", "italic" ] },
    190            { value: "oblique -20deg", testDescriptors: ["oblique -20deg", "oblique -60deg -40deg", "oblique -10deg", "oblique 0deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "italic"] },
    191            { value: "oblique -21deg", testDescriptors: ["oblique -21deg", "oblique -60deg -40deg", "oblique -10deg", "oblique 0deg", "oblique 30deg 60deg", "oblique 40deg 50deg", "italic"] },
    192        ]);
    193 
    194    </script>
    195 </body>
    196 </html>