diff --git a/Source/WebCore/layout/formattingContexts/block/BlockLayoutState.h b/Source/WebCore/layout/formattingContexts/block/BlockLayoutState.h index f441319ff0ff..a9b24065de7d 100644 --- a/Source/WebCore/layout/formattingContexts/block/BlockLayoutState.h +++ b/Source/WebCore/layout/formattingContexts/block/BlockLayoutState.h @@ -38,6 +38,7 @@ class BlockLayoutState { struct LineClamp { size_t maximumNumberOfLines { 0 }; size_t numberOfVisibleLines { 0 }; + bool isLineClampRootOverflowHidden { true }; }; BlockLayoutState(FloatingState&, std::optional); diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp index 1f4706fed23a..67b2bb1ba6e7 100644 --- a/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp +++ b/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp @@ -204,15 +204,15 @@ static size_t indexOfFirstInlineItemForNextLine(const LineBuilder::LineContent& static LineBuilder::LineInput::LineEndingEllipsisPolicy lineEndingEllipsisPolicy(const RenderStyle& rootStyle, size_t numberOfLines, std::optional 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; } @@ -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 { if (auto lineClamp = blockLayoutState.lineClamp()) @@ -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); @@ -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; } diff --git a/Source/WebCore/layout/integration/inline/LayoutIntegrationLineLayout.cpp b/Source/WebCore/layout/integration/inline/LayoutIntegrationLineLayout.cpp index 1a2136cf5d45..6d5d215853a7 100644 --- a/Source/WebCore/layout/integration/inline/LayoutIntegrationLineLayout.cpp +++ b/Source/WebCore/layout/integration/inline/LayoutIntegrationLineLayout.cpp @@ -466,8 +466,18 @@ std::pair LineLayout::computeIntrinsicWidthConstraints() static inline std::optional 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 { }; } @@ -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()