Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1081)

Unified Diff: third_party/WebKit/Source/core/layout/LayoutGrid.cpp

Issue 1407633003: [css-grid] Implementation of Baseline Self-Alignment (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Preliminary approach. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/layout/LayoutGrid.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/layout/LayoutGrid.cpp
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index e828f0b9b611de39ddced39a99e6c766aafd4ba1..53156bc714211bedd23e489921dcc0c3593ab9f3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -142,6 +142,68 @@ public:
LayoutUnit distributionOffset = -1;
};
+class BaselineGroup {
cbiesinger 2015/10/26 22:07:16 For this class and BaselineContext, can you add a
jfernandez 2015/10/27 09:47:56 Done.
+public:
+ BaselineGroup(LayoutBox* child, LayoutUnit childAscent, ItemPosition preference)
+ {
+ ASSERT(preference == ItemPositionBaseline || preference == ItemPositionLastBaseline);
+ add(child, childAscent);
+ groupPreference = preference;
+ groupWritingMode = child->styleRef().writingMode();
+ }
+
+ static bool oppositeBlockDirection(WritingMode childBlockDirection, WritingMode groupBlockDirection)
+ {
+ return (childBlockDirection == TopToBottomWritingMode && groupBlockDirection == BottomToTopWritingMode)
+ || (childBlockDirection == BottomToTopWritingMode && groupBlockDirection == TopToBottomWritingMode)
+ || (childBlockDirection == LeftToRightWritingMode && groupBlockDirection == RightToLeftWritingMode)
+ || (childBlockDirection == RightToLeftWritingMode && groupBlockDirection == LeftToRightWritingMode);
+ }
+
+ bool isCompatibleChild(LayoutBox* child, ItemPosition preference)
+ {
+ return (child->styleRef().writingMode() == groupWritingMode && preference == groupPreference)
+ || (oppositeBlockDirection(child->styleRef().writingMode(), groupWritingMode) && preference != groupPreference);
cbiesinger 2015/10/26 22:07:16 I don't think I fully understand what this is nece
jfernandez 2015/10/27 09:47:56 The CSS Box Alignment spec defines when a group of
cbiesinger 2015/10/27 21:52:30 Oh, thanks for the explanation. I should have chec
+ }
+
+ void add(LayoutBox* child, LayoutUnit childAscent)
+ {
+ ASSERT(child);
+ children.append(child);
+ groupMaxAscent = std::max(groupMaxAscent, childAscent);
+ }
+
+ Vector<LayoutBox*> children;
cbiesinger 2015/10/26 22:07:17 Why not the m_children style for member variables?
jfernandez 2015/10/27 09:47:56 Acknowledged.
+ ItemPosition groupPreference;
+ WritingMode groupWritingMode;
+ LayoutUnit groupMaxAscent;
+};
+
+class BaselineContext {
+public:
+ BaselineContext() { }
+
+ BaselineContext(LayoutBox* child, LayoutUnit maxAscent, ItemPosition preference)
+ {
+ sharedGroups.append(BaselineGroup(child, maxAscent, preference));
+ }
+
+ void addGroupMember(LayoutBox* child, LayoutUnit childAscent, ItemPosition preference)
+ {
+ bool compatibleGroupFound = false;
+ for (auto& group : sharedGroups) {
+ if ((compatibleGroupFound = group.isCompatibleChild(child, preference))) {
+ group.add(child, childAscent);
+ break;
+ }
+ }
+ if (!compatibleGroupFound)
+ sharedGroups.append(BaselineGroup(child, childAscent, preference));
+ }
+
+ Vector<BaselineGroup> sharedGroups;
+};
+
enum TrackSizeRestriction {
AllowInfinity,
ForbidInfinity,
@@ -226,6 +288,8 @@ private:
size_t m_childIndex;
};
+typedef HashMap<unsigned, BaselineContext, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> BaselineContextsMap;
+
struct LayoutGrid::GridSizingData {
WTF_MAKE_NONCOPYABLE(GridSizingData);
STACK_ALLOCATED();
@@ -240,6 +304,8 @@ public:
Vector<GridTrack> rowTracks;
Vector<size_t> contentSizedTracksIndex;
+ BaselineContextsMap rowAxisAlignmentContext;
+
// Performance optimization: hold onto these Vectors until the end of Layout to avoid repeated malloc / free.
Vector<GridTrack*> filteredTracks;
Vector<GridItemWithSpan> itemsSortedByIncreasingSpan;
@@ -1334,6 +1400,8 @@ void LayoutGrid::layoutGridItems()
child->layoutIfNeeded();
+ updateBaselineAlignmentContextInRowAxisIfNeeded(child, sizingData);
+
// We need pending layouts to be done in order to compute auto-margins properly.
updateAutoMarginsInColumnAxisIfNeeded(*child);
updateAutoMarginsInRowAxisIfNeeded(*child);
@@ -1352,6 +1420,8 @@ void LayoutGrid::layoutGridItems()
m_gridItemsOverflowingGridArea.append(child);
}
+ applyBaselineAlignmentIfNeeded(sizingData);
+
for (const auto& row : sizingData.rowTracks)
setLogicalHeight(logicalHeight() + row.baseSize());
@@ -1709,6 +1779,120 @@ void LayoutGrid::updateAutoMarginsInColumnAxisIfNeeded(LayoutBox& child)
}
}
+void LayoutGrid::updateBaselineAlignmentContextInRowAxisIfNeeded(LayoutBox* child, GridSizingData& sizingData) const
+{
+ ItemPosition align = ComputedStyle::resolveAlignment(styleRef(), child->styleRef(), ItemPositionStretch);
+ if ((align != ItemPositionBaseline && align != ItemPositionLastBaseline) || hasAutoMarginsInColumnAxis(*child))
+ return;
+
+ const GridCoordinate& coordinate = cachedGridCoordinate(*child);
+ unsigned lineNumber = coordinate.rows.resolvedInitialPosition.toInt();
+ LayoutUnit ascent = marginBoxAscentFromBaselineForChild(*child);
+ bool contextExists = sizingData.rowAxisAlignmentContext.contains(lineNumber);
+ BaselineContext context = contextExists ? sizingData.rowAxisAlignmentContext.get(lineNumber) : BaselineContext(child, ascent, align);
+ if (contextExists)
+ context.addGroupMember(child, ascent, align);
+ sizingData.rowAxisAlignmentContext.set(lineNumber, context);
+}
+
+// FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
+LayoutUnit LayoutGrid::marginBoxAscentFromBaselineForChild(const LayoutBox& child) const
+{
+ LayoutUnit baseline = child.firstLineBoxBaseline();
+ // We take content-box's bottom if no valid baseline.
+ if (baseline == -1)
+ baseline = LayoutBlock::logicalHeightForChild(child);
+ return baseline + marginBeforeForChild(child);
+}
+
+void LayoutGrid::applyBaselineAlignmentIfNeeded(const GridSizingData& sizingData)
+{
+ for (auto& contexts : sizingData.rowAxisAlignmentContext.values()) {
+ for (auto& group : contexts.sharedGroups) {
+ for (LayoutBox* child : group.children) {
+ ItemPosition align = ComputedStyle::resolveAlignment(styleRef(), child->styleRef(), ItemPositionStretch);
+ // TODO (lajava): implement last-baseline logic here.
+ if (align == ItemPositionBaseline) {
+ LayoutUnit ascent = marginBoxAscentFromBaselineForChild(*child);
+ LayoutUnit startOffset = group.groupMaxAscent - ascent;
+ LayoutPoint location(isHorizontalWritingMode() ? child->location() : child->location().transposedPoint());
+ child->setLogicalLocation(location + LayoutSize(0, startOffset));
+ }
+ }
+ }
+ }
+}
+
+static int synthesizedBaselineFromContentBox(const LayoutBox& box, LineDirectionMode direction)
+{
+ if (direction == HorizontalLine)
+ return box.size().height() - box.borderBottom() - box.paddingBottom() - box.verticalScrollbarWidth();
+ return box.size().width() - box.borderLeft() - box.paddingLeft() - box.horizontalScrollbarHeight();
+}
+
+int LayoutGrid::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
+{
+ ASSERT(mode == PositionOnContainingLine);
+ int baseline = firstLineBoxBaseline();
+ // We take content-box's bottom if no valid baseline.
+ if (baseline == -1)
+ baseline = synthesizedBaselineFromContentBox(*this, direction);
+
+ return baseline + beforeMarginInLineDirection(direction);
+}
+
+int LayoutGrid::firstLineBoxBaseline() const
+{
+ if (isWritingModeRoot())
+ return -1;
+ LayoutBox* baselineChild = nullptr;
+ for (LayoutBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
+ if (child->isOutOfFlowPositioned())
+ continue;
+ const GridCoordinate& coordinate = cachedGridCoordinate(*child);
+ // TODO (lajava): propertly identifying grid items whose areas intersect the grid container's first row/column.
+ if (coordinate.rows.resolvedInitialPosition.toInt() > 0 && coordinate.columns.resolvedInitialPosition.toInt() > 0)
+ break;
+ ItemPosition align = ComputedStyle::resolveAlignment(styleRef(), child->styleRef(), ItemPositionStretch);
+ // Orthogonal children don't participate in baseline alignment.
+ bool isOrthogonal = child->isHorizontalWritingMode() != isHorizontalWritingMode();
+ if (align == ItemPositionBaseline && !isOrthogonal && !hasAutoMarginsInColumnAxis(*child)) {
+ baselineChild = child;
+ break;
+ }
+ if (!baselineChild)
+ baselineChild = child;
+ }
+
+ if (!baselineChild)
+ return -1;
+
+ // Using a synthesized baseline (content-box's bottom) if baselineChild has an orthogonal writing mode.
+ // TODO (lajava) We still don't support orthogonal modes in grid.
+ if (baselineChild->isHorizontalWritingMode() != isHorizontalWritingMode())
+ return -1;
+
+ int baseline = baselineChild->firstLineBoxBaseline();
+ if (baseline == -1) {
+ // TODO (lajava): We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
+ // This would also fix some cases where the grid is orthogonal to its container.
+ LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
+ return synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop();
+ }
+
+ return baseline + baselineChild->logicalTop();
+}
+
+int LayoutGrid::inlineBlockBaseline(LineDirectionMode direction) const
+{
+ int baseline = firstLineBoxBaseline();
+ if (baseline != -1)
+ return baseline;
+
+ int marginHeight = direction == HorizontalLine ? marginTop() : marginRight();
+ return synthesizedBaselineFromContentBox(*this, direction) + marginHeight;
+}
+
GridAxisPosition LayoutGrid::columnAxisPositionForChild(const LayoutBox& child) const
{
bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizontalWritingMode();
@@ -1747,8 +1931,6 @@ GridAxisPosition LayoutGrid::columnAxisPositionForChild(const LayoutBox& child)
return GridAxisStart;
case ItemPositionBaseline:
case ItemPositionLastBaseline:
- // FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
- // crbug.com/234191
return GridAxisStart;
case ItemPositionAuto:
break;
@@ -1790,8 +1972,6 @@ GridAxisPosition LayoutGrid::rowAxisPositionForChild(const LayoutBox& child) con
return GridAxisStart;
case ItemPositionBaseline:
case ItemPositionLastBaseline:
- // FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
- // crbug.com/234191
return GridAxisStart;
case ItemPositionAuto:
break;
« no previous file with comments | « third_party/WebKit/Source/core/layout/LayoutGrid.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698