| 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 d97816e9b8c5b900599694276d4a6a41a7cf8e7e..ca5f7132ecc47b1412c352b407aead2e70f0e116 100644
|
| --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
|
| +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
|
| @@ -25,6 +25,8 @@
|
|
|
| #include "core/layout/LayoutGrid.h"
|
|
|
| +#include <algorithm>
|
| +#include <memory>
|
| #include "core/frame/UseCounter.h"
|
| #include "core/layout/LayoutState.h"
|
| #include "core/layout/TextAutosizer.h"
|
| @@ -33,9 +35,8 @@
|
| #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>
|
|
|
| namespace blink {
|
|
|
| @@ -167,19 +168,44 @@ void LayoutGrid::computeTrackSizesForDefiniteSize(
|
|
|
| void LayoutGrid::repeatTracksSizingIfNeeded(LayoutUnit availableSpaceForColumns,
|
| LayoutUnit availableSpaceForRows) {
|
| + // 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.
|
| - // 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
|
| + bool hasAnyOrthogonal =
|
| + m_trackSizingAlgorithm.grid().hasAnyOrthogonalGridItem();
|
| +
|
| + // TODO (lajava): these are just some of the cases which may require
|
| // a new cycle of the sizing algorithm; there may be more. In addition, not
|
| // 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 (m_grid.hasAnyOrthogonalGridItem()) {
|
| - computeTrackSizesForDefiniteSize(ForColumns, availableSpaceForColumns);
|
| - computeTrackSizesForDefiniteSize(ForRows, availableSpaceForRows);
|
| + if (!baselineAffectIntrinsicWidth && !baselineAffectIntrinsicHeight &&
|
| + !hasAnyOrthogonal)
|
| + return;
|
| +
|
| + // TODO (lajava): Whenever the min-content contribution of a grid item changes
|
| + // we may need to update the grid container's intrinsic width. The new
|
| + // intrinsic width may also affect the extra Track Sizing algorithm cycles we
|
| + // are about to execute.
|
| + // https://crbug.com/704713
|
| + // https://github.com/w3c/csswg-drafts/issues/1039
|
| +
|
| + // Hence we need to repeat computeUsedBreadthOfGridTracks for both, columns
|
| + // and rows, to determine the final values.
|
| + computeTrackSizesForDefiniteSize(ForColumns, availableSpaceForColumns);
|
| + computeTrackSizesForDefiniteSize(ForRows, availableSpaceForRows);
|
| +
|
| + if (baselineAffectIntrinsicHeight) {
|
| + setLogicalHeight(computeTrackBasedLogicalHeight() +
|
| + borderAndPaddingLogicalHeight() +
|
| + scrollbarLogicalHeight());
|
| }
|
| }
|
|
|
| @@ -193,6 +219,9 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) {
|
| simplifiedLayout())
|
| return;
|
|
|
| + m_rowAxisAlignmentContext.clear();
|
| + m_colAxisAlignmentContext.clear();
|
| +
|
| SubtreeLayoutScope layoutScope(*this);
|
|
|
| {
|
| @@ -259,6 +288,15 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) {
|
| 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();
|
| +
|
| // 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).
|
| @@ -1580,8 +1618,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,
|
| @@ -1595,11 +1631,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;
|
| @@ -1612,8 +1643,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;
|
| @@ -1663,6 +1694,199 @@ 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) &&
|
| + ((child.styleRef().isFlippedBlocksWritingMode() &&
|
| + !styleRef().isFlippedBlocksWritingMode()) ||
|
| + (child.styleRef().isFlippedLinesWritingMode() &&
|
| + 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,
|
| + GridAxis baselineAxis) const {
|
| + DCHECK(isBaselineAlignmentForChild(child, baselineAxis));
|
| + auto& grid = m_trackSizingAlgorithm.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.at(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::marginUnderForChild(const LayoutBox& child,
|
| + GridAxis axis) const {
|
| + return isHorizontalGridAxis(axis) ? child.marginLeft() : child.marginBottom();
|
| +}
|
| +
|
| +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 {
|
| + LayoutUnit margin = isDescentBaselineForChild(child, baselineAxis)
|
| + ? marginUnderForChild(child, baselineAxis)
|
| + : marginOverForChild(child, baselineAxis);
|
| + int baseline = isParallelToBlockAxisForChild(child, baselineAxis)
|
| + ? child.firstLineBoxBaseline()
|
| + : -1;
|
| + // We take border-box's under edge if no valid baseline.
|
| + if (baseline == -1) {
|
| + if (isHorizontalGridAxis(baselineAxis)) {
|
| + return styleRef().isFlippedBlocksWritingMode()
|
| + ? child.size().width().toInt() + margin
|
| + : margin;
|
| + }
|
| + return child.size().height() + margin;
|
| + }
|
| + return LayoutUnit(baseline) + margin;
|
| +}
|
| +
|
| +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() {
|
| + for (auto* child = firstInFlowChildBox(); child;
|
| + child = child->nextInFlowSiblingBox()) {
|
| + updateBaselineAlignmentContextIfNeeded(*child, GridRowAxis);
|
| + updateBaselineAlignmentContextIfNeeded(*child, GridColumnAxis);
|
| + }
|
| +}
|
| +
|
| +void LayoutGrid::updateBaselineAlignmentContextIfNeeded(LayoutBox& child,
|
| + GridAxis baselineAxis) {
|
| + // TODO (lajava): We must ensure this method is not called as part of an
|
| + // intrinsic size computation.
|
| + 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 = m_trackSizingAlgorithm.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.insert(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 {
|
| + if (!isBaselineAlignmentForChild(child, GridColumnAxis))
|
| + return LayoutUnit();
|
| + auto& group = getBaselineGroupForChild(child, GridColumnAxis);
|
| + if (group.size() > 1)
|
| + return group.maxAscent() - logicalAscentForChild(child, GridColumnAxis);
|
| + return LayoutUnit();
|
| +}
|
| +
|
| +LayoutUnit LayoutGrid::rowAxisBaselineOffsetForChild(
|
| + const LayoutBox& child) const {
|
| + if (!isBaselineAlignmentForChild(child, GridRowAxis))
|
| + return LayoutUnit();
|
| + auto& group = getBaselineGroupForChild(child, GridRowAxis);
|
| + if (group.size() > 1)
|
| + return group.maxAscent() - logicalAscentForChild(child, GridRowAxis);
|
| + return LayoutUnit();
|
| +}
|
| +
|
| GridAxisPosition LayoutGrid::columnAxisPositionForChild(
|
| const LayoutBox& child) const {
|
| bool hasSameWritingMode =
|
| @@ -1732,8 +1956,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:
|
| @@ -1811,8 +2033,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:
|
| @@ -1834,7 +2054,7 @@ LayoutUnit LayoutGrid::columnAxisOffsetForChild(const LayoutBox& child) const {
|
| GridAxisPosition axisPosition = columnAxisPositionForChild(child);
|
| switch (axisPosition) {
|
| case GridAxisStart:
|
| - return startPosition;
|
| + return startPosition + columnAxisBaselineOffsetForChild(child);
|
| case GridAxisEnd:
|
| case GridAxisCenter: {
|
| size_t childEndLine = rowsSpan.endLine();
|
| @@ -1876,7 +2096,7 @@ LayoutUnit LayoutGrid::rowAxisOffsetForChild(const LayoutBox& child) const {
|
| GridAxisPosition axisPosition = rowAxisPositionForChild(child);
|
| switch (axisPosition) {
|
| case GridAxisStart:
|
| - return startPosition;
|
| + return startPosition + rowAxisBaselineOffsetForChild(child);
|
| case GridAxisEnd:
|
| case GridAxisCenter: {
|
| size_t childEndLine = columnsSpan.endLine();
|
|
|