Diff
Modified: trunk/Source/WebCore/ChangeLog (266508 => 266509)
--- trunk/Source/WebCore/ChangeLog 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/ChangeLog 2020-09-03 10:15:04 UTC (rev 266509)
@@ -1,3 +1,64 @@
+2020-09-03 Zalan Bujtas <za...@apple.com>
+
+ [LFC][IFC] Finalize InlineBox alignment in LineBox
+ https://bugs.webkit.org/show_bug.cgi?id=215410
+
+ Reviewed by Antti Koivisto.
+
+ This patch completes the InlineBox transition.
+
+ LineBox now has a dedicated root inline box and additional inline boxes as needed.
+ Both horizontal and vertical alignments are performed on the inline boxes as opposed to on the runs.
+
+ * layout/inlineformatting/InlineFormattingContext.cpp:
+ (WebCore::Layout::InlineFormattingContext::lineLayout):
+ (WebCore::Layout::InlineFormattingContext::constraintsForLine):
+ (WebCore::Layout::InlineFormattingContext::setDisplayBoxesForLine):
+ * layout/inlineformatting/InlineFormattingContext.h:
+ * layout/inlineformatting/InlineFormattingContextQuirks.cpp:
+ (WebCore::Layout::InlineFormattingContext::Quirks::initialLineHeight const):
+ * layout/inlineformatting/InlineLineBox.cpp:
+ (WebCore::Layout::collectHangingContent):
+ (WebCore::Layout::horizontalAlignmentOffset):
+ (WebCore::Layout::halfLeadingMetrics):
+ (WebCore::Layout::LineBox::InlineBox::InlineBox):
+ (WebCore::Layout::LineBox::LineBox):
+ (WebCore::Layout::m_inlineFormattingContext):
+ (WebCore::Layout::LineBox::inlineBoxForLayoutBox const):
+ (WebCore::Layout::LineBox::inlineRectForTextRun const):
+ (WebCore::Layout::LineBox::constructInlineBoxes):
+ (WebCore::Layout::LineBox::alignVertically):
+ (WebCore::Layout::LineBox::rectForRun const): Deleted.
+ (WebCore::Layout::LineBox::alignHorizontally): Deleted.
+ (WebCore::Layout::LineBox::adjustBaselineAndLineHeight): Deleted.
+ (WebCore::Layout::LineBox::collectHangingContent const): Deleted.
+ * layout/inlineformatting/InlineLineBox.h:
+ (WebCore::Layout::LineBox::InlineBox::AscentAndDescent::height const):
+ (WebCore::Layout::LineBox::InlineBox::logicalRect const):
+ (WebCore::Layout::LineBox::InlineBox::logicalTop const):
+ (WebCore::Layout::LineBox::InlineBox::logicalLeft const):
+ (WebCore::Layout::LineBox::InlineBox::logicalWidth const):
+ (WebCore::Layout::LineBox::InlineBox::logicalHeight const):
+ (WebCore::Layout::LineBox::InlineBox::baseline const):
+ (WebCore::Layout::LineBox::InlineBox::descent const):
+ (WebCore::Layout::LineBox::InlineBox::setLogicalTop):
+ (WebCore::Layout::LineBox::InlineBox::setLogicalWidth):
+ (WebCore::Layout::LineBox::InlineBox::isAtomicInlineLevelBox const):
+ (WebCore::Layout::LineBox::InlineBox::setHasStrut):
+ (WebCore::Layout::LineBox::InlineBox::hasStrut const):
+ (WebCore::Layout::LineBox::alignmentBaseline const):
+ (WebCore::Layout::AscentAndDescent::height const): Deleted.
+ (WebCore::Layout::LineBox::ascentAndDescent const): Deleted.
+ (WebCore::Layout::LineBox::setScrollableOverflow): Deleted.
+ (WebCore::Layout::LineBox::InlineBox::InlineBox): Deleted.
+ (WebCore::Layout::LineBox::setLogicalHeightIfGreater): Deleted.
+ (WebCore::Layout::LineBox::setAlignmentBaselineIfGreater): Deleted.
+ (WebCore::Layout::LineBox::setAscentIfGreater): Deleted.
+ (WebCore::Layout::LineBox::setDescentIfGreater): Deleted.
+ (WebCore::Layout::LineBox::halfLeadingMetrics): Deleted.
+ * layout/inlineformatting/InlineLineBuilder.h:
+ (WebCore::Layout::LineBuilder::Run::logicalRight const):
+
2020-09-03 Youenn Fablet <you...@apple.com>
calling transceiver setCodecPreferences doesn't change the order of codecs in the offer/answer generated by the browser
Modified: trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h (266508 => 266509)
--- trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h 2020-09-03 10:15:04 UTC (rev 266509)
@@ -58,6 +58,7 @@
void moveHorizontally(InlineLayoutUnit);
void moveVertically(InlineLayoutUnit);
+ void moveBy(InlineLayoutPoint);
void expand(Optional<InlineLayoutUnit>, Optional<InlineLayoutUnit>);
void expandToContain(const InlineRect&);
@@ -236,6 +237,13 @@
m_rect.move(InlineLayoutSize { 0, offset });
}
+inline void InlineRect::moveBy(InlineLayoutPoint offset)
+{
+ ASSERT(m_hasValidTop);
+ ASSERT(m_hasValidLeft);
+ m_rect.moveBy(offset);
+}
+
inline void InlineRect::expand(Optional<InlineLayoutUnit> width, Optional<InlineLayoutUnit> height)
{
ASSERT(!width || m_hasValidWidth);
@@ -245,7 +253,13 @@
inline void InlineRect::expandToContain(const InlineRect& other)
{
- m_rect = unionRect(other, m_rect);
+#if ASSERT_ENABLED
+ m_hasValidTop = true;
+ m_hasValidLeft = true;
+ m_hasValidWidth = true;
+ m_hasValidHeight = true;
+#endif
+ m_rect.uniteEvenIfEmpty(other);
}
inline void InlineRect::expandVerticallyToContain(const InlineRect& other)
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2020-09-03 10:15:04 UTC (rev 266509)
@@ -167,8 +167,10 @@
return false;
}();
line.close(isLastLineWithInlineContent);
- auto lineRect = Display::InlineRect { lineConstraints.logicalTopLeft, line.lineLogicalWidth(), lineConstraints.lineHeight};
- auto lineBox = LineBox { *this, lineRect, lineContent.runs, line.isVisuallyEmpty() ? LineBox::IsLineVisuallyEmpty::Yes : LineBox::IsLineVisuallyEmpty::No, isLastLineWithInlineContent ? LineBox::IsLastLineWithInlineContent::Yes : LineBox::IsLastLineWithInlineContent::No };
+
+ auto lineIsVisuallyEmpty = line.isVisuallyEmpty() ? LineBox::IsLineVisuallyEmpty::Yes : LineBox::IsLineVisuallyEmpty::No;
+ auto lastLine = isLastLineWithInlineContent ? LineBox::IsLastLineWithInlineContent::Yes : LineBox::IsLastLineWithInlineContent::No;
+ auto lineBox = LineBox { *this, lineConstraints.logicalTopLeft, line.lineLogicalWidth(), line.contentLogicalWidth(), lineContent.runs, lineIsVisuallyEmpty, lastLine};
setDisplayBoxesForLine(lineContent, lineBox, constraints.horizontal);
if (!lineContentRange.isEmpty()) {
@@ -417,7 +419,6 @@
{
auto lineLogicalLeft = horizontalConstraints.logicalLeft;
auto lineLogicalRight = lineLogicalLeft + horizontalConstraints.logicalWidth;
- auto initialLineHeight = quirks().initialLineHeight(root());
auto lineIsConstrainedByFloat = false;
auto floatingContext = FloatingContext { root(), *this, formattingState().floatingState() };
@@ -424,7 +425,7 @@
// Check for intruding floats and adjust logical left/available width for this line accordingly.
if (!floatingContext.isEmpty()) {
// FIXME: Add support for variable line height, where the intrusive floats should be probed as the line height grows.
- auto floatConstraints = floatingContext.constraints(toLayoutUnit(lineLogicalTop), toLayoutUnit(lineLogicalTop + initialLineHeight));
+ auto floatConstraints = floatingContext.constraints(toLayoutUnit(lineLogicalTop), toLayoutUnit(lineLogicalTop + quirks().initialLineHeight()));
// Check if these constraints actually put limitation on the line.
if (floatConstraints.left && floatConstraints.left->x <= lineLogicalLeft)
floatConstraints.left = { };
@@ -480,7 +481,7 @@
return geometry().computedTextIndent(root, horizontalConstraints).valueOr(InlineLayoutUnit { });
};
lineLogicalLeft += computedTextIndent();
- return LineConstraints { { lineLogicalLeft, lineLogicalTop }, lineLogicalRight - lineLogicalLeft, initialLineHeight, lineIsConstrainedByFloat };
+ return LineConstraints { { lineLogicalLeft, lineLogicalTop }, lineLogicalRight - lineLogicalLeft, lineIsConstrainedByFloat };
}
void InlineFormattingContext::setDisplayBoxesForLine(const LineLayoutContext::LineContent& lineContent, const LineBox& lineBox, const HorizontalConstraints& horizontalConstraints)
@@ -510,16 +511,13 @@
auto& inlineContent = formattingState.ensureDisplayInlineContent();
auto lineIndex = inlineContent.lineBoxes.size();
auto lineInkOverflow = lineBox.scrollableOverflow();
- // Compute box final geometry.
+ // Compute final box geometry.
for (auto& lineRun : lineContent.runs) {
- auto& logicalRect = lineBox.rectForRun(lineRun);
auto& layoutBox = lineRun.layoutBox();
-
- // Add final display runs to state first.
// Inline level containers (<span>) don't generate display runs and neither do completely collapsed runs.
- auto initiatesInlineRun = !lineRun.isContainerStart() && !lineRun.isContainerEnd();
+ auto initiatesInlineRun = lineRun.isText() || lineRun.isLineBreak() || lineRun.isBox();
if (initiatesInlineRun) {
- auto computedInkOverflow = [&] {
+ auto computedInkOverflow = [&] (const auto& logicalRect) {
// FIXME: Add support for non-text ink overflow.
if (!lineRun.isText())
return logicalRect;
@@ -535,53 +533,33 @@
}
return inkOverflow;
};
- auto inkOverflow = computedInkOverflow();
+ auto logicalRect = lineRun.isBox() ? lineBox.inlineBoxForLayoutBox(layoutBox).logicalRect() : lineBox.inlineRectForTextRun(lineRun);
+ // Inline boxes are relative to the line box while final Display::Runs need to be relative to the parent Display:Box
+ // FIXME: Shouldn't we just leave them be relative to the line box?
+ logicalRect.moveBy({ lineBox.logicalLeft(), lineBox.logicalTop() });
+ auto inkOverflow = computedInkOverflow(logicalRect);
lineInkOverflow.expandToContain(inkOverflow);
- inlineContent.runs.append({ lineIndex, lineRun.layoutBox(), logicalRect, inkOverflow, lineRun.expansion(), lineRun.textContent() });
+ inlineContent.runs.append({ lineIndex, layoutBox, logicalRect, inkOverflow, lineRun.expansion(), lineRun.textContent() });
}
- if (lineRun.isText())
- continue;
-
- if (lineRun.isLineBreak()) {
- // FIXME: Since <br> and <wbr> runs have associated DOM elements, we might need to construct a display box here.
- continue;
- }
-
- // Inline level box (replaced or inline-block)
- if (lineRun.isBox()) {
- auto topLeft = logicalRect.topLeft();
+ // Create display boxes.
+ // FIXME: Since <br> and <wbr> runs have associated DOM elements, we might need to construct a display box here.
+ auto initiatesDisplayBox = lineRun.isBox() || lineRun.isContainerStart();
+ if (initiatesDisplayBox) {
+ auto& displayBox = formattingState.displayBox(layoutBox);
+ auto& inlineBox = lineBox.inlineBoxForLayoutBox(layoutBox);
+ auto topLeft = inlineBox.logicalRect().topLeft();
if (layoutBox.isInFlowPositioned())
topLeft += geometry().inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
- auto& displayBox = formattingState.displayBox(layoutBox);
displayBox.setTopLeft(toLayoutPoint(topLeft));
- continue;
- }
-
- // Inline level container start (<span>)
- if (lineRun.isContainerStart()) {
- auto& displayBox = formattingState.displayBox(layoutBox);
- displayBox.setTopLeft(toLayoutPoint(logicalRect.topLeft()));
- continue;
- }
-
- // Inline level container end (</span>)
- if (lineRun.isContainerEnd()) {
- auto& displayBox = formattingState.displayBox(layoutBox);
- if (layoutBox.isInFlowPositioned()) {
- auto inflowOffset = geometry().inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
- displayBox.moveHorizontally(inflowOffset.width());
- displayBox.moveVertically(inflowOffset.height());
+ if (lineRun.isContainerStart()) {
+ auto marginBoxWidth = inlineBox.logicalWidth();
+ auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0));
+ // FIXME: Fix it for multiline.
+ displayBox.setContentBoxWidth(toLayoutUnit(contentBoxWidth));
+ displayBox.setContentBoxHeight(toLayoutUnit(inlineBox.logicalHeight()));
}
- auto marginBoxWidth = logicalRect.left() - displayBox.left();
- auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0));
- // FIXME fix it for multiline.
- displayBox.setContentBoxWidth(toLayoutUnit(contentBoxWidth));
- displayBox.setContentBoxHeight(toLayoutUnit(logicalRect.height()));
- continue;
}
-
- ASSERT_NOT_REACHED();
}
// FIXME: This is where the logical to physical translate should happen.
inlineContent.lineBoxes.append({ lineBox.logicalRect(), lineBox.scrollableOverflow(), lineInkOverflow, lineBox.alignmentBaseline() });
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2020-09-03 10:15:04 UTC (rev 266509)
@@ -46,13 +46,10 @@
InlineFormattingContext(const ContainerBox& formattingContextRoot, InlineFormattingState&);
void layoutInFlowContent(InvalidationState&, const ConstraintsForInFlowContent&) override;
-private:
- IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
-
class Quirks : public FormattingContext::Quirks {
public:
bool lineDescentNeedsCollapsing(const LineBuilder::RunList&) const;
- InlineLayoutUnit initialLineHeight(const ContainerBox& formattingRoot) const;
+ InlineLayoutUnit initialLineHeight() const;
private:
friend class InlineFormattingContext;
@@ -63,6 +60,9 @@
};
InlineFormattingContext::Quirks quirks() const { return Quirks(*this); }
+private:
+ IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
+
class Geometry : public FormattingContext::Geometry {
public:
ContentHeightAndMargin inlineBlockHeightAndMargin(const Box&, const HorizontalConstraints&, const OverrideVerticalValues&) const;
@@ -91,7 +91,6 @@
struct LineConstraints {
InlineLayoutPoint logicalTopLeft;
InlineLayoutUnit availableLogicalWidth { 0 };
- InlineLayoutUnit lineHeight { 0 };
bool lineIsConstrainedByFloat { false };
};
LineConstraints constraintsForLine(const HorizontalConstraints&, InlineLayoutUnit lineLogicalTop);
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp 2020-09-03 10:15:04 UTC (rev 266509)
@@ -70,13 +70,13 @@
return true;
}
-InlineLayoutUnit InlineFormattingContext::Quirks::initialLineHeight(const ContainerBox& formattingRoot) const
+InlineLayoutUnit InlineFormattingContext::Quirks::initialLineHeight() const
{
- InlineLayoutUnit computedLineHeight = formattingRoot.style().computedLineHeight();
// Negative lineHeight value means the line-height is not set
- if (layoutState().inNoQuirksMode() || !formattingRoot.style().lineHeight().isNegative())
- return computedLineHeight;
- return LineBox::halfLeadingMetrics(formattingRoot.style().fontMetrics(), computedLineHeight).height();
+ auto& root = formattingContext().root();
+ if (layoutState().inNoQuirksMode() || !root.style().lineHeight().isNegative())
+ return root.style().computedLineHeight();
+ return root.style().fontMetrics().floatHeight();
}
}
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp 2020-09-03 10:15:04 UTC (rev 266509)
@@ -31,6 +31,13 @@
namespace WebCore {
namespace Layout {
+struct AscentAndDescent {
+ InlineLayoutUnit height() const { return ascent + descent; }
+
+ InlineLayoutUnit ascent { 0 };
+ InlineLayoutUnit descent { 0 };
+};
+
struct HangingContent {
public:
void reset();
@@ -52,139 +59,153 @@
m_width = 0;
}
-LineBox::LineBox(const InlineFormattingContext& inlineFormattingContext, const Display::InlineRect& lineRect, const LineBuilder::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty, IsLastLineWithInlineContent isLastLineWithInlineContent)
- : m_inlineFormattingContext(inlineFormattingContext)
- , m_runs(runs)
- , m_rect(lineRect)
- , m_scrollableOverflow(lineRect)
- , m_rootInlineBox(InlineBox { lineRect, { }, inlineFormattingContext.root() })
+static HangingContent collectHangingContent(const LineBuilder::RunList& runs, LineBox::IsLastLineWithInlineContent isLastLineWithInlineContent)
{
-#if ASSERT_ENABLED
- m_hasValidAlignmentBaseline = true;
-#endif
- auto& rootStyle = inlineFormattingContext.root().style();
- auto halfLeadingMetrics = this->halfLeadingMetrics(rootStyle.fontMetrics(), lineRect.height());
-
- m_rootInlineBox.ascentAndDescent = halfLeadingMetrics;
- m_alignmentBaseline = halfLeadingMetrics.ascent;
-
- auto contentLogicalWidth = InlineLayoutUnit { };
- for (auto& run : m_runs) {
- auto runHeight = [&]() -> InlineLayoutUnit {
- auto& fontMetrics = run.style().fontMetrics();
- if (run.isText() || run.isLineBreak())
- return fontMetrics.height();
-
- if (run.isContainerStart() || run.isContainerEnd())
- return fontMetrics.height();
-
- auto& layoutBox = run.layoutBox();
- auto& boxGeometry = inlineFormattingContext.geometryForBox(layoutBox);
- if (layoutBox.isReplacedBox() || layoutBox.isFloatingPositioned())
- return boxGeometry.contentBoxHeight();
-
- // Non-replaced inline box (e.g. inline-block). It looks a bit misleading but their margin box is considered the content height here.
- return boxGeometry.marginBoxHeight();
- };
- // FIXME: This is temporary. Do not make an inline box for each run.
- m_inlineBoxList.append(InlineBox { { 0, run.logicalLeft(), run.logicalWidth(), runHeight() }, halfLeadingMetrics, run.layoutBox() });
- m_runToInlineBoxMap.set(&run, m_inlineBoxList.size() - 1);
- contentLogicalWidth += run.logicalWidth();
+ auto hangingContent = HangingContent { };
+ if (isLastLineWithInlineContent == LineBox::IsLastLineWithInlineContent::Yes)
+ hangingContent.setIsConditional();
+ for (auto& run : WTF::makeReversedRange(runs)) {
+ if (run.isContainerStart() || run.isContainerEnd())
+ continue;
+ if (run.isLineBreak()) {
+ hangingContent.setIsConditional();
+ continue;
+ }
+ if (!run.hasTrailingWhitespace())
+ break;
+ // Check if we have a preserved or hung whitespace.
+ if (run.style().whiteSpace() != WhiteSpace::PreWrap)
+ break;
+ // This is either a normal or conditionally hanging trailing whitespace.
+ hangingContent.expand(run.trailingWhitespaceWidth());
}
- m_scrollableOverflow.setWidth(std::max(lineRect.width(), contentLogicalWidth));
- alignVertically();
- alignHorizontally(lineRect.width() - contentLogicalWidth, isLastLineWithInlineContent);
-
- if (isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes) {
- m_rect.setHeight({ });
- m_rootInlineBox.ascentAndDescent = { };
- }
+ return hangingContent;
}
-void LineBox::alignHorizontally(InlineLayoutUnit availableWidth, IsLastLineWithInlineContent isLastLine)
+static Optional<InlineLayoutUnit> horizontalAlignmentOffset(const LineBuilder::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, LineBox::IsLastLineWithInlineContent isLastLine)
{
- auto hangingContent = collectHangingContent(isLastLine);
+ auto availableWidth = lineLogicalWidth - contentLogicalWidth;
+ auto hangingContent = collectHangingContent(runs, isLastLine);
availableWidth += hangingContent.width();
- if (m_runs.isEmpty() || availableWidth <= 0)
- return;
+ if (availableWidth <= 0)
+ return { };
auto computedHorizontalAlignment = [&] {
- auto& rootStyle = formattingContext().root().style();
- if (rootStyle.textAlign() != TextAlignMode::Justify)
- return rootStyle.textAlign();
+ if (textAlign != TextAlignMode::Justify)
+ return textAlign;
// Text is justified according to the method specified by the text-justify property,
// in order to exactly fill the line box. Unless otherwise specified by text-align-last,
// the last line before a forced break or the end of the block is start-aligned.
- if (m_runs.last().isLineBreak() || isLastLine == IsLastLineWithInlineContent::Yes)
+ if (runs.last().isLineBreak() || isLastLine == LineBox::IsLastLineWithInlineContent::Yes)
return TextAlignMode::Start;
return TextAlignMode::Justify;
- }();
+ };
- if (computedHorizontalAlignment == TextAlignMode::Justify) {
- auto accumulatedExpansion = InlineLayoutUnit { };
- for (size_t index = 0; index < m_runs.size(); ++index) {
- m_inlineBoxList[index].rect.moveHorizontally(accumulatedExpansion);
-
- auto horizontalExpansion = m_runs[index].expansion().horizontalExpansion;
- m_inlineBoxList[index].rect.expandHorizontally(horizontalExpansion);
- accumulatedExpansion += horizontalExpansion;
- }
- return;
+ switch (computedHorizontalAlignment()) {
+ case TextAlignMode::Left:
+ case TextAlignMode::WebKitLeft:
+ case TextAlignMode::Start:
+ return { };
+ case TextAlignMode::Right:
+ case TextAlignMode::WebKitRight:
+ case TextAlignMode::End:
+ return availableWidth;
+ case TextAlignMode::Center:
+ case TextAlignMode::WebKitCenter:
+ return availableWidth / 2;
+ case TextAlignMode::Justify:
+ // TextAlignMode::Justify is a run alignment (and we only do inline box alignment here)
+ return { };
+ default:
+ ASSERT_NOT_IMPLEMENTED_YET();
+ return { };
}
+ ASSERT_NOT_REACHED();
+ return { };
+}
- auto adjustmentForAlignment = [&] (auto availableWidth) -> Optional<InlineLayoutUnit> {
- switch (computedHorizontalAlignment) {
- case TextAlignMode::Left:
- case TextAlignMode::WebKitLeft:
- case TextAlignMode::Start:
- return { };
- case TextAlignMode::Right:
- case TextAlignMode::WebKitRight:
- case TextAlignMode::End:
- return std::max<InlineLayoutUnit>(availableWidth, 0);
- case TextAlignMode::Center:
- case TextAlignMode::WebKitCenter:
- return std::max<InlineLayoutUnit>(availableWidth / 2, 0);
- case TextAlignMode::Justify:
- ASSERT_NOT_REACHED();
- break;
- }
- ASSERT_NOT_REACHED();
- return { };
- };
+inline static AscentAndDescent halfLeadingMetrics(const FontMetrics& fontMetrics, InlineLayoutUnit lineLogicalHeight)
+{
+ InlineLayoutUnit ascent = fontMetrics.ascent();
+ InlineLayoutUnit descent = fontMetrics.descent();
+ // 10.8.1 Leading and half-leading
+ auto halfLeading = (lineLogicalHeight - (ascent + descent)) / 2;
+ // Inline tree height is all integer based.
+ return { floorf(ascent + halfLeading), ceilf(descent + halfLeading) };
+}
- if (auto adjustment = adjustmentForAlignment(availableWidth)) {
- // FIXME: line box should not need to be moved, only the runs.
- m_rect.moveHorizontally(*adjustment);
- for (auto& inlineBox : m_inlineBoxList)
- inlineBox.rect.moveHorizontally(*adjustment);
+LineBox::InlineBox::InlineBox(const Display::InlineRect& rect, InlineLayoutUnit syntheticBaseline)
+ : m_logicalRect(rect)
+ , m_baseline(syntheticBaseline)
+ , m_isEmpty(false)
+ , m_isAtomic(true)
+{
+}
+
+LineBox::InlineBox::InlineBox(const Display::InlineRect& rect, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty isConsideredEmpty)
+ : m_logicalRect(rect)
+ , m_baseline(baseline)
+ , m_descent(descent)
+ , m_isEmpty(isConsideredEmpty == IsConsideredEmpty::Yes)
+{
+}
+
+LineBox::LineBox(const InlineFormattingContext& inlineFormattingContext, const InlineLayoutPoint& topLeft, InlineLayoutUnit logicalWidth, InlineLayoutUnit contentLogicalWidth, const LineBuilder::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty, IsLastLineWithInlineContent isLastLineWithInlineContent)
+ : m_rect(topLeft, logicalWidth, { })
+ , m_contentLogicalWidth(contentLogicalWidth)
+ , m_inlineFormattingContext(inlineFormattingContext)
+{
+ m_lineAlignmentOffset = horizontalAlignmentOffset(runs, root().style().textAlign(), logicalWidth, contentLogicalWidth, isLastLineWithInlineContent);
+ if (m_lineAlignmentOffset) {
+ // FIXME: line box should not need to be moved, only the inline boxes.
+ m_rect.moveHorizontally(*m_lineAlignmentOffset);
}
+ constructInlineBoxes(runs, isLineVisuallyEmpty);
+ alignVertically(isLineVisuallyEmpty);
+ // Compute scrollable overflow.
+ m_scrollableOverflow = Display::InlineRect { topLeft, std::max(logicalWidth, m_rootInlineBox.logicalWidth()), { } };
+ auto logicalBottom = m_rootInlineBox.logicalBottom();
+ for (auto& inlineBoxEntry : m_inlineBoxRectMap)
+ logicalBottom = std::max(logicalBottom, inlineBoxEntry.value->logicalBottom());
+ m_scrollableOverflow.expandVertically(logicalBottom);
+
}
-void LineBox::alignVertically()
+const LineBox::InlineBox& LineBox::inlineBoxForLayoutBox(const Box& layoutBox) const
{
- adjustBaselineAndLineHeight();
- for (size_t index = 0; index < m_inlineBoxList.size(); ++index) {
- auto& inlineBox = m_inlineBoxList[index];
- auto& run = m_runs[index];
- auto& layoutBox = inlineBox.layoutBox;
- auto inlineBoxHeight = inlineBox.rect.height();
+ ASSERT(&layoutBox != &root());
+ return *m_inlineBoxRectMap.get(&layoutBox);
+}
- auto logicalTop = InlineLayoutUnit { };
- auto verticalAlign = layoutBox.style().verticalAlign();
- auto ascent = layoutBox.style().fontMetrics().ascent();
+Display::InlineRect LineBox::inlineRectForTextRun(const LineBuilder::Run& run) const
+{
+ ASSERT(run.isText() || run.isLineBreak());
+ auto inlineBoxRect = m_rootInlineBox.logicalRect();
+ if (&run.layoutBox().parent() != &root())
+ inlineBoxRect = m_inlineBoxRectMap.get(&run.layoutBox().parent())->logicalRect();
+ return { inlineBoxRect.top(), run.logicalLeft(), run.logicalWidth(), inlineBoxRect.height() };
+}
- switch (verticalAlign) {
- case VerticalAlign::Baseline:
- if (run.isLineBreak() || run.isText())
- logicalTop = alignmentBaseline() - ascent;
- else if (run.isContainerStart()) {
- auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
- logicalTop = alignmentBaseline() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0);
- } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
+void LineBox::constructInlineBoxes(const LineBuilder::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty)
+{
+ auto lineHasImaginaryStrut = !layoutState().inQuirksMode();
+ auto lineIsConsideredEmpty = !lineHasImaginaryStrut || isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes ? InlineBox::IsConsideredEmpty::Yes : InlineBox::IsConsideredEmpty::No;
+ auto& fontMetrics = root().style().fontMetrics();
+ InlineLayoutUnit rootInlineBoxHeight = fontMetrics.height();
+ auto rootInlineRect = Display::InlineRect { { }, { }, contentLogicalWidth(), rootInlineBoxHeight };
+ InlineLayoutUnit rootInlineBaseline = fontMetrics.ascent();
+ auto rootInlineDescent = rootInlineBoxHeight - rootInlineBaseline;
+ m_rootInlineBox = InlineBox { rootInlineRect, rootInlineBaseline, rootInlineDescent, lineIsConsideredEmpty };
+
+ for (auto& run : runs) {
+ auto& layoutBox = run.layoutBox();
+ if (run.isBox()) {
+ auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
+ if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
// Spec makes us generate at least one line -even if it is empty.
- auto inlineBlockBaseline = formattingState.displayInlineContent()->lineBoxes.last().baseline();
+ auto& lastLineBox = formattingState.displayInlineContent()->lineBoxes.last();
+ auto inlineBlockBaseline = lastLineBox.top() + lastLineBox.baseline();
// The inline-block's baseline offset is relative to its content box. Let's convert it relative to the margin box.
// _______________ <- margin box
// |
@@ -197,148 +218,120 @@
// text | | | v text
// -----|-|-|---------- <- baseline
//
- auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
- auto baselineFromMarginBox = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0) + inlineBlockBaseline;
- logicalTop = alignmentBaseline() - baselineFromMarginBox;
+ auto adjustedBaseline = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0) + inlineBlockBaseline;
+ auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), run.logicalWidth(), boxGeometry.marginBoxHeight() };
+ m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, adjustedBaseline));
} else {
- auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
- logicalTop = alignmentBaseline() - (boxGeometry.verticalBorder() + boxGeometry.verticalPadding().valueOr(0_lu) + inlineBoxHeight + boxGeometry.marginAfter());
+ auto runHeight = boxGeometry.marginBoxHeight();
+ auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), run.logicalWidth(), runHeight };
+ m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, runHeight));
}
- break;
- case VerticalAlign::Top:
- logicalTop = 0_lu;
- break;
- case VerticalAlign::Bottom:
- logicalTop = logicalBottom() - inlineBoxHeight;
- break;
- default:
- ASSERT_NOT_IMPLEMENTED_YET();
- break;
+ } else if (run.isContainerStart()) {
+ auto initialWidth = contentLogicalWidth() - run.logicalLeft();
+ ASSERT(initialWidth >= 0);
+ auto& fontMetrics = layoutBox.style().fontMetrics();
+ InlineLayoutUnit logicalHeight = fontMetrics.height();
+ InlineLayoutUnit baseline = fontMetrics.ascent();
+ auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), initialWidth, logicalHeight };
+ m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, baseline, logicalHeight - baseline, InlineBox::IsConsideredEmpty::Yes));
+ } else if (run.isContainerEnd()) {
+ // Adjust the logical width when the inline level container closes on this line.
+ auto& inlineBox = *m_inlineBoxRectMap.get(&layoutBox);
+ inlineBox.setLogicalWidth(run.logicalRight() - inlineBox.logicalLeft());
+ } else if ((run.isText() || run.isLineBreak())) {
+ auto& containerBox = run.layoutBox().parent();
+ &containerBox == &root() ? m_rootInlineBox.setIsNonEmpty() : m_inlineBoxRectMap.get(&containerBox)->setIsNonEmpty();
}
- auto& inlineBoxRect = inlineBox.rect;
- inlineBoxRect.setTop(logicalTop);
- // Adjust scrollable overflow if the run overflows the line.
- m_scrollableOverflow.expandVerticallyToContain(inlineBoxRect);
- // Convert runs from relative to the line top/left to the formatting root's border box top/left.
- inlineBoxRect.moveVertically(this->logicalTop());
- inlineBoxRect.moveHorizontally(logicalLeft());
}
}
-void LineBox::adjustBaselineAndLineHeight()
+void LineBox::alignVertically(IsLineVisuallyEmpty isLineVisuallyEmpty)
{
- unsigned inlineContainerNestingLevel = 0;
- auto hasSeenDirectTextOrLineBreak = false;
- for (size_t index = 0; index < m_inlineBoxList.size(); ++index) {
- auto& inlineBox = m_inlineBoxList[index];
- auto& layoutBox = inlineBox.layoutBox;
- auto& style = layoutBox.style();
- auto& run = m_runs[index];
- if (run.isText() || run.isLineBreak()) {
- // For text content we set the baseline either through the initial strut (set by the formatting context root) or
- // through the inline container (start). Normally the text content itself does not stretch the line.
- if (inlineContainerNestingLevel) {
- // We've already adjusted the line height/baseline through the parent inline container.
- continue;
+ if (isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes)
+ return;
+ // 1. Compute line box height/alignment baseline by placing the inline boxes vertically.
+ // 2. Adjust the inline box vertical position.
+ auto& rootStyle = root().style();
+ // FIXME: We should let line box fully contain the inline boxes and move line spacing/overflow out to Display::LineBox.
+ // see webkit.org/b/215087#c9
+ InlineLayoutUnit recommendedLineBoxHeight = rootStyle.lineHeight().isNegative() ? rootStyle.fontMetrics().lineSpacing() : rootStyle.computedLineHeight();
+
+ auto contentLogicalHeight = InlineLayoutUnit { };
+ auto alignmentBaseline = InlineLayoutUnit { };
+ auto computeLineBoxHeight = [&](auto& inlineBox, auto textAlignMode) {
+ switch (textAlignMode) {
+ case VerticalAlign::Baseline: {
+ auto baselineOverflow = inlineBox.baseline() - alignmentBaseline;
+ if (baselineOverflow > 0) {
+ contentLogicalHeight += baselineOverflow;
+ alignmentBaseline += baselineOverflow;
}
- if (hasSeenDirectTextOrLineBreak) {
- // e.g div>first text</div> or <div><span>nested<span>first direct text</div>.
- continue;
+ // Table cells, inline-block boxes may stretch the line beyond their baseline.
+ auto belowBaseline = inlineBox.descent().valueOr(inlineBox.logicalHeight() - inlineBox.baseline());
+ auto belowBaselineOverflow = belowBaseline - (contentLogicalHeight - alignmentBaseline);
+ if (belowBaselineOverflow > 0)
+ contentLogicalHeight += belowBaselineOverflow;
+ break;
+ }
+ case VerticalAlign::Top: {
+ auto overflow = inlineBox.logicalHeight() - contentLogicalHeight;
+ if (overflow > 0)
+ contentLogicalHeight += overflow;
+ break;
+ }
+ case VerticalAlign::Bottom: {
+ auto overflow = inlineBox.logicalHeight() - contentLogicalHeight;
+ if (overflow > 0) {
+ contentLogicalHeight += overflow;
+ alignmentBaseline += overflow;
}
- hasSeenDirectTextOrLineBreak = true;
- continue;
+ break;
}
-
- if (run.isContainerStart()) {
- ++inlineContainerNestingLevel;
- // Inline containers stretch the line by their font size.
- // Vertical margins, paddings and borders don't contribute to the line height.
- auto& fontMetrics = style.fontMetrics();
- if (style.verticalAlign() == VerticalAlign::Baseline) {
- auto halfLeading = LineBox::halfLeadingMetrics(fontMetrics, style.computedLineHeight());
- // Both halfleading ascent and descent could be negative (tall font vs. small line-height value)
- if (halfLeading.descent > 0)
- setDescentIfGreater(halfLeading.descent);
- if (halfLeading.ascent > 0)
- setAscentIfGreater(halfLeading.ascent);
- setLogicalHeightIfGreater(ascentAndDescent().height());
- } else
- setLogicalHeightIfGreater(fontMetrics.height());
- continue;
+ default:
+ ASSERT_NOT_IMPLEMENTED_YET();
+ break;
}
+ };
- if (run.isContainerEnd()) {
- // The line's baseline and height have already been adjusted at ContainerStart.
- ASSERT(inlineContainerNestingLevel);
- --inlineContainerNestingLevel;
- continue;
- }
+ auto shouldRootInlineBoxStretchLineBox = !m_rootInlineBox.isEmpty();
+ if (shouldRootInlineBoxStretchLineBox)
+ computeLineBoxHeight(m_rootInlineBox, VerticalAlign::Baseline);
+ for (auto& inlineBoxEntry : m_inlineBoxRectMap) {
+ auto& inlineBox = *inlineBoxEntry.value;
+ auto shouldInlineBoxStretchLineBox = !inlineBox.isEmpty();
+ if (shouldInlineBoxStretchLineBox)
+ computeLineBoxHeight(inlineBox, inlineBoxEntry.key->style().verticalAlign());
+ }
- if (run.isBox()) {
- auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
- auto marginBoxHeight = boxGeometry.marginBoxHeight();
+ auto lineBoxLogicalHeight = rootStyle.lineHeight().isNegative() ? std::max(recommendedLineBoxHeight, contentLogicalHeight) : recommendedLineBoxHeight;
+ m_rect.setHeight(lineBoxLogicalHeight);
- switch (style.verticalAlign()) {
- case VerticalAlign::Baseline: {
- if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
- // Inline-blocks with inline content always have baselines.
- auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
- // There has to be at least one line -even if it is empty.
- auto& lastLineBox = formattingState.displayInlineContent()->lineBoxes.last();
- auto beforeHeight = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0);
- setAlignmentBaselineIfGreater(beforeHeight + lastLineBox.baseline());
- setLogicalHeightIfGreater(marginBoxHeight);
- } else {
- // Non inline-block boxes sit on the baseline (including their bottom margin).
- setAscentIfGreater(marginBoxHeight);
- // Ignore negative descent (yes, negative descent is a thing).
- setLogicalHeightIfGreater(marginBoxHeight + std::max<InlineLayoutUnit>(0, ascentAndDescent().descent));
- }
- break;
- }
- case VerticalAlign::Top:
- // Top align content never changes the baseline, it only pushes the bottom of the line further down.
- setLogicalHeightIfGreater(marginBoxHeight);
- break;
- case VerticalAlign::Bottom: {
- // Bottom aligned, tall content pushes the baseline further down from the line top.
- auto lineLogicalHeight = logicalHeight();
- if (marginBoxHeight > lineLogicalHeight) {
- setLogicalHeightIfGreater(marginBoxHeight);
- setAlignmentBaselineIfGreater(alignmentBaseline() + (marginBoxHeight - lineLogicalHeight));
- }
- break;
- }
- default:
- ASSERT_NOT_IMPLEMENTED_YET();
- break;
- }
- continue;
+ auto adjustInlineBoxTop = [&](auto& inlineBox, auto textAlignMode) {
+ auto inlineBoxLogicalTop = InlineLayoutUnit { };
+ switch (textAlignMode) {
+ case VerticalAlign::Baseline:
+ inlineBoxLogicalTop = alignmentBaseline - inlineBox.baseline();
+ break;
+ case VerticalAlign::Top:
+ inlineBoxLogicalTop = { };
+ break;
+ case VerticalAlign::Bottom:
+ inlineBoxLogicalTop = logicalBottom() - inlineBox.logicalHeight();
+ break;
+ default:
+ ASSERT_NOT_IMPLEMENTED_YET();
+ break;
}
- }
-}
+ inlineBox.setLogicalTop(inlineBoxLogicalTop);
+ };
-HangingContent LineBox::collectHangingContent(IsLastLineWithInlineContent isLastLineWithInlineContent) const
-{
- auto hangingContent = HangingContent { };
- if (isLastLineWithInlineContent == IsLastLineWithInlineContent::Yes)
- hangingContent.setIsConditional();
- for (auto& run : WTF::makeReversedRange(m_runs)) {
- if (run.isContainerStart() || run.isContainerEnd())
- continue;
- if (run.isLineBreak()) {
- hangingContent.setIsConditional();
- continue;
- }
- if (!run.hasTrailingWhitespace())
- break;
- // Check if we have a preserved or hung whitespace.
- if (run.style().whiteSpace() != WhiteSpace::PreWrap)
- break;
- // This is either a normal or conditionally hanging trailing whitespace.
- hangingContent.expand(run.trailingWhitespaceWidth());
+ alignmentBaseline = halfLeadingMetrics(rootStyle.fontMetrics(), lineBoxLogicalHeight).ascent;
+ adjustInlineBoxTop(m_rootInlineBox, VerticalAlign::Baseline);
+ for (auto& inlineBoxEntry : m_inlineBoxRectMap) {
+ auto& layoutBox = *inlineBoxEntry.key;
+ auto& inlineBox = *inlineBoxEntry.value;
+ adjustInlineBoxTop(inlineBox, layoutBox.style().verticalAlign());
}
- return hangingContent;
}
}
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h 2020-09-03 10:15:04 UTC (rev 266509)
@@ -30,34 +30,52 @@
#include "DisplayBox.h"
#include "DisplayInlineRect.h"
#include "InlineLineBuilder.h"
+#include <wtf/IsoMallocInlines.h>
namespace WebCore {
namespace Layout {
class InlineFormattingContext;
-struct HangingContent;
-struct AscentAndDescent {
- InlineLayoutUnit height() const { return ascent + descent; }
-
- InlineLayoutUnit ascent { 0 };
- InlineLayoutUnit descent { 0 };
-};
-
class LineBox {
WTF_MAKE_FAST_ALLOCATED;
public:
struct InlineBox {
- InlineBox(const Display::InlineRect&, const AscentAndDescent&, const Box&);
+ WTF_MAKE_ISO_ALLOCATED_INLINE(InlineBox);
+ public:
+ enum class IsConsideredEmpty { Yes, No };
+ InlineBox(const Display::InlineRect&, InlineLayoutUnit syntheticBaseline);
+ InlineBox(const Display::InlineRect&, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty);
+ InlineBox() = default;
- Display::InlineRect rect;
- AscentAndDescent ascentAndDescent;
- const Box& layoutBox;
+ const Display::InlineRect& logicalRect() const { return m_logicalRect; }
+ InlineLayoutUnit logicalTop() const { return m_logicalRect.top(); }
+ InlineLayoutUnit logicalBottom() const { return m_logicalRect.bottom(); }
+ InlineLayoutUnit logicalLeft() const { return m_logicalRect.left(); }
+ InlineLayoutUnit logicalWidth() const { return m_logicalRect.width(); }
+ InlineLayoutUnit logicalHeight() const { return m_logicalRect.height(); }
+
+ InlineLayoutUnit baseline() const { return m_baseline; }
+ Optional<InlineLayoutUnit> descent() const { return m_descent; }
+
+ void setLogicalTop(InlineLayoutUnit logicalTop) { m_logicalRect.setTop(logicalTop); }
+ void setLogicalWidth(InlineLayoutUnit logicalWidth) { m_logicalRect.setWidth(logicalWidth); }
+
+ bool isEmpty() const { return m_isEmpty; }
+ void setIsNonEmpty() { m_isEmpty = false; }
+ bool isAtomic() const { return m_isAtomic; }
+
+ private:
+ Display::InlineRect m_logicalRect;
+ InlineLayoutUnit m_baseline;
+ Optional<InlineLayoutUnit> m_descent;
+ bool m_isEmpty { true };
+ bool m_isAtomic { false };
};
enum class IsLastLineWithInlineContent { No, Yes };
enum class IsLineVisuallyEmpty { No, Yes };
- LineBox(const InlineFormattingContext&, const Display::InlineRect&, const LineBuilder::RunList&, IsLineVisuallyEmpty, IsLastLineWithInlineContent);
+ LineBox(const InlineFormattingContext&, const InlineLayoutPoint& topLeft, InlineLayoutUnit logicalWidth, InlineLayoutUnit contentLogicalWidth, const LineBuilder::RunList&, IsLineVisuallyEmpty, IsLastLineWithInlineContent);
InlineLayoutUnit logicalLeft() const { return m_rect.left(); }
InlineLayoutUnit logicalRight() const { return m_rect.right(); }
@@ -69,116 +87,49 @@
const Display::InlineRect& logicalRect() const { return m_rect; }
const Display::InlineRect& scrollableOverflow() const { return m_scrollableOverflow; }
- static AscentAndDescent halfLeadingMetrics(const FontMetrics&, InlineLayoutUnit lineLogicalHeight);
+ const InlineBox& inlineBoxForLayoutBox(const Box&) const;
+ Display::InlineRect inlineRectForTextRun(const LineBuilder::Run&) const;
- // Aligment baseline from line logical top.
- //
- // ------------------- line logical top ------------------- (top align)
- // ^ ^
- // | ^ |
- // ^ | alignment baseline | | alignment baseline
- // | | | |
- // | ascent | | ascent |
- // | | v v
- // v v ------------------- baseline
- // ----------------- baseline ^
- // ^ | descent
- // | descent v
+ // _____________________________________________________ line box logical top
+ // ^
+ // |
+ // ____________________________________ root inline box
+ // ^ |
+ // | |
+ // | root line ascent |
+ // | |
+ // v v
+ // ___________________________________________________ alignment baseline
+ // ^
+ // | root line descent
// v
- // ------------------- line logical bottom -------------------
- InlineLayoutUnit alignmentBaseline() const;
+ // ___________________________________
+ // _____________________________________________________ line box logical bottom
+ InlineLayoutUnit alignmentBaseline() const { return m_rootInlineBox.logicalTop() + m_rootInlineBox.baseline(); }
- const Display::InlineRect& rectForRun(const LineBuilder::Run& run) const { return m_inlineBoxList[m_runToInlineBoxMap.get(&run)].rect; }
-
private:
- const AscentAndDescent& ascentAndDescent() const { return m_rootInlineBox.ascentAndDescent; }
+ void constructInlineBoxes(const LineBuilder::RunList&, IsLineVisuallyEmpty);
+ void alignVertically(IsLineVisuallyEmpty);
- void setAlignmentBaselineIfGreater(InlineLayoutUnit);
- void setAscentIfGreater(InlineLayoutUnit);
- void setDescentIfGreater(InlineLayoutUnit);
- void setLogicalHeightIfGreater(InlineLayoutUnit);
+ InlineLayoutUnit contentLogicalWidth() const { return m_contentLogicalWidth; }
- void setScrollableOverflow(const Display::InlineRect& rect) { m_scrollableOverflow = rect; }
-
- void alignHorizontally(InlineLayoutUnit availableWidth, IsLastLineWithInlineContent);
- void alignVertically();
- void adjustBaselineAndLineHeight();
- HangingContent collectHangingContent(IsLastLineWithInlineContent) const;
-
const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
+ const Box& root() const { return formattingContext().root(); }
LayoutState& layoutState() const { return formattingContext().layoutState(); }
private:
-#if ASSERT_ENABLED
- bool m_hasValidAlignmentBaseline { false };
-#endif
- const InlineFormattingContext& m_inlineFormattingContext;
- const LineBuilder::RunList& m_runs;
Display::InlineRect m_rect;
Display::InlineRect m_scrollableOverflow;
- InlineLayoutUnit m_alignmentBaseline { 0 };
+ InlineLayoutUnit m_contentLogicalWidth { 0 };
+
InlineBox m_rootInlineBox;
- Vector<InlineBox> m_inlineBoxList;
- // FIXME: This is temporary and will be replaced by an inline box map.
- HashMap<const LineBuilder::Run*, size_t> m_runToInlineBoxMap;
+
+ Optional<InlineLayoutUnit> m_lineAlignmentOffset;
+ HashMap<const Box*, std::unique_ptr<InlineBox>> m_inlineBoxRectMap;
+ const InlineFormattingContext& m_inlineFormattingContext;
};
-inline LineBox::InlineBox::InlineBox(const Display::InlineRect& rect, const AscentAndDescent& ascentAndDescent, const Box& layoutBox)
- : rect(rect)
- , ascentAndDescent(ascentAndDescent)
- , layoutBox(layoutBox)
-{
}
-
-inline void LineBox::setLogicalHeightIfGreater(InlineLayoutUnit logicalHeight)
-{
- if (logicalHeight <= m_rect.height())
- return;
- m_rect.setHeight(logicalHeight);
}
-inline void LineBox::setAlignmentBaselineIfGreater(InlineLayoutUnit alignmentBaseline)
-{
-#if ASSERT_ENABLED
- m_hasValidAlignmentBaseline = true;
#endif
- m_alignmentBaseline = std::max(alignmentBaseline, m_alignmentBaseline);
-}
-
-inline void LineBox::setAscentIfGreater(InlineLayoutUnit ascent)
-{
- if (ascent < m_rootInlineBox.ascentAndDescent.ascent)
- return;
- setAlignmentBaselineIfGreater(ascent);
- m_rootInlineBox.ascentAndDescent.ascent = ascent;
-}
-
-inline void LineBox::setDescentIfGreater(InlineLayoutUnit descent)
-{
- if (descent < m_rootInlineBox.ascentAndDescent.descent)
- return;
- m_rootInlineBox.ascentAndDescent.descent = descent;
-}
-
-inline InlineLayoutUnit LineBox::alignmentBaseline() const
-{
- ASSERT(m_hasValidAlignmentBaseline);
- return m_alignmentBaseline;
-}
-
-inline AscentAndDescent LineBox::halfLeadingMetrics(const FontMetrics& fontMetrics, InlineLayoutUnit lineLogicalHeight)
-{
- auto ascent = fontMetrics.ascent();
- auto descent = fontMetrics.descent();
- // 10.8.1 Leading and half-leading
- auto halfLeading = (lineLogicalHeight - (ascent + descent)) / 2;
- // Inline tree height is all integer based.
- auto adjustedAscent = std::max<InlineLayoutUnit>(floorf(ascent + halfLeading), 0);
- auto adjustedDescent = std::max<InlineLayoutUnit>(ceilf(descent + halfLeading), 0);
- return { adjustedAscent, adjustedDescent };
-}
-
-}
-}
-
-#endif
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp 2020-09-03 10:15:04 UTC (rev 266509)
@@ -110,10 +110,18 @@
if (expansionOpportunityCount && availableWidth()) {
// Distribute the extra space.
auto expansionToDistribute = availableWidth() / expansionOpportunityCount;
+ auto accumulatedExpansion = InlineLayoutUnit { };
for (auto& run : m_runs) {
- // Expand and moves runs by the accumulated expansion.
- if (run.hasExpansionOpportunity())
- run.setHorizontalExpansion(expansionToDistribute * run.expansionOpportunityCount());
+ // Expand and move runs by the accumulated expansion.
+ run.moveHorizontally(accumulatedExpansion);
+ if (!run.hasExpansionOpportunity())
+ continue;
+ ASSERT(run.expansionOpportunityCount());
+ auto computedExpansion = expansionToDistribute * run.expansionOpportunityCount();
+ // FIXME: Check why we need to set both.
+ run.setHorizontalExpansion(computedExpansion);
+ run.shrinkHorizontally(-computedExpansion);
+ accumulatedExpansion += computedExpansion;
}
}
};
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h (266508 => 266509)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h 2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h 2020-09-03 10:15:04 UTC (rev 266509)
@@ -77,6 +77,7 @@
InlineLayoutUnit logicalWidth() const { return m_logicalWidth; }
InlineLayoutUnit logicalLeft() const { return m_logicalLeft; }
+ InlineLayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); }
const Display::Run::Expansion& expansion() const { return m_expansion; }
bool hasExpansionOpportunity() const { return m_expansionOpportunityCount; }