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

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: Applied suggested changes. Created 4 years, 1 month 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
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 05a01b709fbfee65abbd54397c163e4667c2d148..bead4c968403e308706f55d1d9cf672aa8416a58 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -32,6 +32,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>
@@ -140,6 +141,66 @@ struct ContentAlignmentData {
LayoutUnit distributionOffset = LayoutUnit(-1);
};
+class BaselineGroup {
+ public:
+ BaselineGroup() {}
+
+ void update(LayoutUnit ascent, LayoutUnit descent) {
+ m_maxAscent = std::max(m_maxAscent, ascent);
+ m_maxDescent = std::max(m_maxDescent, descent);
+ m_size++;
+ }
+ LayoutUnit maxAscent() const { return m_maxAscent; }
+ LayoutUnit maxDescent() const { return m_maxDescent; }
+ LayoutUnit size() const { return m_size; }
+
+ private:
+ LayoutUnit m_maxAscent;
+ LayoutUnit m_maxDescent;
+ LayoutUnit m_size;
svillar 2016/11/25 14:44:48 Not clear to me what this m_size is and why we inc
+};
+
+class BaselineContext {
+ public:
+ BaselineContext(const LayoutBox& child,
+ ItemPosition preference,
+ LayoutUnit ascent,
+ LayoutUnit descent) {
+ updateSharedGroup(child, preference, ascent, descent);
+ }
+
+ const BaselineGroup& getSharedGroup(const LayoutBox& child,
+ ItemPosition preference) const {
+ if (isAscentBaseline(child.styleRef().getWritingMode(), preference))
+ return m_ascentSharedGroup;
+ return m_descentSharedGroup;
+ }
+
+ void updateSharedGroup(const LayoutBox& child,
+ ItemPosition preference,
+ LayoutUnit ascent,
+ LayoutUnit descent) {
+ if (isAscentBaseline(child.styleRef().getWritingMode(), preference))
+ m_ascentSharedGroup.update(ascent, descent);
+ else
+ m_descentSharedGroup.update(ascent, descent);
+ }
+
+ private:
+ bool isAscentBaseline(WritingMode blockDirection,
+ ItemPosition preference) const {
+ return ((blockDirection == TopToBottomWritingMode &&
+ preference == ItemPositionBaseline) ||
+ (blockDirection == LeftToRightWritingMode &&
+ preference == ItemPositionBaseline) ||
+ (blockDirection == RightToLeftWritingMode &&
+ preference == ItemPositionLastBaseline));
+ }
+
+ BaselineGroup m_ascentSharedGroup;
+ BaselineGroup m_descentSharedGroup;
+};
+
enum TrackSizeRestriction {
AllowInfinity,
ForbidInfinity,
@@ -247,6 +308,12 @@ class LayoutGrid::GridIterator {
size_t m_childIndex;
};
+typedef HashMap<unsigned,
+ std::unique_ptr<BaselineContext>,
+ DefaultHash<unsigned>::Hash,
+ WTF::UnsignedWithZeroKeyHashTraits<unsigned>>
+ BaselineContextsMap;
+
struct LayoutGrid::GridSizingData {
WTF_MAKE_NONCOPYABLE(GridSizingData);
STACK_ALLOCATED();
@@ -259,6 +326,9 @@ struct LayoutGrid::GridSizingData {
Vector<GridTrack> rowTracks;
Vector<size_t> contentSizedTracksIndex;
+ BaselineContextsMap rowAxisAlignmentContext;
+ BaselineContextsMap colAxisAlignmentContext;
+
// Performance optimization: hold onto these Vectors until the end of Layout
// to avoid repeated malloc / free.
Vector<GridTrack*> filteredTracks;
@@ -790,8 +860,18 @@ void LayoutGrid::computeUsedBreadthOfGridTracks(
track.setGrowthLimitCap(valueForLength(gridLength.length(), maxSize));
}
- if (trackSize.isContentSized())
+ if (trackSize.isContentSized()) {
sizingData.contentSizedTracksIndex.append(i);
+ } else if (!m_gridItemArea.isEmpty()) {
svillar 2016/11/25 14:44:48 I am not sure this condition is correct. Why are w
+ GridIterator iterator(m_grid, direction, i);
+ while (LayoutBox* gridItem = iterator.nextGridItem()) {
+ if (isBaselineAlignment(*gridItem) &&
+ (sizingData.sizingOperation != IntrinsicSizeComputation ||
+ direction == ForRows))
+ gridItem->layoutIfNeeded();
+ updateBaselineAlignmentContextIfNeeded(*gridItem, sizingData);
+ }
+ }
if (trackSize.maxTrackBreadth().isFlex())
flexibleSizedTracksIndex.append(i);
}
@@ -1104,7 +1184,8 @@ GridTrackSize LayoutGrid::gridTrackSize(GridTrackSizingDirection direction,
}
}
- // Flex sizes are invalid as a min sizing function. However we still can have
+ // Flex sizes are invalid as a min sizing function. However we still can
+ // have
svillar 2016/11/25 14:44:48 Something has happened to this comment
// a flexible |minTrackBreadth| if the track had a flex size directly (e.g.
// "1fr"), the spec says that in this case it implies an automatic minimum.
if (minTrackBreadth.isFlex())
@@ -1136,7 +1217,11 @@ LayoutUnit LayoutGrid::logicalHeightForChild(LayoutBox& child,
child.clearOverrideLogicalContentHeight();
child.layoutIfNeeded();
- return child.logicalHeight() + child.marginLogicalHeight();
+ LayoutUnit baselineOffset =
+ updateBaselineAlignmentContextIfNeeded(child, sizingData);
+ return baselineOffset > 0
+ ? baselineOffset
+ : child.logicalHeight() + child.marginLogicalHeight();
svillar 2016/11/25 14:44:48 Nit: what about if (auto baselineOffset = update.
}
GridTrackSizingDirection LayoutGrid::flowAwareDirectionForChild(
@@ -1232,7 +1317,11 @@ LayoutUnit LayoutGrid::minContentForChild(LayoutBox& child,
if (direction == ForColumns &&
sizingData.sizingOperation == IntrinsicSizeComputation) {
DCHECK(isOrthogonalChild(child));
- return child.logicalHeight() + child.marginLogicalHeight();
+ LayoutUnit baselineOffset =
+ updateBaselineAlignmentContextIfNeeded(child, sizingData);
+ return baselineOffset > 0
+ ? baselineOffset
+ : child.logicalHeight() + child.marginLogicalHeight();
svillar 2016/11/25 14:44:48 Looks like exactly the same code, would it make se
}
if (updateOverrideContainingBlockContentSizeForChild(
@@ -2746,6 +2835,11 @@ LayoutUnit LayoutGrid::marginLogicalHeightForChild(
return isHorizontalWritingMode() ? child.marginHeight() : child.marginWidth();
}
+LayoutUnit LayoutGrid::marginLogicalWidthForChild(
+ const LayoutBox& child) const {
+ return isHorizontalWritingMode() ? child.marginWidth() : child.marginHeight();
+}
+
LayoutUnit LayoutGrid::computeMarginLogicalSizeForChild(
MarginDirection forDirection,
const LayoutBox& child) const {
@@ -2929,6 +3023,110 @@ static int synthesizedBaselineFromBorderBox(const LayoutBox& box,
// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it might be
// refactored somehow.
+bool LayoutGrid::isBaselineAlignment(const LayoutBox& child) const {
+ bool isChildInlineFlowAlongRowAxis = !isOrthogonalChild(child);
svillar 2016/11/25 14:44:48 I don't understand this variable name. isParallelC
+ ItemPosition align = isChildInlineFlowAlongRowAxis
+ ? alignSelfForChild(child).position()
+ : justifySelfForChild(child).position();
+ bool hasAutoMargins = isChildInlineFlowAlongRowAxis
+ ? hasAutoMarginsInColumnAxis(child)
+ : hasAutoMarginsInRowAxis(child);
+ return (
+ (align == ItemPositionBaseline || align == ItemPositionLastBaseline) &&
+ !hasAutoMargins);
+}
+
+LayoutUnit LayoutGrid::updateBaselineAlignmentContextIfNeeded(
+ LayoutBox& child,
+ GridSizingData& sizingData) const {
+ if (!isBaselineAlignment(child))
+ return LayoutUnit();
+
+ bool isChildInlineFlowAlongRowAxis = !isOrthogonalChild(child);
+ ItemPosition align = isChildInlineFlowAlongRowAxis
+ ? alignSelfForChild(child).position()
+ : justifySelfForChild(child).position();
+ const GridSpan& span = isChildInlineFlowAlongRowAxis
+ ? cachedGridSpan(child, ForRows)
+ : cachedGridSpan(child, ForColumns);
+ LayoutUnit ascent = firstLineBoxBaselineForChild(child);
+ LayoutUnit descent = descentBaselineForChild(child, ascent);
+ BaselineContextsMap& baselineContexts =
+ isChildInlineFlowAlongRowAxis ? sizingData.rowAxisAlignmentContext
+ : sizingData.colAxisAlignmentContext;
+ BaselineContext* context = nullptr;
+ BaselineContextsMap::AddResult addResult = baselineContexts.add(
+ span.startLine(), std::unique_ptr<BaselineContext>());
+ if (addResult.isNewEntry) {
+ context = new BaselineContext(child, align, ascent, descent);
+ addResult.storedValue->value = wrapUnique(context);
+ } else {
+ context = addResult.storedValue->value.get();
+ context->updateSharedGroup(child, align, ascent, descent);
+ }
+ auto group = context->getSharedGroup(child, align);
+ return group.maxAscent() + group.maxDescent();
+}
+
+LayoutUnit LayoutGrid::firstLineBoxBaselineForChild(
+ 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);
+}
+
+LayoutUnit LayoutGrid::descentBaselineForChild(const LayoutBox& child,
+ LayoutUnit ascent) const {
+ bool isChildInlineFlowAlongRowAxis = !isOrthogonalChild(child);
+ return isChildInlineFlowAlongRowAxis
+ ? (marginLogicalHeightForChild(child) +
+ LayoutBlock::logicalHeightForChild(child)) -
+ ascent
+ : (marginLogicalWidthForChild(child) +
+ logicalWidthForChild(child)) -
+ ascent;
+}
+
+LayoutUnit LayoutGrid::columnAxisBaselineOffsetForChild(
+ const LayoutBox& child,
+ const GridSizingData& sizingData) const {
+ // only parallel items participating in baseline alignment along
svillar 2016/11/25 14:44:48 Nit: capital letter -> Only
+ // the grid's row axis have an offset in the column axis.
+ if (!isInlineBaselineAlignedChild(child))
+ return LayoutUnit();
+
+ const GridSpan& span = cachedGridSpan(child, ForRows);
+ const BaselineContext* context =
+ sizingData.rowAxisAlignmentContext.get(span.startLine());
+ DCHECK(context);
+ const BaselineGroup& group =
+ context->getSharedGroup(child, alignSelfForChild(child).position());
+ // TODO (lajava): We could just return LayoutUnit() if there is only
+ // 1 child in the group.
+ return group.maxAscent() - firstLineBoxBaselineForChild(child);
+}
+
+LayoutUnit LayoutGrid::rowAxisBaselineOffsetForChild(
+ const LayoutBox& child,
+ const GridSizingData& sizingData) const {
+ // only orthogonal items participating in baseline alignment along
+ // the grid's column axis have an offset in the row axis.
+ if (!isBlockBaselineAlignedChild(child))
+ return LayoutUnit();
+
+ const GridSpan& span = cachedGridSpan(child, ForColumns);
+ const BaselineContext* context =
+ sizingData.colAxisAlignmentContext.get(span.startLine());
+ DCHECK(context);
+ const BaselineGroup& group =
+ context->getSharedGroup(child, justifySelfForChild(child).position());
+ // TODO (lajava): We could just return LayoutUnit() if there is only
+ // 1 child in the group.
+ return group.maxAscent() - firstLineBoxBaselineForChild(child);
+}
+
int LayoutGrid::baselinePosition(FontBaseline,
bool,
LineDirectionMode direction,
@@ -2942,9 +3140,12 @@ int LayoutGrid::baselinePosition(FontBaseline,
return baseline + beforeMarginInLineDirection(direction);
}
-bool LayoutGrid::isInlineBaselineAlignedChild(const LayoutBox* child) const {
- return alignSelfForChild(*child).position() == ItemPositionBaseline &&
- !isOrthogonalChild(*child) && !hasAutoMarginsInColumnAxis(*child);
+bool LayoutGrid::isInlineBaselineAlignedChild(const LayoutBox& child) const {
+ return !isOrthogonalChild(child) && isBaselineAlignment(child);
+}
+
+bool LayoutGrid::isBlockBaselineAlignedChild(const LayoutBox& child) const {
+ return isOrthogonalChild(child) && isBaselineAlignment(child);
}
int LayoutGrid::firstLineBoxBaseline() const {
@@ -2959,8 +3160,8 @@ int LayoutGrid::firstLineBoxBaseline() const {
for (size_t index = 0; index < m_grid[0][column].size(); index++) {
const LayoutBox* child = m_grid[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 (isInlineBaselineAlignedChild(*child)) {
// TODO (lajava): self-baseline and content-baseline alignment
// still not implemented.
baselineChild = child;
@@ -3079,8 +3280,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:
@@ -3158,8 +3357,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:
@@ -3182,7 +3379,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();
@@ -3225,7 +3423,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();

Powered by Google App Engine
This is Rietveld 408576698