Skip to content

Commit

Permalink
[IFC][Line clamp] Let's construct lines even after the line-clamp cap…
Browse files Browse the repository at this point in the history
… when overflow is not hidden

https://bugs.webkit.org/show_bug.cgi?id=248255

Reviewed by Antti Koivisto.

When the flex box is not overflow hidden, we should still produce lines for the block even
after we reach the line-clamp limit.
This result in a rather odd rendering where the ellipsis is placed at the end of a line somewhere
in the middle of the block.
However (which is even more odd) the block height uses the clamped content height (see FIXME), which then can produce overlapping content.

* Source/WebCore/layout/formattingContexts/block/BlockLayoutState.h:
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::lineEndingEllipsisPolicy):
(WebCore::Layout::InlineFormattingContext::lineLayout):
* Source/WebCore/layout/integration/inline/LayoutIntegrationLineLayout.cpp:
(WebCore::LayoutIntegration::lineClamp):
(WebCore::LayoutIntegration::LineLayout::contentLogicalHeight const):

Canonical link: https://commits.webkit.org/256979@main
  • Loading branch information
alanbaradlay committed Nov 23, 2022
1 parent 18af8a2 commit f707f6a
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
Expand Up @@ -38,6 +38,7 @@ class BlockLayoutState {
struct LineClamp {
size_t maximumNumberOfLines { 0 };
size_t numberOfVisibleLines { 0 };
bool isLineClampRootOverflowHidden { true };
};
BlockLayoutState(FloatingState&, std::optional<LineClamp>);

Expand Down
Expand Up @@ -204,15 +204,15 @@ static size_t indexOfFirstInlineItemForNextLine(const LineBuilder::LineContent&

static LineBuilder::LineInput::LineEndingEllipsisPolicy lineEndingEllipsisPolicy(const RenderStyle& rootStyle, size_t numberOfLines, std::optional<size_t> maximumNumberOfLines)
{
if (maximumNumberOfLines) {
ASSERT(numberOfLines < *maximumNumberOfLines);
// We may have passed the line-clamp line with overflow visible.
if (maximumNumberOfLines && numberOfLines < *maximumNumberOfLines) {
// If the next call to layoutInlineContent() won't produce a line with content (e.g. only floats), we'll end up here again.
auto treatNextLineAsLastLine = *maximumNumberOfLines - numberOfLines == 1;
if (treatNextLineAsLastLine)
return LineBuilder::LineInput::LineEndingEllipsisPolicy::Always;
}
// Truncation is in effect when the block container has overflow other than visible.
if (!rootStyle.isOverflowVisible() && rootStyle.textOverflow() == TextOverflow::Ellipsis)
if (rootStyle.overflowX() == Overflow::Hidden && rootStyle.textOverflow() == TextOverflow::Ellipsis)
return LineBuilder::LineInput::LineEndingEllipsisPolicy::WhenContentOverflows;
return LineBuilder::LineInput::LineEndingEllipsisPolicy::No;
}
Expand All @@ -226,6 +226,7 @@ void InlineFormattingContext::lineLayout(InlineItems& inlineItems, const LineBui

auto& floatingState = blockLayoutState.floatingState();
auto floatingContext = FloatingContext { *this, floatingState };
auto& rootStyle = root().style();

auto maximumNumberOfLines = [&] () -> std::optional<size_t> {
if (auto lineClamp = blockLayoutState.lineClamp())
Expand All @@ -248,7 +249,7 @@ void InlineFormattingContext::lineLayout(InlineItems& inlineItems, const LineBui
while (true) {

auto lineInitialRect = InlineRect { lineLogicalTop, constraints.horizontal().logicalLeft, constraints.horizontal().logicalWidth, formattingGeometry().initialLineHeight(!previousLine.has_value()) };
auto ellipsisPolicy = lineEndingEllipsisPolicy(root().style(), numberOfLines, maximumNumberOfLines);
auto ellipsisPolicy = lineEndingEllipsisPolicy(rootStyle, numberOfLines, maximumNumberOfLines);
auto contentIsTruncatedInBlockDirection = ellipsisPolicy == LineBuilder::LineInput::LineEndingEllipsisPolicy::Always;
auto lineContent = lineBuilder.layoutInlineContent({ { firstInlineItemNeedsLayout, needsLayoutRange.end }, lineInitialRect, ellipsisPolicy }, previousLine);

Expand All @@ -260,7 +261,7 @@ void InlineFormattingContext::lineLayout(InlineItems& inlineItems, const LineBui
auto lineLogicalRect = createDisplayContentForLine(lineContent, constraints);
if (lineContent.isLastLineWithInlineContent)
formattingState.setClearGapAfterLastLine(formattingGeometry().logicalTopForNextLine(lineContent, lineLogicalRect, floatingContext) - lineLogicalRect.bottom());
if (isLastLine || contentIsTruncatedInBlockDirection) {
if (isLastLine || (contentIsTruncatedInBlockDirection && blockLayoutState.lineClamp()->isLineClampRootOverflowHidden)) {
resetGeometryForClampedContent({ firstInlineItemNeedsLayout, needsLayoutRange.end }, lineContent.overflowingFloats, { constraints.horizontal().logicalLeft, lineLogicalRect.bottom() });
break;
}
Expand Down
Expand Up @@ -466,8 +466,18 @@ std::pair<LayoutUnit, LayoutUnit> LineLayout::computeIntrinsicWidthConstraints()
static inline std::optional<Layout::BlockLayoutState::LineClamp> lineClamp(const RenderBlockFlow& rootRenderer)
{
auto& layoutState = *rootRenderer.view().frameView().layoutContext().layoutState();
if (layoutState.hasLineClamp())
return Layout::BlockLayoutState::LineClamp { *layoutState.maximumLineCountForLineClamp(), layoutState.visibleLineCountForLineClamp().value_or(0) };
if (layoutState.hasLineClamp()) {
// FIXME: This is a rather odd behavior when we let line-clamp place ellipsis on a line and still
// continue with constructing subsequent, visible lines on the block (other browsers match this exoctic behavior).
auto isLineClampRootOverflowHidden = true;
for (const RenderBlock* ancestor = &rootRenderer; ancestor; ancestor = ancestor->containingBlock()) {
if (!ancestor->style().lineClamp().isNone()) {
isLineClampRootOverflowHidden = ancestor->style().overflowY() == Overflow::Hidden;
break;
}
}
return Layout::BlockLayoutState::LineClamp { *layoutState.maximumLineCountForLineClamp(), layoutState.visibleLineCountForLineClamp().value_or(0), isLineClampRootOverflowHidden };
}
return { };
}

Expand Down Expand Up @@ -657,6 +667,7 @@ LayoutUnit LineLayout::contentLogicalHeight() const
if (!m_inlineContent)
return { };

// FIXME: Content height with line-clamp and non-hidden overflow computes to the clamped content.
auto& lines = m_inlineContent->lines;
auto flippedContentHeightForWritingMode = rootLayoutBox().style().isHorizontalWritingMode()
? lines.last().lineBoxBottom() - lines.first().lineBoxTop()
Expand Down

0 comments on commit f707f6a

Please sign in to comment.