new file mode 100644
--- /dev/null
+++ b/dom/flex/test/chrome/test_flex_items.html
@@ -0,0 +1,169 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+ .container {
+ display: flex;
+ background-color: grey;
+ font: 14px sans-serif;
+ width: 800px;
+ height: 50px;
+ }
+
+ .base { align-self: baseline; }
+ .lastbase { align-self: last baseline; }
+
+ .offset { margin-top: 10px;
+ margin-bottom: 3px; }
+
+ .lime { background: lime; }
+ .yellow { background: yellow; }
+ .orange { background: orange; }
+ .pink { background: pink; }
+ .white { background: white; }
+
+ .crossMinMax { min-height: 40px;
+ max-height: 120px; }
+
+ .mainMinMax { min-width: 120px;
+ max-width: 500px; }
+
+ .flexGrow { flex-grow: 1; }
+
+ #second { width: 100px; }
+</style>
+
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+const TEXT_NODE = Ci.nsIDOMNode.TEXT_NODE;
+
+function testItemMatchesExpectedValues(item, values, index) {
+ if (typeof(values.node) != "undefined") {
+ is(item.node, values.node, "Item index " + index + " has expected node.");
+ }
+
+ if (typeof(values.node_todo) != "undefined") {
+ todo_is(item.node, values.node_todo, "Item index " + index + " has expected node.");
+ }
+
+ if (typeof(values.mainBaseSize) != "undefined") {
+ is(item.mainBaseSize, values.mainBaseSize, "Item index " + index + " has expected mainBaseSize.");
+ }
+
+ if (typeof(values.mainDeltaSize) != "undefined") {
+ is(item.mainDeltaSize, values.mainDeltaSize, "Item index " + index + " has expected mainDeltaSize.");
+ }
+
+ if (typeof(values.mainMinSize) != "undefined") {
+ is(item.mainMinSize, values.mainMinSize, "Item index " + index + " has expected mainMinSize.");
+ }
+
+ if (typeof(values.mainMaxSize) != "undefined") {
+ is(item.mainMaxSize, values.mainMaxSize, "Item index " + index + " has expected mainMaxSize.");
+ }
+
+ if (typeof(values.crossMinSize) != "undefined") {
+ is(item.crossMinSize, values.crossMinSize, "Item index " + index + " has expected crossMinSize.");
+ }
+
+ if (typeof(values.crossMaxSize) != "undefined") {
+ is(item.crossMaxSize, values.crossMaxSize, "Item index " + index + " has expected crossMaxSize.");
+ }
+}
+
+function nearlyEqual(a, b) {
+ const ep = 1e-4;
+ let diff = a - b;
+ return (diff < ep && diff > -ep);
+}
+
+function runTests() {
+ let container = document.getElementById("wrapper");
+ let flex = container.getAsFlexContainer();
+ let lines = flex.getLines();
+ is(lines.length, 1, "Container has expected number of lines.");
+
+ let line = lines[0];
+ let containerHeight = container.getBoundingClientRect().height;
+ is(line.crossSize, containerHeight, "Line crossSize equals the height of the container.");
+
+ let first = document.getElementById("first");
+ let second = document.getElementById("second");
+ let third = document.getElementById("third");
+ let fourth = document.getElementById("fourth");
+ let fifth = document.getElementById("fifth");
+ let sixth = container.lastChild;
+ is(sixth.nodeType, TEXT_NODE, "Sixth child should be an anonymous text node.");
+
+ // We can't compare baselines precisely, so we'll just confirm that they appear
+ // somewhere within the elements that determine them.
+ let firstRect = first.getBoundingClientRect();
+ ok(line.firstBaselineOffset > firstRect.top &&
+ line.firstBaselineOffset < firstRect.bottom,
+ "Line firstBaselineOffset lands somewhere within the element that determines it.");
+
+ // For last baseline, it's measured from the bottom, so we have to compare against
+ // the element bounds subtracted from the container height.
+ let secondRect = second.getBoundingClientRect();
+ ok(line.lastBaselineOffset > containerHeight - secondRect.bottom &&
+ line.lastBaselineOffset < containerHeight - secondRect.top,
+ "Line lastBaselineOffset lands somewhere within the element that determines it.");
+
+ let items = line.getItems();
+ is(items.length, 6, "Line has expected number of items.");
+
+ let expectedValues = [
+ { node: first,
+ crossMinSize: 0 },
+ { node: second,
+ mainBaseSize: secondRect.width,
+ mainDeltaSize: 0 },
+ { node: third,
+ crossMinSize: 40,
+ crossMaxSize: 120,
+ mainDeltaSize: 0 },
+ { node: fourth,
+ mainMinSize: 120,
+ mainMaxSize: 500,
+ mainDeltaSize: 0 },
+ { node: fifth,
+ mainDeltaSize: 0 },
+ { node: sixth },
+ ];
+
+ for (let i = 0; i < items.length; ++i) {
+ let item = items[i];
+ let values = expectedValues[i];
+ testItemMatchesExpectedValues(item, values, i);
+ }
+
+ // Check that the delta size of the first item is nearly equal to the actual size minus the base size.
+ ok(nearlyEqual(items[0].mainDeltaSize, firstRect.width - items[0].mainBaseSize),
+ "flex-grow item has expected mainDeltaSize.");
+
+ SimpleTest.finish();
+}
+</script>
+</head>
+
+<body onLoad="runTests();">
+ <div id="wrapper" class="container">
+ <div id="first" class="lime base flexGrow">one line (first)</div>
+ <div id="second" class="yellow lastbase">one line (last)</div>
+ <div id="third" class="orange offset lastbase crossMinMax">two<br/>lines and offset (last)</div>
+ <div id="fourth" class="pink offset base mainMinMax">offset (first)</div>
+ <div style="display:contents">
+ <div id="fifth" class="white">replaced</div>
+ </div>
+ anonymous text node
+ </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/flex/test/chrome/test_flex_lines.html
@@ -0,0 +1,281 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+ f {
+ display: flex;
+ background-color: grey;
+ font: 12px sans-serif;
+ width: 800px;
+ height: 42px;
+ margin-bottom: 5px;
+ }
+
+ .withZ::after {
+ background-color: pink;
+ content: "Z";
+ width: 100px;
+ height: 10px;
+ }
+
+ .wrap {
+ flex-wrap: wrap;
+ }
+
+ .wrapReverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ b {
+ background-color: gold;
+ min-width: 100px;
+ height: 20px;
+ flex-grow: 1;
+ }
+ b::after {
+ content: "B";
+ }
+
+ c {
+ background-color: yellow;
+ width: 200px;
+ height: 15px;
+ }
+ c::after {
+ content: "C";
+ }
+
+ d {
+ background-color: orange;
+ width: 300px;
+ height: 10px;
+ }
+ d::after {
+ content: "D";
+ }
+
+ e {
+ background-color: silver;
+ width: 300px;
+ height: 10px;
+ flex-shrink: 2;
+ }
+ e::after {
+ content: "E";
+ }
+</style>
+
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function testLineMatchesExpectedValues(line, values, lineIndex, flexIndex) {
+ if (typeof(values.growthState) != "undefined") {
+ is(line.growthState, values.growthState, "Flex index " + flexIndex + " line index " + lineIndex + " has expected growthState.");
+ }
+
+ if (typeof(values.crossSize) != "undefined") {
+ is(line.crossSize, values.crossSize, "Flex index " + flexIndex + " line index " + lineIndex + " has expected crossSize.");
+ }
+
+ if (typeof(values.itemCount) != "undefined") {
+ is(line.getItems().length, values.itemCount, "Flex index " + flexIndex + " line index " + lineIndex + " has expected number of items.");
+ }
+}
+
+function runTests() {
+ let expectedValues = [
+ // items don't fill container, no grow, shrink, or min-width
+ [{ crossSize: 42,
+ itemCount: 2,
+ growthState: "unchanged" }],
+ [{ crossSize: 42,
+ itemCount: 3,
+ growthState: "unchanged" }],
+
+ // items don't fill container, no grow, shrink, or min-width, with wrap and align-content:center -->
+ [{ crossSize: 15,
+ itemCount: 2,
+ growthState: "unchanged" }],
+ [{ crossSize: 15,
+ itemCount: 3,
+ growthState: "unchanged" }],
+
+ // items don't fill container, with grow
+ [{ crossSize: 42,
+ itemCount: 3,
+ growthState: "growing" }],
+ [{ crossSize: 42,
+ itemCount: 4,
+ growthState: "growing" }],
+
+ // items overfill container, with min-width, and sometimes with wrap
+ [{ crossSize: 42,
+ itemCount: 5,
+ growthState: "shrinking" }],
+ [{ crossSize: 21,
+ itemCount: 3,
+ growthState: "growing" },
+ { crossSize: 21,
+ itemCount: 2,
+ growthState: "growing" }],
+ [{ crossSize: 42,
+ itemCount: 6,
+ growthState: "shrinking" }],
+ [{ crossSize: 21,
+ itemCount: 3,
+ growthState: "growing" },
+ { crossSize: 21,
+ itemCount: 3,
+ growthState: "growing" }],
+
+ // items overfill container, with shrink and sometimes with wrap
+ [{ crossSize: 42,
+ itemCount: 3,
+ growthState: "shrinking" }],
+ [{ crossSize: 21,
+ itemCount: 2,
+ growthState: "unchanged" },
+ { crossSize: 21,
+ itemCount: 1,
+ growthState: "unchanged" }],
+ [{ crossSize: 42,
+ itemCount: 4,
+ growthState: "shrinking" }],
+ [{ crossSize: 21,
+ itemCount: 2,
+ growthState: "unchanged" },
+ { crossSize: 21,
+ itemCount: 2,
+ growthState: "unchanged" }],
+
+ // items overfill container, with wrap and different types of align-content
+ [{ crossSize: 26,
+ itemCount: 3 },
+ { crossSize: 16,
+ itemCount: 1 }],
+ [{ crossSize: 20,
+ itemCount: 3 },
+ { crossSize: 10,
+ itemCount: 1 }],
+ [{ crossSize: 20,
+ itemCount: 3 },
+ { crossSize: 10,
+ itemCount: 1 }],
+ [{ crossSize: 20,
+ itemCount: 3 },
+ { crossSize: 10,
+ itemCount: 1 }],
+ [{ crossSize: 20,
+ itemCount: 3 },
+ { crossSize: 10,
+ itemCount: 1 }],
+ [{ crossSize: 20,
+ itemCount: 3 },
+ { crossSize: 10,
+ itemCount: 1 }],
+
+ // items overfill container, with wrap-reverse and different types of align-content
+ [{ crossSize: 16,
+ itemCount: 2 },
+ { crossSize: 26,
+ itemCount: 3 }],
+ [{ crossSize: 10,
+ itemCount: 2 },
+ { crossSize: 20,
+ itemCount: 3 }],
+ [{ crossSize: 10,
+ itemCount: 2 },
+ { crossSize: 20,
+ itemCount: 3 }],
+ [{ crossSize: 10,
+ itemCount: 2 },
+ { crossSize: 20,
+ itemCount: 3 }],
+ [{ crossSize: 10,
+ itemCount: 2 },
+ { crossSize: 20,
+ itemCount: 3 }],
+ [{ crossSize: 10,
+ itemCount: 2 },
+ { crossSize: 20,
+ itemCount: 3 }],
+
+ // other strange types of flex containers
+ [{ itemCount: 3 }],
+ ];
+
+ let children = document.body.children;
+ is(children.length, expectedValues.length, "Document has expected number of flex containers.");
+
+ for (let i = 0; i < children.length; ++i) {
+ let flex = children.item(i).getAsFlexContainer();
+ ok(flex, "Document child index " + i + " is a flex container.");
+ if (flex) {
+ let values = expectedValues[i];
+
+ let lines = flex.getLines();
+ is(lines.length, values.length, "Flex index " + i + " has expected number of lines.");
+
+ for (let j = 0; j < lines.length; ++j) {
+ testLineMatchesExpectedValues(lines[j], values[j], j, i);
+ }
+ }
+ }
+
+ SimpleTest.finish();
+}
+</script>
+</head>
+
+<body onLoad="runTests();">
+
+<!-- items don't fill container, no grow, shrink, or min-width -->
+<f><c></c><d></d></f>
+<f class="withZ"><c></c><d></d></f>
+
+<!-- items don't fill container, no grow, shrink, or min-width, with wrap and align-content:center -->
+<f class="wrap" style="align-content:center"><c></c><d></d></f>
+<f class="withZ wrap" style="align-content:center"><c></c><d></d></f>
+
+<!-- items don't fill container, with grow -->
+<f><b></b><c></c><d></d></f>
+<f class="withZ"><b></b><c></c><d></d></f>
+
+<!-- items overfill container, with min-width, and sometimes with wrap -->
+<f><b></b><d></d><d></d><d></d><b></b></f>
+<f class="wrap"><b></b><d></d><d></d><d></d><b></b></f>
+<f class="withZ"><b></b><d></d><d></d><d></d><b></b></f>
+<f class="wrap withZ"><b></b><d></d><d></d><d></d><b></b></f>
+
+<!-- items overfill container, with shrink and sometimes with wrap -->
+<f><d></d><d></d><e></e></f>
+<f class="wrap"><d></d><d></d><e></e></f>
+<f class="withZ"><d></d><d></d><e></e></f>
+<f class="wrap withZ"><d></d><d></d><e></e></f>
+
+<!-- items overfill container, with wrap and different types of align-content -->
+<f class="wrap"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:flex-start"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:flex-end"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:center"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:space-between"><b></b><c></c><d></d><e></e></f>
+<f class="wrap" style="align-content:space-around"><b></b><c></c><d></d><e></e></f>
+
+<!-- items overfill container, with wrap-reverse and different types of align-content -->
+<f class="wrapReverse withZ"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:flex-start"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:flex-end"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:center"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:space-between"><b></b><c></c><d></d><e></e></f>
+<f class="wrapReverse withZ" style="align-content:space-around"><b></b><c></c><d></d><e></e></f>
+
+<!-- other strange types of flex containers -->
+<f style="overflow:scroll"><d></d><d></d><e></e></f>
+
+</body>
+</html>