[LFC][IFC] Add (right, center)text-align support.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Oct 2018 16:02:48 +0000 (16:02 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Oct 2018 16:02:48 +0000 (16:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190745

Reviewed by Antti Koivisto.

Adjust the logical left of each run while closing the line.

* layout/Verification.cpp:
(WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):
(WebCore::Layout::outputMismatchingComplexLineInformationIfNeeded):
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::trimLeadingRun):
(WebCore::Layout::InlineFormattingContext::layoutInlineContent const):
* layout/inlineformatting/InlineFormattingContext.h:
(WebCore::Layout::InlineFormattingContext::Line::hasContent const):
(WebCore::Layout::InlineFormattingContext::Line::contentLogicalLeft const): Deleted.
* layout/inlineformatting/InlineLineBreaker.cpp:
(WebCore::Layout::InlineLineBreaker::nextRun):
(WebCore::Layout::InlineLineBreaker::splitRun):
* layout/inlineformatting/InlineLineBreaker.h:
* layout/inlineformatting/InlineRun.h:
(WebCore::Layout::InlineRun::setLogicalLeft):
(WebCore::Layout::InlineRun::TextContext::start const):
(WebCore::Layout::InlineRun::createRun):
(WebCore::Layout::InlineRun::createTextRun):
(WebCore::Layout::InlineRun::InlineRun):
(WebCore::Layout::InlineRun::TextContext::TextContext):
(WebCore::Layout::InlineRun::TextContext::position const): Deleted.
* layout/inlineformatting/Line.cpp:
(WebCore::Layout::InlineFormattingContext::Line::Line):
(WebCore::Layout::InlineFormattingContext::Line::init):
(WebCore::Layout::adjustedLineLogicalLeft):
(WebCore::Layout::InlineFormattingContext::Line::contentLogicalRight):
(WebCore::Layout::InlineFormattingContext::Line::appendContent):
(WebCore::Layout::InlineFormattingContext::Line::close):
(WebCore::Layout::InlineFormattingContext::Line::setConstraints): Deleted.
* layout/layouttree/LayoutTreeBuilder.cpp:
(WebCore::Layout::outputInlineRuns):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237323 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/layout/Verification.cpp
Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
Source/WebCore/layout/inlineformatting/InlineFormattingContext.h
Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp
Source/WebCore/layout/inlineformatting/InlineLineBreaker.h
Source/WebCore/layout/inlineformatting/InlineRun.h
Source/WebCore/layout/inlineformatting/Line.cpp
Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp

index 2cfc6ad..09edd26 100644 (file)
@@ -1,5 +1,46 @@
 2018-10-22  Zalan Bujtas  <zalan@apple.com>
 
+        [LFC][IFC] Add (right, center)text-align support.
+        https://bugs.webkit.org/show_bug.cgi?id=190745
+
+        Reviewed by Antti Koivisto.
+
+        Adjust the logical left of each run while closing the line.
+
+        * layout/Verification.cpp:
+        (WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):
+        (WebCore::Layout::outputMismatchingComplexLineInformationIfNeeded):
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::trimLeadingRun):
+        (WebCore::Layout::InlineFormattingContext::layoutInlineContent const):
+        * layout/inlineformatting/InlineFormattingContext.h:
+        (WebCore::Layout::InlineFormattingContext::Line::hasContent const):
+        (WebCore::Layout::InlineFormattingContext::Line::contentLogicalLeft const): Deleted.
+        * layout/inlineformatting/InlineLineBreaker.cpp:
+        (WebCore::Layout::InlineLineBreaker::nextRun):
+        (WebCore::Layout::InlineLineBreaker::splitRun):
+        * layout/inlineformatting/InlineLineBreaker.h:
+        * layout/inlineformatting/InlineRun.h:
+        (WebCore::Layout::InlineRun::setLogicalLeft):
+        (WebCore::Layout::InlineRun::TextContext::start const):
+        (WebCore::Layout::InlineRun::createRun):
+        (WebCore::Layout::InlineRun::createTextRun):
+        (WebCore::Layout::InlineRun::InlineRun):
+        (WebCore::Layout::InlineRun::TextContext::TextContext):
+        (WebCore::Layout::InlineRun::TextContext::position const): Deleted.
+        * layout/inlineformatting/Line.cpp:
+        (WebCore::Layout::InlineFormattingContext::Line::Line):
+        (WebCore::Layout::InlineFormattingContext::Line::init):
+        (WebCore::Layout::adjustedLineLogicalLeft):
+        (WebCore::Layout::InlineFormattingContext::Line::contentLogicalRight):
+        (WebCore::Layout::InlineFormattingContext::Line::appendContent):
+        (WebCore::Layout::InlineFormattingContext::Line::close):
+        (WebCore::Layout::InlineFormattingContext::Line::setConstraints): Deleted.
+        * layout/layouttree/LayoutTreeBuilder.cpp:
+        (WebCore::Layout::outputInlineRuns):
+
+2018-10-22  Zalan Bujtas  <zalan@apple.com>
+
         [LFC][IFC] Implement Replaced helper class.
         https://bugs.webkit.org/show_bug.cgi?id=190719
 
index 180d248..e0bce4f 100644 (file)
@@ -73,11 +73,11 @@ static bool outputMismatchingSimpleLineInformationIfNeeded(TextStream& stream, c
 
         auto matchingRuns = areEssentiallyEqual(simpleRun.logicalLeft, inlineRun.logicalLeft()) && areEssentiallyEqual(simpleRun.logicalRight, inlineRun.logicalRight());
         if (matchingRuns)
-            matchingRuns = (simpleRun.start == inlineRun.textContext()->position() && simpleRun.end == (inlineRun.textContext()->position() + inlineRun.textContext()->length()));
+            matchingRuns = (simpleRun.start == inlineRun.textContext()->start() && simpleRun.end == (inlineRun.textContext()->start() + inlineRun.textContext()->length()));
         if (matchingRuns)
             continue;
 
-        stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun.textContext()->position() << ", " << inlineRun.textContext()->position() + inlineRun.textContext()->length() << ") (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")";
+        stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")";
         stream.nextLine();
         mismatched = true;
     }
@@ -107,7 +107,7 @@ static bool outputMismatchingComplexLineInformationIfNeeded(TextStream& stream,
             auto matchingRuns = areEssentiallyEqual(lineBox->logicalLeft(), inlineRun.logicalLeft()) && areEssentiallyEqual(lineBox->logicalRight(), inlineRun.logicalRight());
             if (matchingRuns && inlineTextBox) {
                 ASSERT(inlineRun.textContext());
-                matchingRuns = inlineTextBox->start() == inlineRun.textContext()->position() && inlineTextBox->end() + 1 == (inlineRun.textContext()->position() + inlineRun.textContext()->length());
+                matchingRuns = inlineTextBox->start() == inlineRun.textContext()->start() && inlineTextBox->end() + 1 == (inlineRun.textContext()->start() + inlineRun.textContext()->length());
             }
 
             if (!matchingRuns) {
@@ -119,7 +119,7 @@ static bool outputMismatchingComplexLineInformationIfNeeded(TextStream& stream,
 
                 stream << "layout run ";
                 if (inlineRun.textContext())
-                    stream << "(" << inlineRun.textContext()->position() << ", " << inlineRun.textContext()->position() + inlineRun.textContext()->length() << ") ";
+                    stream << "(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") ";
                 stream << "(" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")";
                 stream.nextLine();
                 mismatched = true;
index ed7e5bd..81436d9 100644 (file)
@@ -95,11 +95,10 @@ static bool trimLeadingRun(const InlineLineBreaker::Run& run)
 {
     ASSERT(run.position == InlineLineBreaker::Run::Position::LineBegin);
 
-    auto& inlineRun = run.inlineRun;
-    if (!inlineRun.isWhitespace())
+    if (!run.content.isWhitespace())
         return false;
 
-    return inlineRun.style().collapseWhiteSpace();
+    return run.content.style().collapseWhiteSpace();
 }
 
 void InlineFormattingContext::layoutInlineContent(const LayoutContext& layoutContext, InlineFormattingState& inlineFormattingState, const InlineRunProvider& inlineRunProvider) const
@@ -111,11 +110,11 @@ void InlineFormattingContext::layoutInlineContent(const LayoutContext& layoutCon
     auto availableWidth = formattingRootDisplayBox.contentBoxWidth();
     auto previousRunPositionIsLineEnd = false;
 
-    Line line(inlineFormattingState);
-    line.setConstraints(lineLogicalLeft, availableWidth);
+    Line line(inlineFormattingState, root());
+    line.init(lineLogicalLeft, availableWidth);
 
     InlineLineBreaker lineBreaker(layoutContext, inlineFormattingState.inlineContent(), inlineRunProvider.runs());
-    while (auto run = lineBreaker.nextRun(line.contentLogicalLeft(), line.availableWidth(), !line.hasContent())) {
+    while (auto run = lineBreaker.nextRun(line.contentLogicalRight(), line.availableWidth(), !line.hasContent())) {
 
         if (run->position == InlineLineBreaker::Run::Position::LineBegin) {
             // First run on line.
@@ -123,7 +122,7 @@ void InlineFormattingContext::layoutInlineContent(const LayoutContext& layoutCon
             // Previous run ended up being at the line end. Adjust the line accordingly.
             if (!previousRunPositionIsLineEnd) {
                 line.close();
-                line.setConstraints(lineLogicalLeft, availableWidth);
+                line.init(lineLogicalLeft, availableWidth);
             }
             // Skip leading whitespace.
             if (!trimLeadingRun(*run))
@@ -137,7 +136,7 @@ void InlineFormattingContext::layoutInlineContent(const LayoutContext& layoutCon
             line.appendContent(*run);
             // Move over to the next line.
             line.close();
-            line.setConstraints(lineLogicalLeft, availableWidth);
+            line.init(lineLogicalLeft, availableWidth);
             continue;
         }
 
index 1384c1d..2d9fcf4 100644 (file)
@@ -49,13 +49,14 @@ public:
 private:
     class Line {
     public:
-        Line(InlineFormattingState&);
+        Line(InlineFormattingState&, const Box& formattingRoot);
 
-        void setConstraints(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth);
+        void init(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth);
         void appendContent(const InlineLineBreaker::Run&);
         void close();
-        bool hasContent() const { return !m_isEmpty; }
-        LayoutUnit contentLogicalLeft() const { return m_contentLogicalLeft; }
+
+        bool hasContent() const { return m_firstRunIndex.has_value(); }
+        LayoutUnit contentLogicalRight();
         LayoutUnit availableWidth() const { return m_availableWidth; }
 
     private:
@@ -64,11 +65,16 @@ private:
             unsigned length;
         };
         std::optional<TrailingTrimmableContent> m_trailingTrimmableContent;
-        InlineFormattingState& m_inlineFormattingState;
-        LayoutUnit m_contentLogicalLeft;
-        LayoutUnit m_availableWidth;
-        bool m_isEmpty { true };
         bool m_lastRunIsNotCollapsedText { true };
+
+        InlineFormattingState& m_formattingState;
+        const Box& m_formattingRoot;
+
+        LayoutUnit m_lineLogicalLeft;
+        LayoutUnit m_availableWidth;
+        LayoutUnit m_lineWidth;
+
+        std::optional<unsigned> m_firstRunIndex;
     };
 
     void layoutInlineContent(const LayoutContext&, InlineFormattingState&, const InlineRunProvider&) const;
index 2b4ce59..fbb05c3 100644 (file)
@@ -60,32 +60,32 @@ std::optional<InlineLineBreaker::Run> InlineLineBreaker::nextRun(LayoutUnit cont
 
     if (currentInlineRun.isLineBreak()) {
         ++m_currentRunIndex;
-        return Run { Run::Position::LineEnd, currentInlineRun, 0 };
+        return Run { Run::Position::LineEnd, 0, currentInlineRun };
     }
 
     auto contentWidth = runWidth(currentInlineRun, contentLogicalLeft);
     // 1. Plenty of space left.
     if (contentWidth <= availableWidth) {
         ++m_currentRunIndex;
-        return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, currentInlineRun, contentWidth };
+        return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, contentWidth, currentInlineRun };
     }
 
     // 2. No space left whatsoever.
     if (availableWidth <= 0) {
         ++m_currentRunIndex;
-        return Run { Run::Position::LineBegin, currentInlineRun, contentWidth };
+        return Run { Run::Position::LineBegin, contentWidth, currentInlineRun };
     }
 
     // 3. Some space left. Let's find out what we need to do with this run.
     auto breakingBehavior = lineBreakingBehavior(currentInlineRun, lineIsEmpty);
     if (breakingBehavior == LineBreakingBehavior::Keep) {
         ++m_currentRunIndex;
-        return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, currentInlineRun, contentWidth };
+        return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, contentWidth, currentInlineRun };
     }
 
     if (breakingBehavior == LineBreakingBehavior::WrapToNextLine) {
         ++m_currentRunIndex;
-        return Run { Run::Position::LineBegin, currentInlineRun, contentWidth };
+        return Run { Run::Position::LineBegin, contentWidth, currentInlineRun };
     }
 
     ASSERT(breakingBehavior == LineBreakingBehavior::Break);
@@ -154,7 +154,7 @@ LayoutUnit InlineLineBreaker::runWidth(const InlineRunProvider::Run& inlineRun,
 
 InlineLineBreaker::Run InlineLineBreaker::splitRun(const InlineRunProvider::Run& inlineRun, LayoutUnit, LayoutUnit, bool)
 {
-    return { Run::Position::Undetermined, inlineRun, { } };
+    return { Run::Position::Undetermined, { }, inlineRun };
 }
 
 std::optional<ItemPosition> InlineLineBreaker::adjustSplitPositionWithHyphenation(const InlineRunProvider::Run&, ItemPosition, LayoutUnit, LayoutUnit, bool) const
index 19a53ec..153dda8 100644 (file)
@@ -42,8 +42,8 @@ public:
     struct Run {
         enum class Position { Undetermined, LineBegin, LineEnd };
         Position position;
-        InlineRunProvider::Run inlineRun;
         LayoutUnit width;
+        InlineRunProvider::Run content;
     };
     std::optional<Run> nextRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty);
 
index c277758..280e68b 100644 (file)
@@ -34,33 +34,37 @@ namespace WebCore {
 namespace Layout {
 
 struct InlineRun {
-    InlineRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&);
-    InlineRun(LayoutUnit logcialLeft, LayoutUnit width, ItemPosition, unsigned length, const InlineItem&);
+    static InlineRun createRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&);
+    static InlineRun createTextRun(LayoutUnit logcialLeft, LayoutUnit width, ItemPosition, unsigned length, const InlineItem&);
 
     LayoutUnit logicalLeft() const { return m_logicalLeft; }
     LayoutUnit logicalRight() const { return logicalLeft() + width(); }
     LayoutUnit width() const { return m_width; }
 
     void setWidth(LayoutUnit width) { m_width = width; }
+    void setLogicalLeft(LayoutUnit logicalLeft) { m_logicalLeft = logicalLeft; }
     void setLogicalRight(LayoutUnit logicalRight) { m_width -= (this->logicalRight() - logicalRight); }
 
     struct TextContext {
     public:
         TextContext(ItemPosition, unsigned length);
 
-        ItemPosition position() const { return m_position; }
+        ItemPosition start() const { return m_start; }
         unsigned length() const { return m_length; }
 
         void setLength(unsigned length) { m_length = length; }
 
     private:
-        ItemPosition m_position;
+        ItemPosition m_start;
         unsigned m_length;
     };
     std::optional<TextContext>& textContext() { return m_textContext; }
     const InlineItem& inlineItem() const { return m_inlineItem; }
 
 private:
+    InlineRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&);
+    InlineRun(LayoutUnit logcialLeft, LayoutUnit width, ItemPosition, unsigned length, const InlineItem&);
+
     LayoutUnit m_logicalLeft;
     LayoutUnit m_width;
 
@@ -70,6 +74,16 @@ private:
 
 using InlineRuns = Vector<InlineRun>;
 
+inline InlineRun InlineRun::createRun(LayoutUnit logicalLeft, LayoutUnit width, const InlineItem& inlineItem)
+{
+    return { logicalLeft, width, inlineItem };
+}
+
+inline InlineRun InlineRun::createTextRun(LayoutUnit logicalLeft, LayoutUnit width, ItemPosition start, unsigned length, const InlineItem& inlineItem)
+{
+    return { logicalLeft, width, start, length, inlineItem };
+}
+
 inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, const InlineItem& inlineItem)
     : m_logicalLeft(logicalLeft)
     , m_width(width)
@@ -77,16 +91,16 @@ inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, const Inli
 {
 }
 
-inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, ItemPosition position, unsigned length, const InlineItem& inlineItem)
+inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, ItemPosition start, unsigned length, const InlineItem& inlineItem)
     : m_logicalLeft(logicalLeft)
     , m_width(width)
     , m_inlineItem(inlineItem)
-    , m_textContext(TextContext { position, length })
+    , m_textContext(TextContext { start, length })
 {
 }
 
-inline InlineRun::TextContext::TextContext(ItemPosition position, unsigned length)
-    : m_position(position)
+inline InlineRun::TextContext::TextContext(ItemPosition start, unsigned length)
+    : m_start(start)
     , m_length(length)
 {
 }
index 2342bee..11c89ab 100644 (file)
 namespace WebCore {
 namespace Layout {
 
-InlineFormattingContext::Line::Line(InlineFormattingState& inlineFormattingState)
-    : m_inlineFormattingState(inlineFormattingState)
+InlineFormattingContext::Line::Line(InlineFormattingState& formattingState, const Box& formattingRoot)
+    : m_formattingState(formattingState)
+    , m_formattingRoot(formattingRoot)
 {
 }
 
-void InlineFormattingContext::Line::setConstraints(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth)
+void InlineFormattingContext::Line::init(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth)
 {
-    m_contentLogicalLeft = lineLogicalLeft;
+    m_lineLogicalLeft = lineLogicalLeft;
+    m_lineWidth = availableWidth;
     m_availableWidth = availableWidth;
+    m_firstRunIndex = { };
+}
+
+static LayoutUnit adjustedLineLogicalLeft(TextAlignMode align, LayoutUnit lineLogicalLeft, LayoutUnit remainingWidth)
+{
+    switch (align) {
+    case TextAlignMode::Left:
+    case TextAlignMode::WebKitLeft:
+    case TextAlignMode::Start:
+        return lineLogicalLeft;
+    case TextAlignMode::Right:
+    case TextAlignMode::WebKitRight:
+    case TextAlignMode::End:
+        return lineLogicalLeft + std::max(remainingWidth, LayoutUnit());
+    case TextAlignMode::Center:
+    case TextAlignMode::WebKitCenter:
+        return lineLogicalLeft + std::max(remainingWidth / 2, LayoutUnit());
+    case TextAlignMode::Justify:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return lineLogicalLeft;
 }
 
 static bool isNonCollapsedText(const InlineRunProvider::Run& inlineRun)
@@ -54,38 +79,46 @@ static bool isTrimmableContent(const InlineRunProvider::Run& inlineRun)
     return inlineRun.isWhitespace() && inlineRun.style().collapseWhiteSpace();
 }
 
+LayoutUnit InlineFormattingContext::Line::contentLogicalRight()
+{
+    if (!m_firstRunIndex.has_value())
+        return m_lineLogicalLeft;
+
+    return m_formattingState.inlineRuns().last().logicalRight();
+}
+
 void InlineFormattingContext::Line::appendContent(const InlineLineBreaker::Run& run)
 {
     auto lastRunWasNotCollapsedText = m_lastRunIsNotCollapsedText;
-    auto hadContent = hasContent();
-    auto contentLogicalLeft = m_contentLogicalLeft;
     m_trailingTrimmableContent = { };
-
-    auto& inlineRun = run.inlineRun;
     m_availableWidth -= run.width;
-    m_lastRunIsNotCollapsedText = isNonCollapsedText(inlineRun);
-    m_isEmpty = false;
-    m_contentLogicalLeft += run.width;
+
+    auto& content = run.content;
+    m_lastRunIsNotCollapsedText = isNonCollapsedText(content);
 
     // Append this text run to the end of the last text run, if the last run is continuous.
-    if (inlineRun.isText()) {
-        auto textContext = inlineRun.textContext();
+    std::optional<InlineRun::TextContext> textRun;
+    if (content.isText()) {
+        auto textContext = content.textContext();
         auto runLength = textContext->isCollapsed() ? 1 : textContext->length();
 
-        if (isTrimmableContent(inlineRun))
+        if (isTrimmableContent(content))
             m_trailingTrimmableContent = TrailingTrimmableContent { run.width, runLength };
 
-        if (hadContent && lastRunWasNotCollapsedText) {
-            auto& inlineRun = m_inlineFormattingState.inlineRuns().last();
+        if (hasContent() && lastRunWasNotCollapsedText) {
+            auto& inlineRun = m_formattingState.inlineRuns().last();
             inlineRun.setWidth(inlineRun.width() + run.width);
             inlineRun.textContext()->setLength(inlineRun.textContext()->length() + runLength);
             return;
         }
-
-        return m_inlineFormattingState.appendInlineRun({ contentLogicalLeft, run.width, textContext->start(), runLength, inlineRun.inlineItem()});
+        textRun = InlineRun::TextContext { textContext->start(), runLength };
     }
 
-    m_inlineFormattingState.appendInlineRun({ contentLogicalLeft, run.width, inlineRun.inlineItem() });
+    if (textRun)
+        m_formattingState.appendInlineRun(InlineRun::createTextRun(contentLogicalRight(), run.width, textRun->start(), textRun->length(), content.inlineItem()));
+    else
+        m_formattingState.appendInlineRun(InlineRun::createRun(contentLogicalRight(), run.width, content.inlineItem()));
+    m_firstRunIndex = m_firstRunIndex.value_or(m_formattingState.inlineRuns().size() - 1);
 }
 
 void InlineFormattingContext::Line::close()
@@ -95,18 +128,41 @@ void InlineFormattingContext::Line::close()
         if (!m_trailingTrimmableContent)
             return;
 
-        auto& lastInlineRun = m_inlineFormattingState.inlineRuns().last();
+        auto& lastInlineRun = m_formattingState.inlineRuns().last();
         lastInlineRun.setWidth(lastInlineRun.width() - m_trailingTrimmableContent->width);
         lastInlineRun.textContext()->setLength(lastInlineRun.textContext()->length() - m_trailingTrimmableContent->length);
 
-        if (!lastInlineRun.textContext()->length())
-            m_inlineFormattingState.inlineRuns().removeLast();
+        if (!lastInlineRun.textContext()->length()) {
+            m_formattingState.inlineRuns().removeLast();
+            if (m_firstRunIndex.value())
+                --*m_firstRunIndex;
+            else
+                m_firstRunIndex = { };
+        }
         m_availableWidth += m_trailingTrimmableContent->width;
         m_trailingTrimmableContent = { };
     };
 
+    auto alignRuns = [&]() {
+
+        if (!hasContent())
+            return;
+
+        auto adjustedLogicalLeft = adjustedLineLogicalLeft(m_formattingRoot.style().textAlign(), m_lineLogicalLeft, m_availableWidth);
+        if (m_lineLogicalLeft == adjustedLogicalLeft)
+            return;
+
+        auto& inlineRuns = m_formattingState.inlineRuns();
+        auto delta = adjustedLogicalLeft - m_lineLogicalLeft;
+        for (auto runIndex = *m_firstRunIndex; runIndex < inlineRuns.size(); ++runIndex)
+            inlineRuns[runIndex].setLogicalLeft(inlineRuns[runIndex].logicalLeft() + delta);
+    };
+
+    if (!hasContent())
+        return;
+
     trimTrailingContent();
-    m_isEmpty = true;
+    alignRuns();
 }
 
 }
index b06d92b..9449547 100644 (file)
@@ -147,7 +147,7 @@ static void outputInlineRuns(TextStream& stream, const LayoutContext& layoutCont
             stream << " ";
         stream << "run";
         if (inlineRun.textContext())
-            stream << "(" << inlineRun.textContext()->position() << ", " << inlineRun.textContext()->position() + inlineRun.textContext()->length() << ") ";
+            stream << "(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") ";
         stream << "(" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")";
         stream.nextLine();
     }