Diff
Modified: trunk/Source/WebCore/ChangeLog (250486 => 250487)
--- trunk/Source/WebCore/ChangeLog 2019-09-29 00:48:26 UTC (rev 250486)
+++ trunk/Source/WebCore/ChangeLog 2019-09-29 01:59:27 UTC (rev 250487)
@@ -1,3 +1,33 @@
+2019-09-28 Zalan Bujtas <za...@apple.com>
+
+ [LFC][IFC] Move horizontal alignment to Line
+ https://bugs.webkit.org/show_bug.cgi?id=202351
+ <rdar://problem/55810139>
+
+ Reviewed by Antti Koivisto.
+
+ Line should be able to finalize the run placement including horizontal alignment.
+
+ * layout/Verification.cpp:
+ (WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):
+ * layout/inlineformatting/InlineFormattingContextLineLayout.cpp:
+ (WebCore::Layout::LineInput::LineInput):
+ (WebCore::Layout::LineLayout::LineLayout):
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::layout):
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::computedIntrinsicWidth const):
+ * layout/inlineformatting/InlineLine.cpp:
+ (WebCore::Layout::Line::Line):
+ (WebCore::Layout::Line::isVisuallyEmpty const):
+ (WebCore::Layout::Line::close):
+ (WebCore::Layout::Line::verticalAlignContent):
+ (WebCore::Layout::Line::horizontalAlignContent):
+ (WebCore::Layout::Line::appendInlineContainerStart):
+ (WebCore::Layout::Line::appendTextContent):
+ (WebCore::Layout::Line::appendNonReplacedInlineBox):
+ (WebCore::Layout::Line::appendHardLineBreak):
+ (WebCore::Layout::Line::inlineItemContentHeight const):
+ * layout/inlineformatting/InlineLine.h:
+
2019-09-28 Wenson Hsieh <wenson_hs...@apple.com>
[IDL] Support record<DOMString, *Callback> in bindings
Modified: trunk/Source/WebCore/layout/Verification.cpp (250486 => 250487)
--- trunk/Source/WebCore/layout/Verification.cpp 2019-09-29 00:48:26 UTC (rev 250486)
+++ trunk/Source/WebCore/layout/Verification.cpp 2019-09-29 01:59:27 UTC (rev 250487)
@@ -99,7 +99,11 @@
if (matchingRuns)
continue;
- stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ") (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")";
+ stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ")";
+ stream << " inline run";
+ if (inlineRun.textContext())
+ stream << " (" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ")";
+ stream << " (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalTop() << ") (" << inlineRun.logicalWidth() << "x" << inlineRun.logicalHeight() << ")";
stream.nextLine();
mismatched = true;
}
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h (250486 => 250487)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2019-09-29 00:48:26 UTC (rev 250486)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2019-09-29 01:59:27 UTC (rev 250487)
@@ -68,7 +68,6 @@
LineContent placeInlineItems(const LineInput&) const;
void setupDisplayBoxes(const LineContent&);
- void alignRuns(TextAlignMode, InlineRuns&, unsigned firstRunIndex, LayoutUnit availableWidth) const;
private:
InlineFormattingContext& m_inlineFormattingContext;
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp (250486 => 250487)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp 2019-09-29 00:48:26 UTC (rev 250486)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp 2019-09-29 01:59:27 UTC (rev 250487)
@@ -81,24 +81,34 @@
};
struct LineInput {
- LineInput(const Line::InitialConstraints& initialLineConstraints, Line::SkipVerticalAligment, IndexAndRange firstToProcess, const InlineItems&);
+ LineInput(const Line::InitialConstraints&, TextAlignMode, IndexAndRange firstToProcess, const InlineItems&);
+ LineInput(const Line::InitialConstraints&, IndexAndRange firstToProcess, const InlineItems&);
Line::InitialConstraints initialConstraints;
+ TextAlignMode horizontalAlignment;
// FIXME Alternatively we could just have a second pass with vertical positioning (preferred width computation opts out)
- Line::SkipVerticalAligment skipVerticalAligment;
+ Line::SkipAlignment skipAlignment { Line::SkipAlignment::No };
IndexAndRange firstInlineItem;
const InlineItems& inlineItems;
Optional<LayoutUnit> floatMinimumLogicalBottom;
};
-LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, Line::SkipVerticalAligment skipVerticalAligment, IndexAndRange firstToProcess, const InlineItems& inlineItems)
+LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, TextAlignMode horizontalAlignment, IndexAndRange firstToProcess, const InlineItems& inlineItems)
: initialConstraints(initialLineConstraints)
- , skipVerticalAligment(skipVerticalAligment)
+ , horizontalAlignment(horizontalAlignment)
, firstInlineItem(firstToProcess)
, inlineItems(inlineItems)
{
}
+LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, IndexAndRange firstToProcess, const InlineItems& inlineItems)
+ : initialConstraints(initialLineConstraints)
+ , skipAlignment(Line::SkipAlignment::Yes)
+ , firstInlineItem(firstToProcess)
+ , inlineItems(inlineItems)
+{
+}
+
struct LineContent {
Optional<IndexAndRange> lastCommitted;
Vector<WeakPtr<InlineItem>> floats;
@@ -164,7 +174,7 @@
LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext, const LineInput& lineInput)
: m_inlineFormattingContext(inlineFormattingContext)
, m_lineInput(lineInput)
- , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.skipVerticalAligment)
+ , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.horizontalAlignment, lineInput.skipAlignment)
, m_lineHasIntrusiveFloat(lineInput.initialConstraints.lineIsConstrainedByFloat)
{
}
@@ -281,7 +291,7 @@
auto lineLogicalTop = formattingContext().geometryForBox(formattingRoot()).contentBoxTop();
IndexAndRange currentInlineItem;
while (currentInlineItem.index < inlineItems.size()) {
- auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), Line::SkipVerticalAligment::No, currentInlineItem, inlineItems };
+ auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), formattingRoot().style().textAlign(), currentInlineItem, inlineItems };
auto lineLayout = LineLayout { formattingContext(), lineInput };
auto lineContent = lineLayout.layout();
@@ -349,7 +359,7 @@
while (currentInlineItem.index < inlineItems.size()) {
// Only the horiztonal available width is constrained when computing intrinsic width.
auto initialLineConstraints = Line::InitialConstraints { { }, widthConstraint(), false, { } };
- auto lineInput = LineInput { initialLineConstraints, Line::SkipVerticalAligment::Yes, currentInlineItem, inlineItems };
+ auto lineInput = LineInput { initialLineConstraints, currentInlineItem, inlineItems };
auto lineContent = LineLayout(formattingContext, lineInput).layout();
@@ -380,11 +390,6 @@
floatingContext.append(floatBox);
}
- auto& inlineDisplayRuns = formattingState.inlineRuns();
- auto previousLineLastRunIndex = Optional<unsigned> { inlineDisplayRuns.isEmpty() ? Optional<unsigned>() : inlineDisplayRuns.size() - 1 };
- // 9.4.2 Inline formatting contexts
- // A line box is always tall enough for all of the boxes it contains.
-
// Add final display runs to state.
for (auto& lineRun : lineContent.runList) {
// Inline level containers (<span>) don't generate inline runs.
@@ -393,6 +398,7 @@
formattingState.addInlineRun(lineRun->displayRun());
}
+ // Compute box final geometry.
auto geometry = formattingContext.geometry();
auto& lineRuns = lineContent.runList;
for (unsigned index = 0; index < lineRuns.size(); ++index) {
@@ -456,44 +462,10 @@
}
ASSERT_NOT_REACHED();
}
- // FIXME linebox needs to be ajusted after content alignment.
formattingState.addLineBox(lineContent.lineBox);
- alignRuns(formattingRoot().style().textAlign(), inlineDisplayRuns, previousLineLastRunIndex.valueOr(-1) + 1, widthConstraint() - lineContent.lineBox.logicalWidth());
}
-static Optional<LayoutUnit> horizontalAdjustmentForAlignment(TextAlignMode align, LayoutUnit remainingWidth)
-{
- switch (align) {
- case TextAlignMode::Left:
- case TextAlignMode::WebKitLeft:
- case TextAlignMode::Start:
- return { };
- case TextAlignMode::Right:
- case TextAlignMode::WebKitRight:
- case TextAlignMode::End:
- return std::max(remainingWidth, 0_lu);
- case TextAlignMode::Center:
- case TextAlignMode::WebKitCenter:
- return std::max(remainingWidth / 2, 0_lu);
- case TextAlignMode::Justify:
- ASSERT_NOT_REACHED();
- break;
- }
- ASSERT_NOT_REACHED();
- return { };
}
-
-void InlineFormattingContext::InlineLayout::alignRuns(TextAlignMode textAlign, InlineRuns& inlineDisplayRuns, unsigned firstRunIndex, LayoutUnit availableWidth) const
-{
- auto adjustment = horizontalAdjustmentForAlignment(textAlign, availableWidth);
- if (!adjustment)
- return;
-
- for (unsigned index = firstRunIndex; index < inlineDisplayRuns.size(); ++index)
- inlineDisplayRuns[index].moveHorizontally(*adjustment);
}
-}
-}
-
#endif
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp (250486 => 250487)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp 2019-09-29 00:48:26 UTC (rev 250486)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp 2019-09-29 01:59:27 UTC (rev 250487)
@@ -57,13 +57,14 @@
return !downcast<InlineTextItem>(m_inlineItem).isCollapsed() && !isVisuallyEmpty();
}
-Line::Line(const InlineFormattingContext& inlineFormattingContext, const InitialConstraints& initialConstraints, SkipVerticalAligment skipVerticalAligment)
+Line::Line(const InlineFormattingContext& inlineFormattingContext, const InitialConstraints& initialConstraints, Optional<TextAlignMode> horizontalAlignment, SkipAlignment skipAlignment)
: m_inlineFormattingContext(inlineFormattingContext)
, m_initialStrut(initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->strut : WTF::nullopt)
, m_lineLogicalWidth(initialConstraints.availableLogicalWidth)
- , m_skipVerticalAligment(skipVerticalAligment == SkipVerticalAligment::Yes)
+ , m_horizontalAlignment(horizontalAlignment)
+ , m_skipAlignment(skipAlignment == SkipAlignment::Yes)
{
- ASSERT(m_skipVerticalAligment || initialConstraints.heightAndBaseline);
+ ASSERT(m_skipAlignment || initialConstraints.heightAndBaseline);
auto initialLineHeight = initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->height : LayoutUnit();
auto initialBaselineOffset = initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->baselineOffset : LayoutUnit();
auto lineRect = Display::Rect { initialConstraints.logicalTopLeft, { }, initialLineHeight };
@@ -96,7 +97,7 @@
auto& boxGeometry = formattingContext.geometryForBox(run->layoutBox());
if (!boxGeometry.width())
continue;
- if (m_skipVerticalAligment || boxGeometry.height())
+ if (m_skipAlignment || boxGeometry.height())
return false;
continue;
}
@@ -109,62 +110,7 @@
Line::RunList Line::close()
{
removeTrailingTrimmableContent();
- if (!m_skipVerticalAligment) {
- if (isVisuallyEmpty()) {
- m_lineBox.baseline().reset();
- m_lineBox.setBaselineOffset({ });
- m_lineBox.setLogicalHeight({ });
- }
-
- // Remove descent when all content is baseline aligned but none of them have descent.
- if (formattingContext().quirks().lineDescentNeedsCollapsing(m_runList)) {
- m_lineBox.shrinkVertically(m_lineBox.baseline().descent());
- m_lineBox.baseline().setDescent({ });
- }
-
- auto& layoutState = this->layoutState();
- auto& formattingContext = this->formattingContext();
- for (auto& run : m_runList) {
- LayoutUnit logicalTop;
- auto& layoutBox = run->layoutBox();
- auto verticalAlign = layoutBox.style().verticalAlign();
- auto ascent = layoutBox.style().fontMetrics().ascent();
-
- switch (verticalAlign) {
- case VerticalAlign::Baseline:
- if (run->isLineBreak() || run->isText())
- logicalTop = baselineOffset() - ascent;
- else if (run->isContainerStart()) {
- auto& boxGeometry = formattingContext.geometryForBox(layoutBox);
- logicalTop = baselineOffset() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0);
- } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
- auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox)));
- // Spec makes us generate at least one line -even if it is empty.
- ASSERT(!formattingState.lineBoxes().isEmpty());
- auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
- logicalTop = baselineOffset() - inlineBlockBaseline.ascent();
- } else
- logicalTop = baselineOffset() - run->logicalRect().height();
- break;
- case VerticalAlign::Top:
- logicalTop = { };
- break;
- case VerticalAlign::Bottom:
- logicalTop = logicalBottom() - run->logicalRect().height();
- break;
- default:
- ASSERT_NOT_IMPLEMENTED_YET();
- break;
- }
- run->adjustLogicalTop(logicalTop);
- // Convert runs from relative to the line top/left to the formatting root's border box top/left.
- run->moveVertically(this->logicalTop());
- run->moveHorizontally(this->logicalLeft());
- }
- }
-
- // Let's join text runs together when possible.
- // FIXME: Check if we can do it as part of the loop above.
+ // Join text runs together when possible.
unsigned index = 1;
while (index < m_runList.size()) {
auto& previousRun = m_runList[index - 1];
@@ -184,9 +130,106 @@
previousRun->expand(*currentRun);
m_runList.remove(index);
}
+
+ if (!m_skipAlignment) {
+ alignContentVertically();
+ alignContentHorizontally();
+ }
+
return WTFMove(m_runList);
}
+void Line::alignContentVertically()
+{
+ ASSERT(!m_skipAlignment);
+
+ if (isVisuallyEmpty()) {
+ m_lineBox.baseline().reset();
+ m_lineBox.setBaselineOffset({ });
+ m_lineBox.setLogicalHeight({ });
+ }
+
+ // Remove descent when all content is baseline aligned but none of them have descent.
+ if (formattingContext().quirks().lineDescentNeedsCollapsing(m_runList)) {
+ m_lineBox.shrinkVertically(m_lineBox.baseline().descent());
+ m_lineBox.baseline().setDescent({ });
+ }
+
+ auto& layoutState = this->layoutState();
+ auto& formattingContext = this->formattingContext();
+ for (auto& run : m_runList) {
+ LayoutUnit logicalTop;
+ auto& layoutBox = run->layoutBox();
+ auto verticalAlign = layoutBox.style().verticalAlign();
+ auto ascent = layoutBox.style().fontMetrics().ascent();
+
+ switch (verticalAlign) {
+ case VerticalAlign::Baseline:
+ if (run->isLineBreak() || run->isText())
+ logicalTop = baselineOffset() - ascent;
+ else if (run->isContainerStart()) {
+ auto& boxGeometry = formattingContext.geometryForBox(layoutBox);
+ logicalTop = baselineOffset() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0);
+ } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
+ auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox)));
+ // Spec makes us generate at least one line -even if it is empty.
+ ASSERT(!formattingState.lineBoxes().isEmpty());
+ auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
+ logicalTop = baselineOffset() - inlineBlockBaseline.ascent();
+ } else
+ logicalTop = baselineOffset() - run->logicalRect().height();
+ break;
+ case VerticalAlign::Top:
+ logicalTop = { };
+ break;
+ case VerticalAlign::Bottom:
+ logicalTop = logicalBottom() - run->logicalRect().height();
+ break;
+ default:
+ ASSERT_NOT_IMPLEMENTED_YET();
+ break;
+ }
+ run->adjustLogicalTop(logicalTop);
+ // Convert runs from relative to the line top/left to the formatting root's border box top/left.
+ run->moveVertically(this->logicalTop());
+ run->moveHorizontally(this->logicalLeft());
+ }
+}
+
+void Line::alignContentHorizontally()
+{
+ ASSERT(!m_skipAlignment);
+
+ auto adjustmentForAlignment = [&]() -> Optional<LayoutUnit> {
+ switch (*m_horizontalAlignment) {
+ case TextAlignMode::Left:
+ case TextAlignMode::WebKitLeft:
+ case TextAlignMode::Start:
+ return { };
+ case TextAlignMode::Right:
+ case TextAlignMode::WebKitRight:
+ case TextAlignMode::End:
+ return std::max(availableWidth(), 0_lu);
+ case TextAlignMode::Center:
+ case TextAlignMode::WebKitCenter:
+ return std::max(availableWidth() / 2, 0_lu);
+ case TextAlignMode::Justify:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return { };
+ };
+
+ auto adjustment = adjustmentForAlignment();
+ if (!adjustment)
+ return;
+
+ for (auto& run : m_runList)
+ run->moveHorizontally(*adjustment);
+ // FIXME: Find out if m_lineBox needs adjustmnent as well.
+}
+
void Line::removeTrailingTrimmableContent()
{
// Collapse trimmable trailing content
@@ -251,7 +294,7 @@
logicalRect.setLeft(contentLogicalWidth());
logicalRect.setWidth(logicalWidth);
- if (!m_skipVerticalAligment) {
+ if (!m_skipAlignment) {
auto logicalHeight = inlineItemContentHeight(inlineItem);
adjustBaselineAndLineHeight(inlineItem, logicalHeight);
logicalRect.setHeight(logicalHeight);
@@ -298,7 +341,7 @@
auto logicalRect = Display::Rect { };
logicalRect.setLeft(contentLogicalWidth());
logicalRect.setWidth(logicalWidth);
- if (!m_skipVerticalAligment) {
+ if (!m_skipAlignment) {
auto runHeight = inlineItemContentHeight(inlineItem);
logicalRect.setHeight(runHeight);
adjustBaselineAndLineHeight(inlineItem, runHeight);
@@ -325,7 +368,7 @@
logicalRect.setLeft(contentLogicalWidth() + horizontalMargin.start);
logicalRect.setWidth(logicalWidth);
- if (!m_skipVerticalAligment) {
+ if (!m_skipAlignment) {
adjustBaselineAndLineHeight(inlineItem, boxGeometry.marginBoxHeight());
logicalRect.setHeight(inlineItemContentHeight(inlineItem));
}
@@ -346,7 +389,7 @@
auto logicalRect = Display::Rect { };
logicalRect.setLeft(contentLogicalWidth());
logicalRect.setWidth({ });
- if (!m_skipVerticalAligment) {
+ if (!m_skipAlignment) {
adjustBaselineAndLineHeight(inlineItem, { });
logicalRect.setHeight(logicalHeight());
}
@@ -426,7 +469,7 @@
LayoutUnit Line::inlineItemContentHeight(const InlineItem& inlineItem) const
{
- ASSERT(!m_skipVerticalAligment);
+ ASSERT(!m_skipAlignment);
auto& fontMetrics = inlineItem.style().fontMetrics();
if (inlineItem.isLineBreak() || is<InlineTextItem>(inlineItem))
return fontMetrics.height();
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLine.h (250486 => 250487)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLine.h 2019-09-29 00:48:26 UTC (rev 250486)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLine.h 2019-09-29 01:59:27 UTC (rev 250487)
@@ -51,8 +51,8 @@
};
Optional<HeightAndBaseline> heightAndBaseline;
};
- enum class SkipVerticalAligment { No, Yes };
- Line(const InlineFormattingContext&, const InitialConstraints&, SkipVerticalAligment);
+ enum class SkipAlignment { No, Yes };
+ Line(const InlineFormattingContext&, const InitialConstraints&, Optional<TextAlignMode>, SkipAlignment);
void append(const InlineItem&, LayoutUnit logicalWidth);
bool hasContent() const { return !isVisuallyEmpty(); }
@@ -125,6 +125,8 @@
void appendHardLineBreak(const InlineItem&);
void removeTrailingTrimmableContent();
+ void alignContentHorizontally();
+ void alignContentVertically();
void adjustBaselineAndLineHeight(const InlineItem&, LayoutUnit runHeight);
LayoutUnit inlineItemContentHeight(const InlineItem&) const;
@@ -139,7 +141,8 @@
Optional<LineBox::Baseline> m_initialStrut;
LayoutUnit m_lineLogicalWidth;
- bool m_skipVerticalAligment { false };
+ Optional<TextAlignMode> m_horizontalAlignment;
+ bool m_skipAlignment { false };
LineBox m_lineBox;
};