| <!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> |