at-font-face-descriptors.html (13918B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Testing @font-face descriptor values introduced in CSS Fonts level 4</title> 5 <link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-face-rule" /> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <style id="testStyle"> 9 @font-face { font-family: Test; src: local('Courier New'), local('Courier'); } 10 </style> 11 </head> 12 <body> 13 <div>@font-face descriptor tests</div> 14 <script> 15 16 function updateFontFaceRule(descriptorName, descriptorValue) { 17 let testRule = document.getElementById("testStyle").sheet.cssRules[0]; 18 19 testRule.style.fontWeight = "normal"; 20 testRule.style.fontStyle = "normal"; 21 testRule.style.fontStretch = "normal"; 22 assert_equals(testRule.style.fontWeight, "normal", "Can't clear @font-face."); 23 assert_equals(testRule.style.fontStyle, "normal", "Can't clear @font-face."); 24 assert_equals(testRule.style.fontStretch, "normal", "Can't clear @font-face."); 25 26 testRule.style.fontWeight = ""; 27 testRule.style.fontStyle = ""; 28 testRule.style.fontStretch = ""; 29 assert_true(!testRule.style.fontWeight, "", "Can't clear @font-face."); 30 assert_true(!testRule.style.fontStyle, "", "Can't clear @font-face."); 31 assert_true(!testRule.style.fontStretch, "", "Can't clear @font-face."); 32 33 testRule.style[descriptorName] = descriptorValue; 34 35 return testRule; 36 } 37 38 function testDescriptor(descriptorName, testCases) { 39 var propertyName = { 'font-weight':'fontWeight', 'font-stretch':'fontStretch', 'font-style':'fontStyle' }[descriptorName]; 40 testCases.forEach(function (testCase) { 41 test(() => { 42 let rule = updateFontFaceRule(descriptorName, testCase.value); 43 44 if (testCase.isValid) { 45 assert_not_equals(rule.style[propertyName], "", "Valid value should be accepted."); 46 47 let expectedValue = (testCase.expectedValue) ? testCase.expectedValue : testCase.value; 48 assert_equals(rule.style[propertyName], expectedValue, "Unexpected resulting value."); 49 } 50 else { 51 assert_equals(rule.style[propertyName], "", "No properties should be set."); 52 } 53 }, descriptorName + (testCase.isValid ? "(valid): " : "(invalid): ") + testCase.description + ": " + testCase.value); 54 55 }); 56 } 57 58 testDescriptor("font-weight", [ 59 // Single value, keyword 60 { value: "normal", isValid: true, description: "'normal' keyword" }, 61 { value: "bold", isValid: true, description: "'bold' keyword" }, 62 { value: "auto", isValid: true, description: "'auto' keyword inside @font-face" }, 63 { value: "lighter", isValid: false, description: "'lighter' keyword inside @font-face" }, 64 { value: "bolder", isValid: false, description: "'bolder' keyword inside @font-face" }, 65 { value: "bold a", isValid: false, description: "Extra content after keyword" }, 66 67 // Single value, number 68 { value: "401", isValid: true, description: "Values that are not multiple of 100 should be parsed successfully" }, 69 { value: "400.1", isValid: true, description: "Non-integer values should be parsed successfully" }, 70 { value: "1", isValid: true, description: "Minimum allowed value should be parsed successfully" }, 71 { value: "0.999", isValid: false, description: "Values below minimum should be rejected" }, 72 { value: "-100", isValid: false, description: "Values below zero should be rejected" }, 73 { value: "1000", isValid: true, description: "Maximum allowed value should be parsed successfully" }, 74 { value: "1000.001", isValid: false, description: "Values above maximum should be rejected" }, 75 { value: "100 a", isValid: false, description: "Extra content after value" }, 76 77 // Single value, calc 78 { value: "calc(100.5)", isValid: true, expectedValue: "calc(100.5)", description: "Simple calc value" }, 79 { value: "calc(1001)", isValid: true, description: "Out-of-range simple calc value" }, 80 { value: "calc(100.5*3 + 50.5)", isValid: true, expectedValue: "calc(352)", description: "Valid calc expression" }, 81 { value: "calc(100.5*3 + 800)", isValid: true, expectedValue: "calc(1101.5)", description: "Valid calc expression with out-of-range value" }, 82 { value: "calc(100.5px + 50.5px)", isValid: false, description: "Valid calc expression with units" }, 83 84 // Value range 85 { value: "100 900", isValid: true, description: "Simple range" }, 86 { value: "500 500", isValid: true, expectedValue: "500", description: "Simple range with equal upper and lower bounds" }, 87 { value: "0.9 100", isValid: false, description: "Lower bound out of range" }, 88 { value: "100 1001", isValid: false, description: "Upper bound out of range" }, 89 { value: "calc(100 + 100) 400", isValid: true, expectedValue: "calc(200) 400", description: "Lower bound calc()" }, 90 { value: "200 calc(200 + 200)", isValid: true, expectedValue: "200 calc(400)", description: "Upper bound calc()" }, 91 { value: "calc(100 + 100) calc(200 + 200)", isValid: true, expectedValue: "calc(200) calc(400)", description: "Both bounds are calc()" }, 92 { value: "400 200", isValid: true, expectedValue: "400 200", description: "Bounds out of order are valid" }, 93 { value: "100 200 300", isValid: false, description: "Extra content after upper bound" }, 94 ]); 95 96 testDescriptor("font-stretch", [ 97 // Single value, keyword 98 { value: "ultra-condensed", isValid: true, description: "'ultra-condensed' keyword" }, 99 { value: "extra-condensed", isValid: true, description: "'extra-condensed' keyword" }, 100 { value: "condensed", isValid: true, description: "'condensed' keyword" }, 101 { value: "semi-condensed", isValid: true, description: "'semi-condensed' keyword" }, 102 { value: "normal", isValid: true, description: "'normal' keyword" }, 103 { value: "semi-expanded", isValid: true, description: "'semi-expanded' keyword" }, 104 { value: "expanded", isValid: true, description: "'expanded' keyword" }, 105 { value: "extra-expanded", isValid: true, description: "'extra-expanded' keyword" }, 106 { value: "ultra-expanded", isValid: true, description: "'ultra-expanded' keyword" }, 107 { value: "expanded a", isValid: false, description: "Extra content after value" }, 108 { value: "auto", isValid: true, description: "'auto' keyword inside @font-face" }, 109 110 // Single value, number 111 { value: "1%", isValid: true, description:"Legal percentage" }, 112 { value: "10.5%", isValid: true, description:"Legal percentage" }, 113 { value: "100%", isValid: true, description:"Legal percentage" }, 114 { value: "1000%", isValid: true, description:"Legal percentage" }, 115 { value: "100", isValid: false, description:"Only percentages, not numbers allowed" }, 116 { value: "-1%", isValid: false, description:"Negative values are illegal" }, 117 { value: "0%", isValid: true, description:"Zero is legal" }, 118 { value: "100% a", isValid: false, description:"Extra content after value" }, 119 120 // Single value, calc 121 { value: "calc(200.5%)", isValid: true, expectedValue: "calc(200.5%)", description: "Simple calc value" }, 122 { value: "calc(50%*2 - 20%)", isValid: true, expectedValue: "calc(80%)", description: "Valid calc expression" }, 123 { value: "calc(-100%)", isValid: true, description: "Negative calc value (to be clamped)" }, 124 { value: "calc(50% - 50%*2)", isValid: true, expectedValue: "calc(-50%)", description: "Negative calc expression (to be clamped)" }, 125 { value: "calc(100)", isValid: false, description: "Unit-less calc value" }, 126 { value: "calc(100px)", isValid: false, description: "Calc value with units" }, 127 128 // Value range 129 { value: "100% 200%", isValid: true, description: "Simple range" }, 130 { value: "100% 100%", isValid: true, expectedValue: "100%", description: "Simple range with equal upper and lower bounds" }, 131 { value: "-100% 100%", isValid: false, description: "Lower bound out of range" }, 132 { value: "calc(10% + 10%) 30%", isValid: true, expectedValue: "calc(20%) 30%", description: "Lower bound calc()" }, 133 { value: "10% calc(10% + 10%)", isValid: true, expectedValue: "10% calc(20%)", description: "Upper bound calc()" }, 134 { value: "calc(10% + 10%) calc(20% + 20%)", isValid: true, expectedValue: "calc(20%) calc(40%)", description: "Both bounds are calc()" }, 135 { value: "200% 100%", isValid: true, expectedValue: "200% 100%", description: "Bounds out of order" }, 136 { value: "100% 200% 300%", isValid: false, description: "Extra content after upper bound" }, 137 ]); 138 139 testDescriptor("font-style", [ 140 // Single value, keyword 141 { value: "normal", isValid: true, description: "'normal' keyword" }, 142 { value: "italic", isValid: true, description: "'italic' keyword" }, 143 { value: "oblique", isValid: true, description: "'oblique' keyword" }, 144 { value: "auto", isValid: true, description: "'auto' keyword inside @font-face" }, 145 146 // Single value 147 { value: "italic 20deg", isValid: false, description: "'italic' followed by angle" }, 148 { value: "italic a", isValid: false, description: "Extra content after keyword" }, 149 { value: "oblique 0deg", isValid: true, expectedValue: "normal", description: "'oblique' followed by zero degrees" }, 150 { value: "oblique 20deg", isValid: true, description: "'oblique' followed by former default 20deg angle" }, 151 { value: "oblique 90deg", isValid: true, description: "'oblique' followed by maxumum 90 degree angle" }, 152 { value: "oblique -90deg", isValid: true, description: "'oblique' followed by minimum -90 degree angle" }, 153 { value: "oblique calc(91deg)", isValid: true, description: "'oblique' followed by calc with out of range value (should be clamped)" }, 154 { value: "oblique calc(-91deg)", isValid: true, description: "'oblique' followed by calc with out of range value (should be clamped)" }, 155 { value: "oblique 0rad", isValid: true, expectedValue: "normal", description: "'oblique' followed by angle in radians" }, 156 { value: "oblique 20", isValid: false, description: "'oblique' followed by unit-less number" }, 157 { value: "oblique 20px", isValid: false, description: "'oblique' followed by non-angle" }, 158 { value: "oblique a", isValid: false, description: "'oblique' followed by non-number" }, 159 { value: "oblique -", isValid: false, description: "'oblique' followed by isolated minus" }, 160 { value: "oblique - 20deg", isValid: false, description: "'oblique' followed by minus and angle separated by space" }, 161 { value: "oblique -a", isValid: false, description: "'oblique' followed by minus and non-number" }, 162 163 // Value range 164 { value: "oblique 10deg 20deg", isValid: true, description: "Simple range" }, 165 { value: "oblique 10deg 10deg", isValid: true, expectedValue: "oblique 10deg", description: "Simple range with equal upper and lower bounds" }, 166 { value: "oblique 0deg 0deg", isValid: true, expectedValue: "normal", description: "Simple range with equal upper and lower bounds" }, 167 { value: "oblique 20deg 20deg", isValid: true, description: "Simple range with former default angle for both bounds" }, 168 { value: "oblique 20deg 10deg", isValid: true, expectedValue: "oblique 20deg 10deg", description: "Bounds out of order" }, 169 { value: "oblique -100deg 20deg", isValid: false, description: "Lower bound out of range" }, 170 { value: "oblique 20deg 100deg", isValid: false, description: "Upper bound out of range" }, 171 { value: "oblique 10deg 20deg 30deg", isValid: false, description: "Extra content after upper bound" }, 172 ]); 173 </script> 174 </body> 175 </html>