mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
458 lines
19 KiB
HTML
458 lines
19 KiB
HTML
<!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>
|
|
<div id="test" class="test"></div>
|
|
|
|
<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
|
|
var gWritingModes = [
|
|
{ style: [
|
|
"writing-mode: horizontal-tb; text-orientation: mixed; direction: ltr; ",
|
|
"writing-mode: horizontal-tb; text-orientation: upright; direction: ltr; ",
|
|
"writing-mode: horizontal-tb; text-orientation: sideways-right; direction: ltr; ",
|
|
// XXX See the todo()s below.
|
|
// "writing-mode: horizontal-tb; text-orientation: sideways-left; direction: ltr; ",
|
|
// "writing-mode: horizontal-tb; text-orientation: sideways; direction: ltr; ",
|
|
],
|
|
blockStart: "top", blockEnd: "bottom", inlineStart: "left", inlineEnd: "right",
|
|
block: "vertical", inline: "horizontal" },
|
|
{ style: [
|
|
"writing-mode: horizontal-tb; text-orientation: mixed; direction: rtl; ",
|
|
"writing-mode: horizontal-tb; text-orientation: upright; direction: rtl; ",
|
|
"writing-mode: horizontal-tb; text-orientation: sideways-right; direction: rtl; ",
|
|
// "writing-mode: horizontal-tb; text-orientation: sideways-left; direction: rtl; ",
|
|
// "writing-mode: horizontal-tb; text-orientation: sideways; direction: rtl; ",
|
|
],
|
|
blockStart: "top", blockEnd: "bottom", inlineStart: "right", inlineEnd: "left",
|
|
block: "vertical", inline: "horizontal" },
|
|
{ style: [
|
|
"writing-mode: vertical-rl; text-orientation: mixed; direction: rtl; ",
|
|
"writing-mode: vertical-rl; text-orientation: upright; direction: rtl; ",
|
|
"writing-mode: vertical-rl; text-orientation: sideways-right; direction: rtl; ",
|
|
// "writing-mode: vertical-rl; text-orientation: sideways-left; direction: ltr; ",
|
|
// "writing-mode: vertical-rl; text-orientation: sideways; direction: rtl; ",
|
|
],
|
|
blockStart: "right", blockEnd: "left", inlineStart: "bottom", inlineEnd: "top",
|
|
block: "horizontal", inline: "vertical" },
|
|
{ style: [
|
|
"writing-mode: vertical-rl; text-orientation: mixed; direction: ltr; ",
|
|
"writing-mode: vertical-rl; text-orientation: upright; direction: ltr; ",
|
|
"writing-mode: vertical-rl; text-orientation: sideways-right; direction: ltr; ",
|
|
// "writing-mode: vertical-rl; text-orientation: sideways-left; direction: rtl; ",
|
|
// "writing-mode: vertical-rl; text-orientation: sideways; direction: ltr; ",
|
|
],
|
|
blockStart: "right", blockEnd: "left", inlineStart: "top", inlineEnd: "bottom",
|
|
block: "horizontal", inline: "vertical" },
|
|
{ style: [
|
|
"writing-mode: vertical-lr; text-orientation: mixed; direction: rtl; ",
|
|
"writing-mode: vertical-lr; text-orientation: upright; direction: rtl; ",
|
|
"writing-mode: vertical-lr; text-orientation: sideways-right; direction: rtl; ",
|
|
// "writing-mode: vertical-lr; text-orientation: sideways-left; direction: ltr; ",
|
|
// "writing-mode: vertical-lr; text-orientation: sideways; direction: ltr; ",
|
|
],
|
|
blockStart: "left", blockEnd: "right", inlineStart: "bottom", inlineEnd: "top",
|
|
block: "horizontal", inline: "vertical" },
|
|
{ style: [
|
|
"writing-mode: vertical-lr; text-orientation: mixed; direction: ltr; ",
|
|
"writing-mode: vertical-lr; text-orientation: upright; direction: ltr; ",
|
|
"writing-mode: vertical-lr; text-orientation: sideways-right; direction: ltr; ",
|
|
// "writing-mode: vertical-lr; text-orientation: sideways-left; direction: rtl; ",
|
|
// "writing-mode: vertical-lr; text-orientation: sideways; 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)
|
|
});
|
|
});
|
|
|
|
// Assume that sideways-left and sideways keywords are still not parsed yet
|
|
// for text-orientation. When we start supporting these keywords, the
|
|
// entries in the .style properties of the gWritingModes objects above
|
|
// should be uncommented.
|
|
var s = document.createElement("style");
|
|
document.body.appendChild(s);
|
|
|
|
s.textContent = "div { }";
|
|
s.sheet.cssRules[0].style.textOrientation = "sideways-left";
|
|
todo(s.sheet.cssRules[0].style.textOrientation, "sideways-left",
|
|
"uncomment sideways-left cases from gWritingModes and " +
|
|
"remove this todo()!");
|
|
|
|
s.textContent = "div { }";
|
|
s.sheet.cssRules[0].style.textOrientation = "sideways";
|
|
todo(s.sheet.cssRules[0].style.textOrientation, "sideways",
|
|
"uncomment sideways cases from gWritingModes and " +
|
|
"remove this todo()!");
|
|
|
|
s.remove();
|
|
}
|
|
|
|
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() {
|
|
// load property_database.js once the pref change has gone into effect
|
|
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();
|
|
SpecialPowers.pushPrefEnv({ "set": [["layout.css.vertical-text.enabled", true]] }, start);
|
|
</script>
|