<!doctype html> <meta charset=utf-8> <title>Test handling of attributes that map to dimension properties</title> <meta name="timeout" content="long"> <link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property"> <link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property-(ignoring-zero)"> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> <body> <!-- We need a place to put our elements so they're bound to a document and have computed style, but we don't want percentages resolved to lengths, so need to make sure they have no CSS boxes --> <div id="container" style="display: none"></div> <script> /* * This test tests * * https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property * and * https://html.spec.whatwg.org/multipage/rendering.html#maps-to-the-dimension-property-(ignoring-zero) * for various elements and various values. */ /* * Array of input/output pairs. The input is the string to use as the * attribute value. The output is the string expected as the computed style * for the relevant CSS property. */ const valid_values = [ // Valid values [ "200", "200px" ], [ "1007", "1007px" ], [ " 00523 ", "523px" ], [ "200.25", "200.25px" ], [ "200.7", "200.7px" ], [ "200.", "200px" ], [ "200in", "200px" ], [ "200.25in", "200.25px" ], [ "200 %", "200px" ], [ "200 abc", "200px" ], [ "200%", "200%" ], [ "200%abc", "200%" ], [ "200.25%", "200.25%" ], [ "200.%", "200%" ], [ "20.25e2", "20.25px" ], [ "20.25E2", "20.25px" ], ]; /* * Values that are only valid for the not-ignoring-zero case. */ const zero_values = [ [ "0", "0px" ], [ "0%", "0%" ], [ "0px", "0px" ], ]; /* * Array of invalid values. These should lead to the default value of the * relevant CSS property. */ const invalid_values = [ "-0", "-0%", "-200", "-200px", " -200", "+-200", "-+200", "-200%", "+200", " +200in ", " +200.25in ", "+200%", " +200.25% ", " +200.25%abc", "+0", "+0%", ".", ".%", ".x", ".5", ".5%" ]; const valid_values_with_0 = valid_values.concat(zero_values); const invalid_values_with_0 = invalid_values.concat(zero_values.map((v) => v[0])); function newElem(name) { return () => document.createElement(name); } function newImageInput() { return () => { var elem = newElem("input")(); elem.type = "image"; return elem; } } function newImgSource() { return () => { var elem = newElem("source")(); elem.setAttribute("srcset", "/images/green-100x50.png"); return elem; } } /* * Array of tests. Each test consists of the following information: * * 1) An element creation function. * 2) The name of the attribute to set * 3) The name of the CSS property to get. * 4) A boolean indicating whether 0 is a valid value for the dimension * attribute. */ const tests = [ [ newElem("hr"), "width", "width", true ], [ newElem("iframe"), "width", "width", true ], [ newElem("iframe"), "height", "height", true ], [ newImageInput(), "width", "width", true ], [ newImageInput(), "height", "height", true ], [ newElem("marquee"), "width", "width", true ], [ newElem("marquee"), "height", "height", true ], [ newElem("video"), "width", "width", true ], [ newElem("video"), "height", "height", true ], [ newElem("object"), "width", "width", true ], [ newElem("object"), "height", "height", true ], [ newElem("embed"), "width", "width", true ], [ newElem("embed"), "height", "height", true ], [ newElem("img"), "width", "width", true ], [ newElem("img"), "height", "height", true ], [ newElem("td"), "width", "width", false ], [ newElem("td"), "height", "height", false ], [ newElem("table"), "width", "width", false ], [ newElem("table"), "height", "height", true ], [ newElem("tr"), "height", "height", true ], [ newElem("col"), "width", "width", true ], [ newElem("embed"), "hspace", "marginLeft", true ], [ newElem("embed"), "hspace", "marginRight", true ], [ newElem("embed"), "vspace", "marginTop", true ], [ newElem("embed"), "vspace", "marginBottom", true ], [ newElem("img"), "hspace", "marginLeft", true ], [ newElem("img"), "hspace", "marginRight", true ], [ newElem("img"), "vspace", "marginTop", true ], [ newElem("img"), "vspace", "marginBottom", true ], [ newElem("object"), "hspace", "marginLeft", true ], [ newElem("object"), "hspace", "marginRight", true ], [ newElem("object"), "vspace", "marginTop", true ], [ newElem("object"), "vspace", "marginBottom", true ], [ newImageInput(), "hspace", "marginLeft", true ], [ newImageInput(), "hspace", "marginRight", true ], [ newImageInput(), "vspace", "marginTop", true ], [ newImageInput(), "vspace", "marginBottom", true ], [ newElem("marquee"), "hspace", "marginLeft", true ], [ newElem("marquee"), "hspace", "marginRight", true ], [ newElem("marquee"), "vspace", "marginTop", true ], [ newElem("marquee"), "vspace", "marginBottom", true ], // <source width> is mapped to <img> width if both are in <picture>. [ newImgSource(), "width", "width", true, newElem("img"), newElem("picture") ], // <source height> is mapped to <img> height if both are in <picture>. [ newImgSource(), "height", "height", true, newElem("img"), newElem("picture") ], ]; function style(element) { return element.ownerDocument.defaultView.getComputedStyle(element); } const container = document.getElementById("container"); for (let [ctor, attr, prop, zero_allowed, mappedElemCtor, containerCtor] of tests) { let valid, invalid; if (zero_allowed) { valid = valid_values_with_0; invalid = invalid_values; } else { valid = valid_values; invalid = invalid_values_with_0; } let elemContainer = null; if (!!containerCtor) { elemContainer = containerCtor(); container.appendChild(elemContainer); } else { elemContainer = container; } let runTest = (value, expected) => { let elem = ctor(); let mappedElem = !!mappedElemCtor ? mappedElemCtor() : elem; test(function() { this.add_cleanup(() => { elem.remove(); if (!!mappedElemCtor) { mappedElem.remove(); } }); elem.setAttribute(attr, value); assert_equals(elem.getAttribute(attr), value); elemContainer.appendChild(elem); if (!!mappedElemCtor) { elemContainer.appendChild(mappedElem); } assert_equals(style(mappedElem)[prop], expected); }, `<${elem.localName} ${attr}="${value}"> mapping to ` + `<${mappedElem.localName}> ${prop} property`); } for (let [value, result] of valid) { runTest(value, result); } let default_elem = !!mappedElemCtor ? mappedElemCtor() : ctor(); elemContainer.appendChild(default_elem); let defaultVal = style(default_elem)[prop]; default_elem.remove(); for (let value of invalid) { runTest(value, defaultVal); } if (!!containerCtor) { elemContainer.remove(); } } </script> </body>