| 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 bd8979ab203b0323eba79b481873d18ef48f7ffd..468cf1bd433ebf563134ccae220b157194335d01 100644
|
| --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
|
| +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
|
| @@ -33,6 +33,7 @@
|
| #include "core/style/ComputedStyle.h"
|
| #include "core/style/GridArea.h"
|
| #include "platform/LengthFunctions.h"
|
| +#include "platform/text/WritingMode.h"
|
| #include "wtf/PtrUtil.h"
|
| #include <algorithm>
|
| #include <memory>
|
| @@ -583,9 +584,40 @@ void LayoutGrid::repeatTracksSizingIfNeeded(GridSizingData& sizingData,
|
| LayoutUnit availableSpaceForRows) {
|
| DCHECK(sizingData.sizingState > GridSizingData::RowSizingFirstIteration);
|
|
|
| + // Baseline alignment may change item's intrinsic size, hence changing its
|
| + // min-content contribution.
|
| + // https://drafts.csswg.org/css-align-3/#baseline-align-content
|
| + // https://drafts.csswg.org/css-align-3/#baseline-align-self
|
| + bool baselineAffectIntrinsicWidth = baselineMayAffectIntrinsicWidth();
|
| + bool baselineAffectIntrinsicHeight = baselineMayAffectIntrinsicHeight();
|
| +
|
| // In orthogonal flow cases column track's size is determined by using the
|
| // computed row track's size, which it was estimated during the first cycle of
|
| // the sizing algorithm.
|
| + bool hasAnyOrthogonal = sizingData.grid().hasAnyOrthogonalGridItem();
|
| +
|
| + bool intrinsicWidthMayHaveChanged =
|
| + baselineAffectIntrinsicWidth || hasAnyOrthogonal;
|
| + if (!intrinsicWidthMayHaveChanged && !baselineAffectIntrinsicHeight)
|
| + return;
|
| +
|
| + // Compute again the intrinsic size if baseline changed item's min-content
|
| + // contribution.
|
| + if (intrinsicWidthMayHaveChanged) {
|
| + if (hasAnyOrthogonal) {
|
| + for (auto* child = firstInFlowChildBox(); child;
|
| + child = child->nextInFlowSiblingBox()) {
|
| + if (isOrthogonalChild(*child) &&
|
| + updateOverrideContainingBlockContentSizeForChild(*child, ForRows,
|
| + sizingData))
|
| + child->forceLayout();
|
| + }
|
| + }
|
| + setPreferredLogicalWidthsDirty(MarkContainerChain);
|
| + updateLogicalWidth();
|
| + availableSpaceForColumns = availableLogicalWidth();
|
| + }
|
| +
|
| // Hence we need to repeat computeUsedBreadthOfGridTracks for both, columns
|
| // and rows, to determine the final values.
|
| // TODO (lajava): orthogonal flows is just one of the cases which may require
|
| @@ -593,11 +625,14 @@ void LayoutGrid::repeatTracksSizingIfNeeded(GridSizingData& sizingData,
|
| // all the cases with orthogonal flows require this extra cycle; we need a
|
| // more specific condition to detect whether child's min-content contribution
|
| // has changed or not.
|
| - if (sizingData.grid().hasAnyOrthogonalGridItem()) {
|
| - computeTrackSizesForDefiniteSize(ForColumns, sizingData,
|
| - availableSpaceForColumns);
|
| - computeTrackSizesForDefiniteSize(ForRows, sizingData,
|
| - availableSpaceForRows);
|
| + computeTrackSizesForDefiniteSize(ForColumns, sizingData,
|
| + availableSpaceForColumns);
|
| + computeTrackSizesForDefiniteSize(ForRows, sizingData, availableSpaceForRows);
|
| +
|
| + if (baselineAffectIntrinsicHeight) {
|
| + setLogicalHeight(computeTrackBasedLogicalHeight(sizingData) +
|
| + borderAndPaddingLogicalHeight() +
|
| + scrollbarLogicalHeight());
|
| }
|
| }
|
|
|
| @@ -611,6 +646,9 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) {
|
| simplifiedLayout())
|
| return;
|
|
|
| + m_rowAxisAlignmentContext.clear();
|
| + m_colAxisAlignmentContext.clear();
|
| +
|
| SubtreeLayoutScope layoutScope(*this);
|
|
|
| {
|
| @@ -681,6 +719,15 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) {
|
| if (!cachedHasDefiniteLogicalHeight())
|
| sizingData.freeSpace(ForRows) = logicalHeight() - trackBasedLogicalHeight;
|
|
|
| + // TODO (lajava): We need to compute baselines after step 2 so
|
| + // items with a relative size (percentages) can resolve it before
|
| + // determining its baseline. However, we only set item's grid area
|
| + // (via override sizes) as part of the content-sized tracks sizing
|
| + // logic. Hence, items located at fixed or flexible tracks can't
|
| + // resolve correctly their size at this stage, which may lead to
|
| + // an incorrect computation of their shared context's baseline.
|
| + computeBaselineAlignmentContext(sizingData);
|
| +
|
| // 3- If the min-content contribution of any grid items have changed based
|
| // on the row sizes calculated in step 2, steps 1 and 2 are repeated with
|
| // the new min-content contribution (once only).
|
| @@ -1324,6 +1371,13 @@ LayoutUnit LayoutGrid::logicalHeightForChild(LayoutBox& child,
|
| child.clearOverrideLogicalContentHeight();
|
|
|
| child.layoutIfNeeded();
|
| + GridAxis baselineAxis =
|
| + isOrthogonalChild(child) ? GridRowAxis : GridColumnAxis;
|
| + if (isBaselineAlignmentForChild(child, baselineAxis) &&
|
| + isBaselineContextComputed(baselineAxis)) {
|
| + auto& group = getBaselineGroupForChild(child, sizingData, baselineAxis);
|
| + return group.maxAscent() + group.maxDescent();
|
| + }
|
| return child.logicalHeight() + child.marginLogicalHeight();
|
| }
|
|
|
| @@ -1427,6 +1481,11 @@ LayoutUnit LayoutGrid::minContentForChild(LayoutBox& child,
|
| if (direction == ForColumns &&
|
| sizingData.sizingOperation == IntrinsicSizeComputation) {
|
| DCHECK(isOrthogonalChild(child));
|
| + if (isBaselineAlignmentForChild(child, GridRowAxis) &&
|
| + isBaselineContextComputed(GridRowAxis)) {
|
| + auto& group = getBaselineGroupForChild(child, sizingData, GridRowAxis);
|
| + return group.maxAscent() + group.maxDescent();
|
| + }
|
| return child.logicalHeight() + child.marginLogicalHeight();
|
| }
|
|
|
| @@ -3089,8 +3148,6 @@ static int synthesizedBaselineFromBorderBox(const LayoutBox& box,
|
| .toInt();
|
| }
|
|
|
| -// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it might be
|
| -// refactored somehow.
|
| int LayoutGrid::baselinePosition(FontBaseline,
|
| bool,
|
| LineDirectionMode direction,
|
| @@ -3104,11 +3161,6 @@ int LayoutGrid::baselinePosition(FontBaseline,
|
| return baseline + beforeMarginInLineDirection(direction);
|
| }
|
|
|
| -bool LayoutGrid::isInlineBaselineAlignedChild(const LayoutBox* child) const {
|
| - return alignSelfForChild(*child).position() == ItemPositionBaseline &&
|
| - !isOrthogonalChild(*child) && !hasAutoMarginsInColumnAxis(*child);
|
| -}
|
| -
|
| int LayoutGrid::firstLineBoxBaseline() const {
|
| if (isWritingModeRoot() || !m_grid.hasGridItems())
|
| return -1;
|
| @@ -3121,8 +3173,8 @@ int LayoutGrid::firstLineBoxBaseline() const {
|
| for (size_t index = 0; index < m_grid.cell(0, column).size(); index++) {
|
| const LayoutBox* child = m_grid.cell(0, column)[index];
|
| DCHECK(!child->isOutOfFlowPositioned());
|
| - // If an item participates in baseline alignmen, we select such item.
|
| - if (isInlineBaselineAlignedChild(child)) {
|
| + // If an item participates in baseline alignment, we select such item.
|
| + if (isBaselineAlignmentForChild(*child)) {
|
| // TODO (lajava): self-baseline and content-baseline alignment
|
| // still not implemented.
|
| baselineChild = child;
|
| @@ -3172,6 +3224,189 @@ int LayoutGrid::inlineBlockBaseline(LineDirectionMode direction) const {
|
| return synthesizedBaselineFromContentBox(*this, direction) + marginHeight;
|
| }
|
|
|
| +bool LayoutGrid::isHorizontalGridAxis(GridAxis axis) const {
|
| + return axis == GridRowAxis ? isHorizontalWritingMode()
|
| + : !isHorizontalWritingMode();
|
| +}
|
| +
|
| +bool LayoutGrid::isParallelToBlockAxisForChild(const LayoutBox& child,
|
| + GridAxis axis) const {
|
| + return axis == GridColumnAxis ? !isOrthogonalChild(child)
|
| + : isOrthogonalChild(child);
|
| +}
|
| +
|
| +bool LayoutGrid::isDescentBaselineForChild(const LayoutBox& child,
|
| + GridAxis baselineAxis) const {
|
| + return isHorizontalGridAxis(baselineAxis) &&
|
| + !styleRef().isFlippedBlocksWritingMode();
|
| +}
|
| +
|
| +bool LayoutGrid::isBaselineAlignmentForChild(const LayoutBox& child,
|
| + GridAxis baselineAxis) const {
|
| + bool isColumnAxisBaseline = baselineAxis == GridColumnAxis;
|
| + ItemPosition align = isColumnAxisBaseline
|
| + ? alignSelfForChild(child).position()
|
| + : justifySelfForChild(child).position();
|
| + bool hasAutoMargins = isColumnAxisBaseline ? hasAutoMarginsInColumnAxis(child)
|
| + : hasAutoMarginsInRowAxis(child);
|
| + return isBaselinePosition(align) && !hasAutoMargins;
|
| +}
|
| +
|
| +const BaselineGroup& LayoutGrid::getBaselineGroupForChild(
|
| + const LayoutBox& child,
|
| + const GridSizingData& sizingData,
|
| + GridAxis baselineAxis) const {
|
| + DCHECK(isBaselineAlignmentForChild(child, baselineAxis));
|
| + auto& grid = sizingData.grid();
|
| + bool isColumnAxisBaseline = baselineAxis == GridColumnAxis;
|
| + bool isRowAxisContext = isColumnAxisBaseline;
|
| + const auto& span = isRowAxisContext ? grid.gridItemSpan(child, ForRows)
|
| + : grid.gridItemSpan(child, ForColumns);
|
| + auto& contextsMap =
|
| + isRowAxisContext ? m_rowAxisAlignmentContext : m_colAxisAlignmentContext;
|
| + auto* context = contextsMap.get(span.startLine());
|
| + DCHECK(context);
|
| + ItemPosition align = isColumnAxisBaseline
|
| + ? alignSelfForChild(child).position()
|
| + : justifySelfForChild(child).position();
|
| + return context->getSharedGroup(child, align);
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::marginOverForChild(const LayoutBox& child,
|
| + GridAxis axis) const {
|
| + return isHorizontalGridAxis(axis) ? child.marginRight() : child.marginTop();
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::logicalAscentForChild(const LayoutBox& child,
|
| + GridAxis baselineAxis) const {
|
| + LayoutUnit ascent = ascentForChild(child, baselineAxis);
|
| + return isDescentBaselineForChild(child, baselineAxis)
|
| + ? descentForChild(child, ascent, baselineAxis)
|
| + : ascent;
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::ascentForChild(const LayoutBox& child,
|
| + GridAxis baselineAxis) const {
|
| + int baseline = isParallelToBlockAxisForChild(child, baselineAxis)
|
| + ? child.firstLineBoxBaseline()
|
| + : -1;
|
| + // We take border-box's bottom if no valid baseline.
|
| + if (baseline == -1) {
|
| + baseline = isHorizontalGridAxis(baselineAxis)
|
| + ? child.size().width().toInt()
|
| + : child.size().height().toInt();
|
| + }
|
| + return LayoutUnit(baseline) + marginOverForChild(child, baselineAxis);
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::descentForChild(const LayoutBox& child,
|
| + LayoutUnit ascent,
|
| + GridAxis baselineAxis) const {
|
| + if (isParallelToBlockAxisForChild(child, baselineAxis))
|
| + return child.marginLogicalHeight() + child.logicalHeight() - ascent;
|
| + return child.marginLogicalWidth() + child.logicalWidth() - ascent;
|
| +}
|
| +
|
| +bool LayoutGrid::isBaselineContextComputed(GridAxis baselineAxis) const {
|
| + return baselineAxis == GridColumnAxis ? !m_rowAxisAlignmentContext.isEmpty()
|
| + : !m_colAxisAlignmentContext.isEmpty();
|
| +}
|
| +
|
| +bool LayoutGrid::baselineMayAffectIntrinsicWidth() const {
|
| + if (!styleRef().logicalWidth().isIntrinsicOrAuto())
|
| + return false;
|
| + for (const auto& context : m_colAxisAlignmentContext) {
|
| + for (const auto& group : context.value->sharedGroups()) {
|
| + if (group.size() > 1)
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool LayoutGrid::baselineMayAffectIntrinsicHeight() const {
|
| + if (!styleRef().logicalHeight().isIntrinsicOrAuto())
|
| + return false;
|
| + for (const auto& context : m_rowAxisAlignmentContext) {
|
| + for (const auto& group : context.value->sharedGroups()) {
|
| + if (group.size() > 1)
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void LayoutGrid::computeBaselineAlignmentContext(GridSizingData& sizingData) {
|
| + for (auto* child = firstInFlowChildBox(); child;
|
| + child = child->nextInFlowSiblingBox()) {
|
| + updateBaselineAlignmentContextIfNeeded(*child, sizingData, GridRowAxis);
|
| + updateBaselineAlignmentContextIfNeeded(*child, sizingData, GridColumnAxis);
|
| + }
|
| +}
|
| +
|
| +void LayoutGrid::updateBaselineAlignmentContextIfNeeded(
|
| + LayoutBox& child,
|
| + GridSizingData& sizingData,
|
| + GridAxis baselineAxis) {
|
| + DCHECK_EQ(sizingData.sizingOperation, TrackSizing);
|
| + if (!isBaselineAlignmentForChild(child, baselineAxis))
|
| + return;
|
| +
|
| + child.layoutIfNeeded();
|
| +
|
| + // Determine Ascent and Descent values of this child with respect to
|
| + // its grid container.
|
| + LayoutUnit ascent = ascentForChild(child, baselineAxis);
|
| + LayoutUnit descent = descentForChild(child, ascent, baselineAxis);
|
| + if (isDescentBaselineForChild(child, baselineAxis))
|
| + std::swap(ascent, descent);
|
| +
|
| + // Looking up for a shared alignment context perpendicular to the
|
| + // baseline axis.
|
| + auto& grid = sizingData.grid();
|
| + bool isColumnAxisBaseline = baselineAxis == GridColumnAxis;
|
| + bool isRowAxisContext = isColumnAxisBaseline;
|
| + const auto& span = isRowAxisContext ? grid.gridItemSpan(child, ForRows)
|
| + : grid.gridItemSpan(child, ForColumns);
|
| + auto& contextsMap =
|
| + isRowAxisContext ? m_rowAxisAlignmentContext : m_colAxisAlignmentContext;
|
| + auto addResult = contextsMap.add(span.startLine(), nullptr);
|
| +
|
| + // Looking for a compatible baseline-sharing group.
|
| + ItemPosition align = isColumnAxisBaseline
|
| + ? alignSelfForChild(child).position()
|
| + : justifySelfForChild(child).position();
|
| + if (addResult.isNewEntry) {
|
| + addResult.storedValue->value =
|
| + WTF::makeUnique<BaselineContext>(child, align, ascent, descent);
|
| + } else {
|
| + auto* context = addResult.storedValue->value.get();
|
| + context->updateSharedGroup(child, align, ascent, descent);
|
| + }
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::columnAxisBaselineOffsetForChild(
|
| + const LayoutBox& child,
|
| + const GridSizingData& sizingData) const {
|
| + if (!isBaselineAlignmentForChild(child, GridColumnAxis))
|
| + return LayoutUnit();
|
| + auto& group = getBaselineGroupForChild(child, sizingData, GridColumnAxis);
|
| + if (group.size() > 1)
|
| + return group.maxAscent() - logicalAscentForChild(child, GridColumnAxis);
|
| + return LayoutUnit();
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::rowAxisBaselineOffsetForChild(
|
| + const LayoutBox& child,
|
| + const GridSizingData& sizingData) const {
|
| + if (!isBaselineAlignmentForChild(child, GridRowAxis))
|
| + return LayoutUnit();
|
| + auto& group = getBaselineGroupForChild(child, sizingData, GridRowAxis);
|
| + if (group.size() > 1)
|
| + return group.maxAscent() - logicalAscentForChild(child, GridRowAxis);
|
| + return LayoutUnit();
|
| +}
|
| +
|
| GridAxisPosition LayoutGrid::columnAxisPositionForChild(
|
| const LayoutBox& child) const {
|
| bool hasSameWritingMode =
|
| @@ -3241,8 +3476,6 @@ GridAxisPosition LayoutGrid::columnAxisPositionForChild(
|
| 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:
|
| case ItemPositionNormal:
|
| @@ -3320,8 +3553,6 @@ GridAxisPosition LayoutGrid::rowAxisPositionForChild(
|
| 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:
|
| case ItemPositionNormal:
|
| @@ -3344,7 +3575,8 @@ LayoutUnit LayoutGrid::columnAxisOffsetForChild(
|
| GridAxisPosition axisPosition = columnAxisPositionForChild(child);
|
| switch (axisPosition) {
|
| case GridAxisStart:
|
| - return startPosition;
|
| + return startPosition +
|
| + columnAxisBaselineOffsetForChild(child, sizingData);
|
| case GridAxisEnd:
|
| case GridAxisCenter: {
|
| size_t childEndLine = rowsSpan.endLine();
|
| @@ -3388,7 +3620,7 @@ LayoutUnit LayoutGrid::rowAxisOffsetForChild(const LayoutBox& child,
|
| GridAxisPosition axisPosition = rowAxisPositionForChild(child);
|
| switch (axisPosition) {
|
| case GridAxisStart:
|
| - return startPosition;
|
| + return startPosition + rowAxisBaselineOffsetForChild(child, sizingData);
|
| case GridAxisEnd:
|
| case GridAxisCenter: {
|
| size_t childEndLine = columnsSpan.endLine();
|
|
|