[css-grid] Use grid area position to determine overflowing items

Grid code keeps a list of items overflowing their grid areas so that it
could apply some painting optimizations to reduce the amount of grid items
to be painted. Even if the border box is completely contained by the
item's grid area, margins in the item could make it overflow its grid area
by altering the border box position.

The problem is not that the optimization won't work, it's worse because it will
make that item not visible as it won't be painted.

BUG=628155

Review-Url: https://codereview.chromium.org/2353513003
Cr-Commit-Position: refs/heads/master@{#420094}
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area-expected.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area-expected.html
new file mode 100644
index 0000000..80ac2cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area-expected.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+
+<p>Test PASS if you see two adjacent iframes with a 50x50 green square.</p>
+
+<iframe height="120px" width="300px" srcdoc="
+     <div style='background: green;  width: 50px; height: 50px; margin-left: 100px;'></div>
+     ">
+</iframe>
+
+<iframe height="120px" width="300px" srcdoc="
+     <div style='background: green; width: 50px; height: 50px; margin-left: 134px;'></div>
+     ">
+</iframe>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area.html
new file mode 100644
index 0000000..4ded6ac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+<p>Test PASS if you see two adjacent iframes with a 50x50 green square.</p>
+
+<iframe height="120px" width="300px" srcdoc="
+     <style>
+     .grid {
+         display: grid;
+         grid: 50px / 100px 50px 150px 100px;
+     }
+     </style>
+
+     <div class='grid'>
+         <div style='background: red; grid-column: 2;'></div>
+         <div style='background: green;  grid-column: 4; width: 50px; margin-left: -200px;'></div>
+     </div>
+     ">
+</iframe>
+
+<iframe height="120px" width="300px" srcdoc="
+     <style>
+     .grid {
+         display: grid;
+         grid: 50px / 100px 50px 150px 100px;
+         direction: rtl;
+     }
+     </style>
+
+     <div class='grid'>
+         <div style='background: red; grid-column: 2;'></div>
+         <div style='background: green;  grid-column: 4; width: 50px; margin-right: -200px;'></div>
+     </div>
+     ">
+</iframe>
+
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index ec13d19..5214d40b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -1922,8 +1922,8 @@
         updateAutoMarginsInColumnAxisIfNeeded(*child);
         updateAutoMarginsInRowAxisIfNeeded(*child);
 
-#if ENABLE(ASSERT)
         const GridArea& area = cachedGridArea(*child);
+#if ENABLE(ASSERT)
         ASSERT(area.columns.startLine() < sizingData.columnTracks.size());
         ASSERT(area.rows.startLine() < sizingData.rowTracks.size());
 #endif
@@ -1931,10 +1931,10 @@
 
         // Keep track of children overflowing their grid area as we might need to paint them even if the grid-area is not visible.
         // Using physical dimensions for simplicity, so we can forget about orthogonalty.
-        // TODO (lajava): Child's margins should account when evaluating whether it overflows its grid area (http://crbug.com/628155).
         LayoutUnit childGridAreaHeight = isHorizontalWritingMode() ? overrideContainingBlockContentLogicalHeight : overrideContainingBlockContentLogicalWidth;
         LayoutUnit childGridAreaWidth = isHorizontalWritingMode() ? overrideContainingBlockContentLogicalWidth : overrideContainingBlockContentLogicalHeight;
-        if (child->size().height() > childGridAreaHeight || child->size().width() > childGridAreaWidth)
+        LayoutRect gridAreaRect(gridAreaLogicalPosition(area), LayoutSize(childGridAreaWidth, childGridAreaHeight));
+        if (!gridAreaRect.contains(child->frameRect()))
             m_gridItemsOverflowingGridArea.append(child);
     }
 }
@@ -2661,6 +2661,16 @@
     return isOrthogonalChild(child) ? childLocation.transposedPoint() : childLocation;
 }
 
+LayoutPoint LayoutGrid::gridAreaLogicalPosition(const GridArea& area) const
+{
+    LayoutUnit columnAxisOffset = m_rowPositions[area.rows.startLine()];
+    LayoutUnit rowAxisOffset = m_columnPositions[area.columns.startLine()];
+
+    // See comment in findChildLogicalPosition() about why we need sometimes to translate from RTL
+    // to LTR the rowAxisOffset coordinate.
+    return LayoutPoint(style()->isLeftToRightDirection() ? rowAxisOffset : translateRTLCoordinate(rowAxisOffset), columnAxisOffset);
+}
+
 void LayoutGrid::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const
 {
     if (!m_gridItemArea.isEmpty())
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h
index b83b4fc..90a9069 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.h
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -177,6 +177,7 @@
     LayoutUnit rowAxisOffsetForChild(const LayoutBox&, GridSizingData&) const;
     LayoutUnit columnAxisOffsetForChild(const LayoutBox&, GridSizingData&) const;
     ContentAlignmentData computeContentPositionAndDistributionOffset(GridTrackSizingDirection, const LayoutUnit& availableFreeSpace, unsigned numberOfGridTracks) const;
+    LayoutPoint gridAreaLogicalPosition(const GridArea&) const;
     LayoutPoint findChildLogicalPosition(const LayoutBox&, GridSizingData&) const;
     GridArea cachedGridArea(const LayoutBox&) const;
     GridSpan cachedGridSpan(const LayoutBox&, GridTrackSizingDirection) const;