Skip to content
Permalink
Browse files
[CSS Grid Layout] Fix positioning grid items using named grid lines/a…
…reas

https://bugs.webkit.org/show_bug.cgi?id=129372

Reviewed by Darin Adler.

Source/WebCore:

Our code was assuming that a <custom-ident> in
-webkit-grid-{column|row}-{start|end} and
-webkit-grid-{column|row} was always a grid area name. That's
wrong because the <custom-ident> could be also a explicitly named
grid line or the an implicitly named grid line created by a grid
area definition.

The style resolution code was not correct either. This patch fixes
it so it now matches the spec, which means that:
- first we try to match any existing grid area.
- then if there is a named grid line with the name
<custom-ident>-{start|end} for -webkit-grid-{column|row}-{start|end}
defined before the grid area then we use it instead of the grid
area.
- otherwise if there is a named grid line we resolve to the first such line.
- otherwise we treat it as 'auto'.

Fixing this uncovered a bug in GridPosition, we were not using the
name of the stored grid area to check if two GridPositions were
the same.

Tests: fast/css-grid-layout/grid-item-position-changed-dynamic.html
       fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html

* css/StyleResolver.cpp:
(WebCore::gridLineDefinedBeforeGridArea): New function to check if
a given named grid line was defined before an implicit named grid
line created by a grid area definition.
(WebCore::StyleResolver::adjustNamedGridItemPosition): New
function that adjusts the position of a GridPosition parsed as a
grid area.
(WebCore::StyleResolver::adjustGridItemPosition): Use the new
function adjustNamedGridItemPosition to adjust the positions of
named grid lines.
* css/StyleResolver.h:
* rendering/RenderGrid.cpp:
(WebCore::RenderGrid::resolveNamedGridLinePositionFromStyle): Use GridPosition:: namespace.
(WebCore::RenderGrid::resolveGridPositionFromStyle): Ditto.
(WebCore::RenderGrid::resolveRowEndColumnEndNamedGridLinePositionAgainstOppositePosition): Ditto.
* rendering/RenderGrid.h:
* rendering/style/GridPosition.h:
(WebCore::GridPosition::adjustGridPositionForRowEndColumnEndSide): Moved from RenderGrid.cpp.
(WebCore::GridPosition::adjustGridPositionForSide): Ditto.
(WebCore::GridPosition::operator==): Use the named grid line to check equality.

LayoutTests:

Added a new test that checks that we correctly position grid items
using named grid lines, grid areas and also with the implicit
named grid lines created by grid areas.

I'm also importing a test from Blink that checks that we can
dynamically change the position of a grid item by changing the
name of the grid lines used to position it.

* fast/css-grid-layout/grid-item-position-changed-dynamic-expected.txt:
Merged from Blink r153913 by <jchaffraix@chromium.org>.
* fast/css-grid-layout/grid-item-position-changed-dynamic.html: Ditto.
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution-expected.txt: Added.
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html: Added.

Canonical link: https://commits.webkit.org/147556@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@164869 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
svillar committed Feb 28, 2014
1 parent 43c697c commit 0cd8da13aa5e02d63c92591a0b63013ca5a4db92
Showing 11 changed files with 694 additions and 36 deletions.
@@ -1,3 +1,24 @@
2014-02-27 Sergio Villar Senin <svillar@igalia.com>

[CSS Grid Layout] Fix positioning grid items using named grid lines/areas
https://bugs.webkit.org/show_bug.cgi?id=129372

Reviewed by Darin Adler.

Added a new test that checks that we correctly position grid items
using named grid lines, grid areas and also with the implicit
named grid lines created by grid areas.

I'm also importing a test from Blink that checks that we can
dynamically change the position of a grid item by changing the
name of the grid lines used to position it.

* fast/css-grid-layout/grid-item-position-changed-dynamic-expected.txt:
Merged from Blink r153913 by <jchaffraix@chromium.org>.
* fast/css-grid-layout/grid-item-position-changed-dynamic.html: Ditto.
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution-expected.txt: Added.
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html: Added.

2014-02-28 Mario Sanchez Prada <mario.prada@samsung.com>

paragraphs with different directionality in textarea with unicode-bidi: plaintext are aligned the same
@@ -0,0 +1,90 @@
This test checks that we properly recompute our internal grid when a grid item is moved.

PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
@@ -0,0 +1,190 @@
<!DOCTYPE html>
<html>
<script>
if (window.testRunner)
testRunner.overridePreference("WebKitCSSGridLayoutEnabled", 1);
</script>
<link href="resources/grid.css" rel="stylesheet">
<style type="text/css">
.grid {
-webkit-grid-template-columns: "col" 50px "col" 100px "col" 200px "col";
-webkit-grid-template-rows: "row" 70px "row" 140px "row" 280px "row";
}
.differentNamedGridLines {
-webkit-grid-template-columns: "col1" 50px "col2" 100px "col3" 200px "col4";
-webkit-grid-template-rows: "row1" 70px "row2" 140px "row3" 280px "row4";
}
</style>
<script src="../../resources/check-layout.js"></script>
<script>
function testPosition(position, size)
{
gridItem = document.getElementsByClassName("grid")[0].firstChild;
gridItem.style.webkitGridColumn = position.column;
gridItem.style.webkitGridRow = position.row;
gridItem.setAttribute("data-expected-width", size.width);
gridItem.setAttribute("data-expected-height", size.height);
checkLayout(".grid");
}

function updateGridItemPosition()
{
// Test with the same type of positions.
// 1. Explicit grid lines.
testPosition({ 'column': '1 / 2', 'row': '1 / 2' }, { 'width': '50', 'height': '70' });
testPosition({ 'column': '1 / 3', 'row': '1 / 2' }, { 'width': '150', 'height': '70' });

testPosition({ 'column': '1 / 2', 'row': '1 / 3' }, { 'width': '50', 'height': '210' });
testPosition({ 'column': '1 / 2', 'row': '1 / 2' }, { 'width': '50', 'height': '70' });

testPosition({ 'column': '2 / 3', 'row': '1 / 3' }, { 'width': '100', 'height': '210' });
testPosition({ 'column': '1 / 3', 'row': '1 / 3' }, { 'width': '150', 'height': '210' });

testPosition({ 'column': '1 / 3', 'row': '1 / 3' }, { 'width': '150', 'height': '210' });
testPosition({ 'column': '1 / 3', 'row': '2 / 3' }, { 'width': '150', 'height': '140' });

// 2. spans.
testPosition({ 'column': '1 / span 2', 'row': '1 / span 1' }, { 'width': '150', 'height': '70' });
testPosition({ 'column': '1 / span 1', 'row': '1 / span 1' }, { 'width': '50', 'height': '70' });

testPosition({ 'column': '2 / span 1', 'row': '1 / span 1' }, { 'width': '100', 'height': '70' });
testPosition({ 'column': '2 / span 1', 'row': '1 / span 2' }, { 'width': '100', 'height': '210' });

testPosition({ 'column': 'span 2 / 3', 'row': 'span 2 / 3' }, { 'width': '150', 'height': '210' });
testPosition({ 'column': 'span 1 / 3', 'row': 'span 2 / 3' }, { 'width': '100', 'height': '210' });

testPosition({ 'column': 'span 2 / 3', 'row': 'span 1 / 3' }, { 'width': '150', 'height': '140' });
testPosition({ 'column': 'span 2 / 3', 'row': 'span 2 / 3' }, { 'width': '150', 'height': '210' });

// 3. Named grid lines, changing the explicit position.
testPosition({ 'column': '1 / 2 "col"', 'row': '1 / 2 "row"' }, { 'width': '50', 'height': '70' });
testPosition({ 'column': '1 / 3 "col"', 'row': '1 / 2 "row"' }, { 'width': '150', 'height': '70' });

testPosition({ 'column': '1 / 2 "col"', 'row': '1 / 3 "row"' }, { 'width': '50', 'height': '210' });
testPosition({ 'column': '1 / 2 "col"', 'row': '1 / 2 "row"' }, { 'width': '50', 'height': '70' });

testPosition({ 'column': '1 "col" / 4', 'row': '1 "row" / 4' }, { 'width': '350', 'height': '490' });
testPosition({ 'column': '2 "col" / 4', 'row': '1 "row" / 4' }, { 'width': '300', 'height': '490' });

testPosition({ 'column': '2 "col" / 4', 'row': '2 "row" / 4' }, { 'width': '300', 'height': '420' });
testPosition({ 'column': '2 "col" / 4', 'row': '1 "row" / 4' }, { 'width': '300', 'height': '490' });

// 4. Named grid lines, changing the name of the grid lines.
testPosition({ 'column': '1 / 3 "col"', 'row': '1 / 2 "row"' }, { 'width': '150', 'height': '70' });
testPosition({ 'column': '1 / 3 "invalid"', 'row': '1 / 2 "row"' }, { 'width': '50', 'height': '70' });

testPosition({ 'column': '1 / 4 "col"', 'row': '1 / 4 "invalid"' }, { 'width': '350', 'height': '70' });
testPosition({ 'column': '1 / 4 "col"', 'row': '1 / 4 "row"' }, { 'width': '350', 'height': '490' });

testPosition({ 'column': '2 "invalid" / 4', 'row': '1 "row" / 4' }, { 'width': '350', 'height': '490' });
testPosition({ 'column': '2 "col" / 4', 'row': '1 "row" / 4' }, { 'width': '300', 'height': '490' });

testPosition({ 'column': '2 "col" / 4', 'row': '2 "row" / 4' }, { 'width': '300', 'height': '420' });
testPosition({ 'column': '2 "col" / 4', 'row': '2 "invalid" / 4' }, { 'width': '300', 'height': '490' });

// 5. Span named grid lines, changing the grid line number.
testPosition({ 'column': '1 / span 3 "col"', 'row': '1 / span 2 "row"' }, { 'width': '350', 'height': '210' });
testPosition({ 'column': '1 / span 2 "col"', 'row': '1 / span 2 "row"' }, { 'width': '150', 'height': '210' });

testPosition({ 'column': '2 / span 3 "col"', 'row': '1 / span 2 "row"' }, { 'width': '300', 'height': '210' });
testPosition({ 'column': '2 / span 3 "col"', 'row': '1 / span 1 "row"' }, { 'width': '300', 'height': '70' });

testPosition({ 'column': 'span 2 "col" / 3', 'row': 'span 2 "row" / 4' }, { 'width': '150', 'height': '420' });
testPosition({ 'column': 'span 1 "col" / 3', 'row': 'span 2 "row" / 4' }, { 'width': '100', 'height': '420' });

testPosition({ 'column': 'span 2 "col" / 3', 'row': 'span 2 "row" / 4' }, { 'width': '150', 'height': '420' });
testPosition({ 'column': 'span 2 "col" / 3', 'row': 'span 3 "row" / 4' }, { 'width': '150', 'height': '490' });

// Test transition across grid lines types.
// 1. Explicit <-> spans.
testPosition({ 'column': '1 / 3', 'row': '1 / 2' }, { 'width': '150', 'height': '70' });
testPosition({ 'column': '1 / span 3', 'row': '1 / 2' }, { 'width': '350', 'height': '70' });

testPosition({ 'column': '1 / 3', 'row': '1 / span 2' }, { 'width': '150', 'height': '210' });
testPosition({ 'column': '1 / 3', 'row': '1 / 2' }, { 'width': '150', 'height': '70' });

testPosition({ 'column': 'span 1 / 3', 'row': '1 / 2' }, { 'width': '100', 'height': '70' });
testPosition({ 'column': '1 / 3', 'row': '1 / 2' }, { 'width': '150', 'height': '70' });

testPosition({ 'column': '1 / 3', 'row': '1 / 4' }, { 'width': '150', 'height': '490' });
testPosition({ 'column': '1 / 3', 'row': 'span 2 / 4' }, { 'width': '150', 'height': '420' });

// 2. Span <-> named grid lines.
testPosition({ 'column': '1 / "col" 3', 'row': '1 / span 4' }, { 'width': '150', 'height': '490' });
testPosition({ 'column': '1 / span 3', 'row': '1 / span 4' }, { 'width': '350', 'height': '490' });

testPosition({ 'column': '1 / "col" 3', 'row': '1 / span 3' }, { 'width': '150', 'height': '490' });
testPosition({ 'column': '1 / "col" 3', 'row': '1 / "row" 3' }, { 'width': '150', 'height': '210' });

testPosition({ 'column': 'span 1 / 3', 'row': 'span 2 / 4' }, { 'width': '100', 'height': '420' });
testPosition({ 'column': '1 "col" / 3', 'row': 'span 2 / 4' }, { 'width': '150', 'height': '420' });

testPosition({ 'column': 'span 1 / 3', 'row': '"col" 1 / 4' }, { 'width': '100', 'height': '490' });
testPosition({ 'column': 'span 1 / 3', 'row': 'span 1 / 4' }, { 'width': '100', 'height': '280' });

// 3. Named grid lines to span named grid line.
testPosition({ 'column': '1 / "col" 3', 'row': '1 / span 4' }, { 'width': '150', 'height': '490' });
testPosition({ 'column': '1 / span "col" 3', 'row': '1 / span 4' }, { 'width': '350', 'height': '490' });

testPosition({ 'column': '1 / "col" 3', 'row': '1 / span "row" 3' }, { 'width': '150', 'height': '490' });
testPosition({ 'column': '1 / "col" 3', 'row': '1 / "row" 3' }, { 'width': '150', 'height': '210' });

testPosition({ 'column': 'span "col" 1 / 3', 'row': 'span 2 / 4' }, { 'width': '100', 'height': '420' });
testPosition({ 'column': '1 "col" / 3', 'row': 'span 2 / 4' }, { 'width': '150', 'height': '420' });

testPosition({ 'column': 'span "col" 1 / 3', 'row': '"col" 1 / 4' }, { 'width': '100', 'height': '490' });
testPosition({ 'column': 'span "col" 1 / 3', 'row': 'span "col" 1 / 4' }, { 'width': '100', 'height': '280' });

// 4. Explicit <-> named grid lines.
// We need to modify the grid's definitions so that we have explicit and named grid lines not match anymore.
var gridElement = document.getElementsByClassName("grid")[0];
gridElement.classList.add("differentNamedGridLines");

testPosition({ 'column': '1 / "col4" 3', 'row': '1 / 4' }, { 'width': '350', 'height': '490' });
testPosition({ 'column': '1 / 3', 'row': '1 / 4' }, { 'width': '150', 'height': '490' });

testPosition({ 'column': '1 / "col4" 3', 'row': '1 / 4' }, { 'width': '350', 'height': '490' });
testPosition({ 'column': '1 / "col4" 3', 'row': '1 / "row3" 4' }, { 'width': '350', 'height': '210' });

testPosition({ 'column': '"col2" 1 / 4', 'row': '1 "row2" / 4' }, { 'width': '300', 'height': '420' });
testPosition({ 'column': '1 / 4', 'row': '1 "row2" / 4' }, { 'width': '350', 'height': '420' });

testPosition({ 'column': '"col2" 1 / 4', 'row': '1 / 4' }, { 'width': '300', 'height': '490' });
testPosition({ 'column': '"col2" 1 / 4', 'row': '1 "row2" / 4' }, { 'width': '300', 'height': '420' });

// 5. Span <-> span named grid lines.
testPosition({ 'column': '1 / span "col4" 2', 'row': '3 / span 1' }, { 'width': '350', 'height': '280' });
testPosition({ 'column': '1 / span 2', 'row': '3 / span 1' }, { 'width': '150', 'height': '280' });

testPosition({ 'column': '1 / span "col4" 3', 'row': '1 / span 4' }, { 'width': '350', 'height': '490' });
testPosition({ 'column': '1 / span "col4" 3', 'row': '1 / span "row3" 4' }, { 'width': '350', 'height': '210' });

testPosition({ 'column': 'span 2 / 4', 'row': 'span 1 / 4' }, { 'width': '300', 'height': '280' });
testPosition({ 'column': 'span "col1" 2 / 4', 'row': 'span 1 / 4' }, { 'width': '350', 'height': '280' });

testPosition({ 'column': 'span 2 / 4', 'row': 'span 1 / 4' }, { 'width': '300', 'height': '280' });
testPosition({ 'column': 'span 2 / 4', 'row': 'span "row2" 1 / 4' }, { 'width': '300', 'height': '420' });

// 6. Explicit to span named grid line.
testPosition({ 'column': '1 / 2', 'row': '2 / span "row3" 1' }, { 'width': '50', 'height': '140' });
testPosition({ 'column': '1 / span "col3" 2', 'row': '2 / span "row3" 1' }, { 'width': '150', 'height': '140' });

testPosition({ 'column': '1 / 2', 'row': '2 / span "row3" 4' }, { 'width': '50', 'height': '140' });
testPosition({ 'column': '1 / 2', 'row': '2 / 4' }, { 'width': '50', 'height': '420' });

testPosition({ 'column': 'span "col2" 1 / 4', 'row': 'span "row1" 3 / 4' }, { 'width': '300', 'height': '490' });
testPosition({ 'column': '1 / 4', 'row': 'span "row1" 3 / 4' }, { 'width': '350', 'height': '490' });

testPosition({ 'column': 'span "col2" 1 / 4', 'row': 'span "row1" 3 / 4' }, { 'width': '300', 'height': '490' });
testPosition({ 'column': 'span "col2" 1 / 4', 'row': '3 / 4' }, { 'width': '300', 'height': '280' });
}
window.addEventListener("load", updateGridItemPosition, false);
</script>
<body>

<p>This test checks that we properly recompute our internal grid when a grid item is moved.</p>

<div class="grid"><div class="sizedToGridArea"></div></div>

</body>
</html>
@@ -0,0 +1,18 @@
This test checks that we resolve named grid line per the specification.

PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS
PASS

0 comments on commit 0cd8da1

Please sign in to comment.