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; |