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

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: Update intrinsic size and compute baseline after step 2 to deal with percentage items. Created 3 years, 11 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 bd8979ab203b0323eba79b481873d18ef48f7ffd..b9ef156a163ef8dbc2c704381c3652a74a89f516 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,30 @@ 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 intrinsicSizeMayHaveChanged =
+ baselineAffectIntrinsicWidth || baselineAffectIntrinsicHeight ||
+ sizingData.grid().hasAnyOrthogonalGridItem();
+
svillar 2017/02/09 13:10:09 Can't we just early return here if !intrinsicSizeM
jfernandez 2017/02/09 14:16:03 Acknowledged.
+ // Compute again the intrinsic size if baseline changed item's min-content
+ // contribution.
+ // TODO (lajava): Should we do the same because if orthogonal items ? Perhaps
+ // after executing again the track sizing algorithm ?
svillar 2017/02/09 13:10:09 I think we can take advantage of this change and d
jfernandez 2017/02/09 14:16:03 Acknowledged.
+ if (baselineAffectIntrinsicWidth) {
+ setPreferredLogicalWidthsDirty(MarkOnlyThis);
svillar 2017/02/09 13:10:09 Not sure if MarkOnlyThis is enough for orthogonal
jfernandez 2017/02/09 14:16:03 Umm, I think we must prevent infinite-iterations,
+ 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,12 +615,19 @@ 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()) {
+ if (intrinsicSizeMayHaveChanged) {
computeTrackSizesForDefiniteSize(ForColumns, sizingData,
availableSpaceForColumns);
computeTrackSizesForDefiniteSize(ForRows, sizingData,
availableSpaceForRows);
}
+
+ if (baselineAffectIntrinsicHeight) {
+ LayoutUnit trackBasedLogicalHeight =
+ computeTrackBasedLogicalHeight(sizingData) +
+ borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
+ setLogicalHeight(trackBasedLogicalHeight);
svillar 2017/02/09 13:10:09 Perhaps you could omit the trackBasedLogicalHeight
jfernandez 2017/02/09 14:16:03 Acknowledged.
+ }
}
void LayoutGrid::layoutBlock(bool relayoutChildren) {
@@ -611,6 +640,9 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) {
simplifiedLayout())
return;
+ m_rowAxisAlignmentContext.clear();
+ m_colAxisAlignmentContext.clear();
+
SubtreeLayoutScope layoutScope(*this);
{
@@ -681,6 +713,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
+ // determining incorrect their shared context's baseline.
+ computeBaselineAlignmentContext(sizingData);
svillar 2017/02/09 13:10:09 Not sure why you insert the computation in the mid
jfernandez 2017/02/09 14:16:03 We must do it here to so that when repeating the t
svillar 2017/02/13 15:18:46 Sorry about this. Yes it's propertly placed. I was
jfernandez 2017/02/13 23:32:37 I meant step 2 as described here: https://drafts.
+
// 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 +1365,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 +1475,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 +3142,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 +3155,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 +3167,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.
svillar 2017/02/09 13:10:09 Time to remove this comment?
jfernandez 2017/02/09 14:16:03 Umm, I don't think we can do it now. We must imple
svillar 2017/02/13 15:18:46 Acknowledged.
baselineChild = child;
@@ -3172,6 +3218,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 +3470,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 +3547,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 +3569,8 @@ LayoutUnit LayoutGrid::columnAxisOffsetForChild(
GridAxisPosition axisPosition = columnAxisPositionForChild(child);
switch (axisPosition) {
case GridAxisStart:
- return startPosition;
+ return startPosition +
+ columnAxisBaselineOffsetForChild(child, sizingData);
svillar 2017/02/09 13:10:09 Maybe this is an stupid question, but why just on
jfernandez 2017/02/09 14:16:03 because 'baseline' value is managed as 'start', in
case GridAxisEnd:
case GridAxisCenter: {
size_t childEndLine = rowsSpan.endLine();
@@ -3388,7 +3614,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();
« 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