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