dimension-attributes.html (7176B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>Test handling of attributes that map to dimension properties</title> 4 <meta name="timeout" content="long"> 5 <link rel="help" 6 href="https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property"> 7 <link rel="help" 8 href="https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property-(ignoring-zero)"> 9 <script src=/resources/testharness.js></script> 10 <script src=/resources/testharnessreport.js></script> 11 <body> 12 <!-- We need a place to put our elements so they're bound to a document and 13 have computed style, but we don't want percentages resolved to lengths, 14 so need to make sure they have no CSS boxes --> 15 <div id="container" style="display: none"></div> 16 <script> 17 /* 18 * This test tests 19 * 20 * https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property 21 * and 22 * https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property-(ignoring-zero) 23 * for various elements and various values. 24 */ 25 26 /* 27 * Array of input/output pairs. The input is the string to use as the 28 * attribute value. The output is the string expected as the computed style 29 * for the relevant CSS property. 30 */ 31 const valid_values = [ 32 // Valid values 33 [ "200", "200px" ], 34 [ "1007", "1007px" ], 35 [ " 00523 ", "523px" ], 36 [ "200.25", "200.25px" ], 37 [ "200.7", "200.7px" ], 38 [ "200.", "200px" ], 39 [ "200in", "200px" ], 40 [ "200.25in", "200.25px" ], 41 [ "200 %", "200px" ], 42 [ "200 abc", "200px" ], 43 [ "200%", "200%" ], 44 [ "200%abc", "200%" ], 45 [ "200.25%", "200.25%" ], 46 [ "200.%", "200%" ], 47 [ "20.25e2", "20.25px" ], 48 [ "20.25E2", "20.25px" ], 49 ]; 50 51 /* 52 * Values that are only valid for the not-ignoring-zero case. 53 */ 54 const zero_values = [ 55 [ "0", "0px" ], 56 [ "0%", "0%" ], 57 [ "0px", "0px" ], 58 ]; 59 60 /* 61 * Array of invalid values. These should lead to the default value of the 62 * relevant CSS property. 63 */ 64 const invalid_values = [ 65 "-0", 66 "-0%", 67 "-200", 68 "-200px", 69 " -200", 70 "+-200", 71 "-+200", 72 "-200%", 73 "+200", 74 " +200in ", 75 " +200.25in ", 76 "+200%", 77 " +200.25% ", 78 " +200.25%abc", 79 "+0", 80 "+0%", 81 ".", 82 ".%", 83 ".x", 84 ".5", 85 ".5%" 86 ]; 87 88 const valid_values_with_0 = 89 valid_values.concat(zero_values); 90 const invalid_values_with_0 = 91 invalid_values.concat(zero_values.map((v) => v[0])); 92 93 function newElem(name) { 94 return () => document.createElement(name); 95 } 96 97 function newImageInput() { 98 return () => { 99 var elem = newElem("input")(); 100 elem.type = "image"; 101 return elem; 102 } 103 } 104 105 function newImgSource() { 106 return () => { 107 var elem = newElem("source")(); 108 elem.setAttribute("srcset", "/images/green-100x50.png"); 109 return elem; 110 } 111 } 112 113 /* 114 * Array of tests. Each test consists of the following information: 115 * 116 * 1) An element creation function. 117 * 2) The name of the attribute to set 118 * 3) The name of the CSS property to get. 119 * 4) A boolean indicating whether 0 is a valid value for the dimension 120 * attribute. 121 */ 122 const tests = [ 123 [ newElem("hr"), "width", "width", true ], 124 [ newElem("iframe"), "width", "width", true ], 125 [ newElem("iframe"), "height", "height", true ], 126 [ newImageInput(), "width", "width", true ], 127 [ newImageInput(), "height", "height", true ], 128 [ newElem("marquee"), "width", "width", true ], 129 [ newElem("marquee"), "height", "height", true ], 130 [ newElem("video"), "width", "width", true ], 131 [ newElem("video"), "height", "height", true ], 132 [ newElem("object"), "width", "width", true ], 133 [ newElem("object"), "height", "height", true ], 134 [ newElem("embed"), "width", "width", true ], 135 [ newElem("embed"), "height", "height", true ], 136 [ newElem("img"), "width", "width", true ], 137 [ newElem("img"), "height", "height", true ], 138 [ newElem("td"), "width", "width", false ], 139 [ newElem("td"), "height", "height", false ], 140 [ newElem("table"), "width", "width", false ], 141 [ newElem("table"), "height", "height", true ], 142 [ newElem("tr"), "height", "height", true ], 143 [ newElem("col"), "width", "width", true ], 144 [ newElem("embed"), "hspace", "marginLeft", true ], 145 [ newElem("embed"), "hspace", "marginRight", true ], 146 [ newElem("embed"), "vspace", "marginTop", true ], 147 [ newElem("embed"), "vspace", "marginBottom", true ], 148 [ newElem("img"), "hspace", "marginLeft", true ], 149 [ newElem("img"), "hspace", "marginRight", true ], 150 [ newElem("img"), "vspace", "marginTop", true ], 151 [ newElem("img"), "vspace", "marginBottom", true ], 152 [ newElem("object"), "hspace", "marginLeft", true ], 153 [ newElem("object"), "hspace", "marginRight", true ], 154 [ newElem("object"), "vspace", "marginTop", true ], 155 [ newElem("object"), "vspace", "marginBottom", true ], 156 [ newImageInput(), "hspace", "marginLeft", true ], 157 [ newImageInput(), "hspace", "marginRight", true ], 158 [ newImageInput(), "vspace", "marginTop", true ], 159 [ newImageInput(), "vspace", "marginBottom", true ], 160 [ newElem("marquee"), "hspace", "marginLeft", true ], 161 [ newElem("marquee"), "hspace", "marginRight", true ], 162 [ newElem("marquee"), "vspace", "marginTop", true ], 163 [ newElem("marquee"), "vspace", "marginBottom", true ], 164 // <source width> is mapped to <img> width if both are in <picture>. 165 [ newImgSource(), "width", "width", true, newElem("img"), newElem("picture") ], 166 // <source height> is mapped to <img> height if both are in <picture>. 167 [ newImgSource(), "height", "height", true, newElem("img"), newElem("picture") ], 168 ]; 169 170 function style(element) { 171 return element.ownerDocument.defaultView.getComputedStyle(element); 172 } 173 174 const container = document.getElementById("container"); 175 176 for (let [ctor, attr, prop, zero_allowed, mappedElemCtor, containerCtor] of tests) { 177 let valid, invalid; 178 if (zero_allowed) { 179 valid = valid_values_with_0; 180 invalid = invalid_values; 181 } else { 182 valid = valid_values; 183 invalid = invalid_values_with_0; 184 } 185 186 let elemContainer = null; 187 if (!!containerCtor) { 188 elemContainer = containerCtor(); 189 container.appendChild(elemContainer); 190 } else { 191 elemContainer = container; 192 } 193 194 let runTest = (value, expected) => { 195 let elem = ctor(); 196 let mappedElem = !!mappedElemCtor ? mappedElemCtor() : elem; 197 test(function() { 198 this.add_cleanup(() => { 199 elem.remove(); 200 if (!!mappedElemCtor) { 201 mappedElem.remove(); 202 } 203 }); 204 elem.setAttribute(attr, value); 205 assert_equals(elem.getAttribute(attr), value); 206 elemContainer.appendChild(elem); 207 if (!!mappedElemCtor) { 208 elemContainer.appendChild(mappedElem); 209 } 210 assert_equals(style(mappedElem)[prop], expected); 211 }, `<${elem.localName} ${attr}="${value}"> mapping to ` + 212 `<${mappedElem.localName}> ${prop} property`); 213 } 214 215 for (let [value, result] of valid) { 216 runTest(value, result); 217 } 218 219 let default_elem = !!mappedElemCtor ? mappedElemCtor() : ctor(); 220 elemContainer.appendChild(default_elem); 221 let defaultVal = style(default_elem)[prop]; 222 default_elem.remove(); 223 for (let value of invalid) { 224 runTest(value, defaultVal); 225 } 226 227 if (!!containerCtor) { 228 elemContainer.remove(); 229 } 230 } 231 232 </script> 233 </body>