diff options
Diffstat (limited to 'layout/style/test/test_logical_properties.html')
-rw-r--r-- | layout/style/test/test_logical_properties.html | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/layout/style/test/test_logical_properties.html b/layout/style/test/test_logical_properties.html new file mode 100644 index 000000000..f1265496d --- /dev/null +++ b/layout/style/test/test_logical_properties.html @@ -0,0 +1,422 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test for handling of logical and physical properties</title> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<script src="/tests/SimpleTest/SimpleTest.js"></script> + +<style id="sheet"></style> + +<!-- specify size for <body> to avoid unconstrained-isize warnings + when writing-mode of the test <div> is vertical-* --> +<body style="width:100px; height: 100px;"> + <div id="test" class="test"></div> +</body> + +<script> +var gSheet = document.getElementById("sheet"); +var gTest = document.getElementById("test"); + +// list of groups of physical and logical box properties, such as +// +// { left: "margin-left", right: "margin-right", +// top: "margin-top", bottom: "margin-bottom", +// inlineStart: "margin-inline-start", inlineEnd: "margin-inline-end", +// blockStart: "margin-block-start", blockEnd: "margin-block-end", +// type: "length", prerequisites: "..." } +// +// where the type is a key from the gValues object and the prerequisites +// is a declaration including gCSSProperties' listed prerequisites for +// all four physical properties. +var gBoxPropertyGroups; + +// list of groups of physical and logical axis properties, such as +// +// { horizontal: "width", vertical: "height", +// inline: "inline-size", block: "block-size", +// type: "length", prerequisites: "..." } +var gAxisPropertyGroups; + +// values to use while testing +var gValues = { + "length": ["1px", "2px", "3px", "4px", "5px"], + "color": ["rgb(1, 1, 1)", "rgb(2, 2, 2)", "rgb(3, 3, 3)", "rgb(4, 4, 4)", "rgb(5, 5, 5)"], + "border-style": ["solid", "dashed", "dotted", "double", "groove"], +}; + +// Six unique overall writing modes for property-mapping purposes. +// Note that text-orientation does not affect these mappings, now that +// the proposed sideways-left value no longer exists (superseded in CSS +// Writing Modes by writing-mode: sideways-lr). +var gWritingModes = [ + { style: [ + "writing-mode: horizontal-tb; direction: ltr; ", + ], + blockStart: "top", blockEnd: "bottom", inlineStart: "left", inlineEnd: "right", + block: "vertical", inline: "horizontal" }, + { style: [ + "writing-mode: horizontal-tb; direction: rtl; ", + ], + blockStart: "top", blockEnd: "bottom", inlineStart: "right", inlineEnd: "left", + block: "vertical", inline: "horizontal" }, + { style: [ + "writing-mode: vertical-rl; direction: rtl; ", + "writing-mode: sideways-rl; direction: rtl; ", + ], + blockStart: "right", blockEnd: "left", inlineStart: "bottom", inlineEnd: "top", + block: "horizontal", inline: "vertical" }, + { style: [ + "writing-mode: vertical-rl; direction: ltr; ", + "writing-mode: sideways-rl; direction: ltr; ", + ], + blockStart: "right", blockEnd: "left", inlineStart: "top", inlineEnd: "bottom", + block: "horizontal", inline: "vertical" }, + { style: [ + "writing-mode: vertical-lr; direction: rtl; ", + "writing-mode: sideways-lr; direction: ltr; ", + ], + blockStart: "left", blockEnd: "right", inlineStart: "bottom", inlineEnd: "top", + block: "horizontal", inline: "vertical" }, + { style: [ + "writing-mode: vertical-lr; direction: ltr; ", + "writing-mode: sideways-lr; direction: rtl; ", + ], + blockStart: "left", blockEnd: "right", inlineStart: "top", inlineEnd: "bottom", + block: "horizontal", inline: "vertical" }, +]; + +function init() { + gBoxPropertyGroups = []; + + for (var p in gCSSProperties) { + var type = gCSSProperties[p].type; + + if ((type == CSS_TYPE_SHORTHAND_AND_LONGHAND || + type == CSS_TYPE_LONGHAND && gCSSProperties[p].logical) && + /-inline-end/.test(p)) { + var valueType; + if (/margin|padding|width|offset/.test(p)) { + valueType = "length"; + } else if (/color/.test(p)) { + valueType = "color"; + } else if (/border.*style/.test(p)) { + valueType = "border-style"; + } else { + throw `unexpected property ${p}`; + } + var group = { + inlineStart: p.replace("-inline-end", "-inline-start"), + inlineEnd: p, + blockStart: p.replace("-inline-end", "-block-start"), + blockEnd: p.replace("-inline-end", "-block-end"), + type: valueType + }; + if (/^offset/.test(p)) { + group.left = "left"; + group.right = "right"; + group.top = "top"; + group.bottom = "bottom"; + } else { + group.left = p.replace("-inline-end", "-left"); + group.right = p.replace("-inline-end", "-right"); + group.top = p.replace("-inline-end", "-top"); + group.bottom = p.replace("-inline-end", "-bottom"); + } + group.prerequisites = + make_declaration(gCSSProperties[group.top].prerequisites) + + make_declaration(gCSSProperties[group.right].prerequisites) + + make_declaration(gCSSProperties[group.bottom].prerequisites) + + make_declaration(gCSSProperties[group.left].prerequisites); + gBoxPropertyGroups.push(group); + } + } + + // We don't populate this automatically since the only entries we have, for + // inline-size etc., don't lend themselves to automatically determining + // the names "width", "height", "min-width", etc. + gAxisPropertyGroups = []; + ["", "max-", "min-"].forEach(function(aPrefix) { + gAxisPropertyGroups.push({ + horizontal: `${aPrefix}width`, vertical: `${aPrefix}height`, + inline: `${aPrefix}inline-size`, block: `${aPrefix}block-size`, + type: "length", + prerequisites: + make_declaration(gCSSProperties[`${aPrefix}height`].prerequisites) + }); + }); +} + +function test_computed_values(aTestName, aRules, aExpectedValues) { + gSheet.textContent = aRules; + var cs = getComputedStyle(gTest); + aExpectedValues.forEach(function(aPair) { + is(cs.getPropertyValue(aPair[0]), aPair[1], `${aTestName}, ${aPair[0]}`); + }); + gSheet.textContent = ""; +} + +function make_declaration(aObject) { + var decl = ""; + if (aObject) { + for (var p in aObject) { + decl += `${p}: ${aObject[p]}; `; + } + } + return decl; +} + +function start() { + var script = document.createElement("script"); + script.src = "property_database.js"; + script.onload = function() { + init(); + run_tests(); + }; + document.body.appendChild(script); +} + +function run_axis_test_for_writing_mode(aGroup, aWritingMode, aWritingModeDecl) { + var values = gValues[aGroup.type]; + var decl; + + // Test that logical axis properties are converted to their physical + // equivalent correctly when all four are present on a single + // declaration, with no overwriting of previous properties and + // no physical properties present. We put the writing mode properties + // on a separate declaration to test that the computed values of these + // properties are used, rather than those on the same declaration. + + decl = aGroup.prerequisites + + `${aGroup.inline}: ${values[0]}; ` + + `${aGroup.block}: ${values[1]}; `; + test_computed_values('logical properties on one declaration, writing ' + + 'mode properties on another, ' + + `'${aWritingModeDecl}'`, + `.test { ${aWritingModeDecl} } ` + + `.test { ${decl} }`, + [[aGroup[aWritingMode.inline], values[0]], + [aGroup[aWritingMode.block], values[1]]]); + + + // Test that logical and physical axis properties are cascaded together, + // honoring their relative order on a single declaration. + + // (a) with a single logical property after the physical ones + + ["inline", "block"].forEach(function(aLogicalAxis) { + decl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.horizontal}: ${values[0]}; ` + + `${aGroup.vertical}: ${values[1]}; ` + + `${aGroup[aLogicalAxis]}: ${values[2]}; `; + var expected = ["horizontal", "vertical"].map( + (axis, i) => [aGroup[axis], + values[axis == aWritingMode[aLogicalAxis] ? 2 : i]] + ); + test_computed_values(`${aLogicalAxis} last on single declaration, ` + + `'${aWritingModeDecl}'`, + `.test { ${decl} }`, + expected); + }); + + // (b) with a single physical property after the logical ones + + ["horizontal", "vertical"].forEach(function(aPhysicalAxis) { + decl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.inline}: ${values[0]}; ` + + `${aGroup.block}: ${values[1]}; ` + + `${aGroup[aPhysicalAxis]}: ${values[2]}; `; + var expected = ["inline", "block"].map( + (axis, i) => [aGroup[aWritingMode[axis]], + values[aWritingMode[axis] == aPhysicalAxis ? 2 : i]] + ); + test_computed_values(`${aPhysicalAxis} last on single declaration, ` + + `'${aWritingModeDecl}'`, + `.test { ${decl} }`, + expected); + }); + + + // Test that logical and physical axis properties are cascaded properly when + // on different declarations. + + var loDecl; // lower specifity + var hiDecl; // higher specificity + + // (a) with a logical property in the high specificity rule + + loDecl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.horizontal}: ${values[0]}; ` + + `${aGroup.vertical}: ${values[1]}; `; + + ["inline", "block"].forEach(function(aLogicalAxis) { + hiDecl = `${aGroup[aLogicalAxis]}: ${values[2]}; `; + var expected = ["horizontal", "vertical"].map( + (axis, i) => [aGroup[axis], + values[axis == aWritingMode[aLogicalAxis] ? 2 : i]] + ); + test_computed_values(`${aLogicalAxis}, two declarations, ` + + `'${aWritingModeDecl}'`, + `#test { ${hiDecl} } ` + + `.test { ${loDecl} }`, + expected); + }); + + // (b) with a physical property in the high specificity rule + + loDecl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.inline}: ${values[0]}; ` + + `${aGroup.block}: ${values[1]}; `; + + ["horizontal", "vertical"].forEach(function(aPhysicalAxis) { + hiDecl = `${aGroup[aPhysicalAxis]}: ${values[2]}; `; + var expected = ["inline", "block"].map( + (axis, i) => [aGroup[aWritingMode[axis]], + values[aWritingMode[axis] == aPhysicalAxis ? 2 : i]] + ); + test_computed_values(`${aPhysicalAxis}, two declarations, ` + + `'${aWritingModeDecl}'`, + `#test { ${hiDecl} } ` + + `.test { ${loDecl} }`, + expected); + }); +} + +function run_box_test_for_writing_mode(aGroup, aWritingMode, aWritingModeDecl) { + var values = gValues[aGroup.type]; + var decl; + + // Test that logical box properties are converted to their physical + // equivalent correctly when all four are present on a single + // declaration, with no overwriting of previous properties and + // no physical properties present. We put the writing mode properties + // on a separate declaration to test that the computed values of these + // properties are used, rather than those on the same declaration. + + decl = aGroup.prerequisites + + `${aGroup.inlineStart}: ${values[0]}; ` + + `${aGroup.inlineEnd}: ${values[1]}; ` + + `${aGroup.blockStart}: ${values[2]}; ` + + `${aGroup.blockEnd}: ${values[3]}; `; + test_computed_values('logical properties on one declaration, writing ' + + 'mode properties on another, ' + + `'${aWritingModeDecl}'`, + `.test { ${aWritingModeDecl} } ` + + `.test { ${decl} }`, + [[aGroup[aWritingMode.inlineStart], values[0]], + [aGroup[aWritingMode.inlineEnd], values[1]], + [aGroup[aWritingMode.blockStart], values[2]], + [aGroup[aWritingMode.blockEnd], values[3]]]); + + // Test that logical and physical box properties are cascaded together, + // honoring their relative order on a single declaration. + + // (a) with a single logical property after the physical ones + + ["inlineStart", "inlineEnd", "blockStart", "blockEnd"].forEach(function(aLogicalSide) { + decl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.left}: ${values[0]}; ` + + `${aGroup.right}: ${values[1]}; ` + + `${aGroup.top}: ${values[2]}; ` + + `${aGroup.bottom}: ${values[3]}; ` + + `${aGroup[aLogicalSide]}: ${values[4]}; `; + var expected = ["left", "right", "top", "bottom"].map( + (side, i) => [aGroup[side], + values[side == aWritingMode[aLogicalSide] ? 4 : i]] + ); + test_computed_values(`${aLogicalSide} last on single declaration, ` + + `'${aWritingModeDecl}'`, + `.test { ${decl} }`, + expected); + }); + + // (b) with a single physical property after the logical ones + + ["left", "right", "top", "bottom"].forEach(function(aPhysicalSide) { + decl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.inlineStart}: ${values[0]}; ` + + `${aGroup.inlineEnd}: ${values[1]}; ` + + `${aGroup.blockStart}: ${values[2]}; ` + + `${aGroup.blockEnd}: ${values[3]}; ` + + `${aGroup[aPhysicalSide]}: ${values[4]}; `; + var expected = ["inlineStart", "inlineEnd", "blockStart", "blockEnd"].map( + (side, i) => [aGroup[aWritingMode[side]], + values[aWritingMode[side] == aPhysicalSide ? 4 : i]] + ); + test_computed_values(`${aPhysicalSide} last on single declaration, ` + + `'${aWritingModeDecl}'`, + `.test { ${decl} }`, + expected); + }); + + + // Test that logical and physical box properties are cascaded properly when + // on different declarations. + + var loDecl; // lower specifity + var hiDecl; // higher specificity + + // (a) with a logical property in the high specificity rule + + loDecl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.left}: ${values[0]}; ` + + `${aGroup.right}: ${values[1]}; ` + + `${aGroup.top}: ${values[2]}; ` + + `${aGroup.bottom}: ${values[3]}; `; + + ["inlineStart", "inlineEnd", "blockStart", "blockEnd"].forEach(function(aLogicalSide) { + hiDecl = `${aGroup[aLogicalSide]}: ${values[4]}; `; + var expected = ["left", "right", "top", "bottom"].map( + (side, i) => [aGroup[side], + values[side == aWritingMode[aLogicalSide] ? 4 : i]] + ); + test_computed_values(`${aLogicalSide}, two declarations, ` + + `'${aWritingModeDecl}'`, + `#test { ${hiDecl} } ` + + `.test { ${loDecl} }`, + expected); + }); + + // (b) with a physical property in the high specificity rule + + loDecl = aWritingModeDecl + aGroup.prerequisites + + `${aGroup.inlineStart}: ${values[0]}; ` + + `${aGroup.inlineEnd}: ${values[1]}; ` + + `${aGroup.blockStart}: ${values[2]}; ` + + `${aGroup.blockEnd}: ${values[3]}; `; + + ["left", "right", "top", "bottom"].forEach(function(aPhysicalSide) { + hiDecl = `${aGroup[aPhysicalSide]}: ${values[4]}; `; + var expected = ["inlineStart", "inlineEnd", "blockStart", "blockEnd"].map( + (side, i) => [aGroup[aWritingMode[side]], + values[aWritingMode[side] == aPhysicalSide ? 4 : i]] + ); + test_computed_values(`${aPhysicalSide}, two declarations, ` + + `'${aWritingModeDecl}'`, + `#test { ${hiDecl} } ` + + `.test { ${loDecl} }`, + expected); + }); +} + +function run_tests() { + gBoxPropertyGroups.forEach(function(aGroup) { + gWritingModes.forEach(function(aWritingMode) { + aWritingMode.style.forEach(function(aWritingModeDecl) { + run_box_test_for_writing_mode(aGroup, aWritingMode, aWritingModeDecl); + }); + }); + }); + + gAxisPropertyGroups.forEach(function(aGroup) { + gWritingModes.forEach(function(aWritingMode) { + aWritingMode.style.forEach(function(aWritingModeDecl) { + run_axis_test_for_writing_mode(aGroup, aWritingMode, aWritingModeDecl); + }); + }); + }); + + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +start(); +</script> |