diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index e1059f0b942..9f31cee5760 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -814,18 +814,54 @@ nsGridContainerFrame::PlaceGridItems(GridItemCSSOrderIterator& aIter, // http://dev.w3.org/csswg/css-grid/#line-placement // Resolve definite positions per spec chap 9.2. - for (; !aIter.AtEnd(); aIter.Next()) { - nsIFrame* child = *aIter; - const GridArea& area = PlaceDefinite(child, aStyle); - GridArea* prop = GetGridAreaForChild(child); - if (prop) { - *prop = area; - } else { - child->Properties().Set(GridAreaProperty(), new GridArea(area)); + { + nsAutoTArray areasToAdjust; + int32_t minCol = 1; + int32_t minRow = 1; + for (; !aIter.AtEnd(); aIter.Next()) { + nsIFrame* child = *aIter; + const GridArea& area = PlaceDefinite(child, aStyle); + bool adjust = false; + if (area.mCols.IsDefinite()) { + minCol = std::min(minCol, area.mCols.mStart); + adjust = true; + } + if (area.mRows.IsDefinite()) { + minRow = std::min(minRow, area.mRows.mStart); + adjust = true; + } + GridArea* prop = GetGridAreaForChild(child); + if (prop) { + *prop = area; + } else { + prop = new GridArea(area); + child->Properties().Set(GridAreaProperty(), prop); + } + if (adjust) { + areasToAdjust.AppendElement(prop); + } } - if (area.IsDefinite()) { - mCellMap.Fill(area); - InflateGridFor(area); + + // Translate the whole grid so that the top-/left-most area is at 1,1. + const uint32_t explicitGridOffsetCol = 1 - minCol; + const uint32_t explicitGridOffsetRow = 1 - minRow; + mGridColEnd += explicitGridOffsetCol; + mGridRowEnd += explicitGridOffsetRow; + mExplicitGridOffsetCol = explicitGridOffsetCol; + mExplicitGridOffsetRow = explicitGridOffsetRow; + for (GridArea* area : areasToAdjust) { + if (explicitGridOffsetCol != 0 && area->mCols.IsDefinite()) { + area->mCols.mStart += explicitGridOffsetCol; + area->mCols.mEnd += explicitGridOffsetCol; + } + if (explicitGridOffsetRow != 0 && area->mRows.IsDefinite()) { + area->mRows.mStart += explicitGridOffsetRow; + area->mRows.mEnd += explicitGridOffsetRow; + } + if (area->IsDefinite()) { + mCellMap.Fill(*area); + InflateGridFor(*area); + } } } @@ -929,9 +965,28 @@ nsGridContainerFrame::PlaceGridItems(GridItemCSSOrderIterator& aIter, // We only resolve definite lines here; we'll align auto positions to the // grid container later during reflow. nsFrameList children(GetChildList(GetAbsoluteListID())); + const uint32_t explicitGridOffsetCol = mExplicitGridOffsetCol; + const uint32_t explicitGridOffsetRow = mExplicitGridOffsetRow; + // Untranslate the grid again temporarily while resolving abs.pos. lines. + AutoRestore save1(mGridColEnd); + AutoRestore save2(mGridRowEnd); + mGridColEnd -= explicitGridOffsetCol; + mGridRowEnd -= explicitGridOffsetRow; for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); GridArea area(PlaceAbsPos(child, aStyle)); + if (area.mCols.mStart != kAutoLine) { + area.mCols.mStart += explicitGridOffsetCol; + } + if (area.mCols.mEnd != kAutoLine) { + area.mCols.mEnd += explicitGridOffsetCol; + } + if (area.mRows.mStart != kAutoLine) { + area.mRows.mStart += explicitGridOffsetRow; + } + if (area.mRows.mEnd != kAutoLine) { + area.mRows.mEnd += explicitGridOffsetRow; + } GridArea* prop = GetGridAreaForChild(child); if (prop) { *prop = area; @@ -980,17 +1035,24 @@ InitializeTrackSizes(nscoord aPercentageBasis, const nsTArray& aMaxSizingFunctions, const nsStyleCoord& aAutoMinFunction, const nsStyleCoord& aAutoMaxFunction, + uint32_t aExplicitGridOffset, nsTArray& aResults) { - MOZ_ASSERT(aResults.Length() >= aMinSizingFunctions.Length()); + MOZ_ASSERT(aResults.Length() >= aExplicitGridOffset + aMinSizingFunctions.Length()); MOZ_ASSERT(aMinSizingFunctions.Length() == aMaxSizingFunctions.Length()); - const size_t len = aMinSizingFunctions.Length(); size_t i = 0; - for (; i < len; ++i) { + for (; i < aExplicitGridOffset; ++i) { InitializeTrackSize(aPercentageBasis, - aMinSizingFunctions[i], aMaxSizingFunctions[i], + aAutoMinFunction, aAutoMaxFunction, &aResults[i]); } + size_t j = 0; + for (const size_t len = aMinSizingFunctions.Length(); j < len; ++j) { + InitializeTrackSize(aPercentageBasis, + aMinSizingFunctions[j], aMaxSizingFunctions[j], + &aResults[i + j]); + } + i += j; for (; i < aResults.Length(); ++i) { InitializeTrackSize(aPercentageBasis, aAutoMinFunction, aAutoMaxFunction, @@ -1012,12 +1074,14 @@ nsGridContainerFrame::CalculateTrackSizes(const LogicalSize& aPercentageBasis, aStyle->mGridTemplateColumns.mMaxTrackSizingFunctions, aStyle->mGridAutoColumnsMin, aStyle->mGridAutoColumnsMax, + mExplicitGridOffsetCol, aColSizes); InitializeTrackSizes(aPercentageBasis.BSize(wm), aStyle->mGridTemplateRows.mMinTrackSizingFunctions, aStyle->mGridTemplateRows.mMaxTrackSizingFunctions, aStyle->mGridAutoRowsMin, aStyle->mGridAutoRowsMax, + mExplicitGridOffsetRow, aRowSizes); } diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h index c825ea3c03b..5e83b1c7144 100644 --- a/layout/generic/nsGridContainerFrame.h +++ b/layout/generic/nsGridContainerFrame.h @@ -353,6 +353,10 @@ protected: { mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd()); mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd()); + MOZ_ASSERT(mGridColEnd <= uint32_t(nsStyleGridLine::kMaxLine - + nsStyleGridLine::kMinLine) && + mGridRowEnd <= uint32_t(nsStyleGridLine::kMaxLine - + nsStyleGridLine::kMinLine)); } /** @@ -465,6 +469,16 @@ private: // Same for the implicit grid uint32_t mGridColEnd; // always >= mExplicitGridColEnd uint32_t mGridRowEnd; // always >= mExplicitGridRowEnd + + /** + * Offsets from the start of the implicit grid to the start of the translated + * explicit grid. They are zero if there are no implicit lines before 1,1. + * e.g. "grid-column: span 3 / 1" makes mExplicitGridOffsetCol = 3 and the + * corresponding GridArea::mCols will be 1 / 4 in the translated grid. + */ + uint32_t mExplicitGridOffsetCol; + uint32_t mExplicitGridOffsetRow; + /** * True iff the normal flow children are already in CSS 'order' in the * order they occur in the child frame list.