[LFC][IFC] Add generic inline content handling.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Oct 2018 16:41:58 +0000 (16:41 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Oct 2018 16:41:58 +0000 (16:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190713

Reviewed by Antti Koivisto.

layoutInlineContent turns InlineLineBreaker::Run objects into final inline runs by
resolving heading/trailing whitespace, aligment, expansion opportunities etc.
These inline runs are input to the display tree construction.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/displaytree/DisplayBox.h:
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::layout const):
(WebCore::Layout::trimLeadingRun):
(WebCore::Layout::InlineFormattingContext::layoutInlineContent const):
(WebCore::Layout::InlineFormattingContext::computeWidthAndHeight const):
* layout/inlineformatting/InlineFormattingContext.h:
(WebCore::Layout::InlineFormattingContext::Line::hasContent const):
(WebCore::Layout::InlineFormattingContext::Line::contentLogicalLeft const):
(WebCore::Layout::InlineFormattingContext::Line::availableWidth const):
* layout/inlineformatting/InlineFormattingState.h:
(WebCore::Layout::InlineFormattingState::inlineRuns):
(WebCore::Layout::InlineFormattingState::appendInlineRun):
* layout/inlineformatting/InlineLineBreaker.cpp:
(WebCore::Layout::InlineLineBreaker::nextRun):
(WebCore::Layout::InlineLineBreaker::nextLayoutRun): Deleted.
* layout/inlineformatting/InlineLineBreaker.h:
* layout/inlineformatting/InlineRun.h: Added.
(WebCore::Layout::InlineRun::logicalLeft const):
(WebCore::Layout::InlineRun::logicalRight const):
(WebCore::Layout::InlineRun::width const):
(WebCore::Layout::InlineRun::setWidth):
(WebCore::Layout::InlineRun::setLogicalRight):
(WebCore::Layout::InlineRun::TextContext::position const):
(WebCore::Layout::InlineRun::TextContext::length const):
(WebCore::Layout::InlineRun::TextContext::setLength):
(WebCore::Layout::InlineRun::textContext):
(WebCore::Layout::InlineRun::inlineItem const):
(WebCore::Layout::InlineRun::InlineRun):
(WebCore::Layout::InlineRun::TextContext::TextContext):
* layout/inlineformatting/Line.cpp: Added.
(WebCore::Layout::InlineFormattingContext::Line::Line):
(WebCore::Layout::InlineFormattingContext::Line::setConstraints):
(WebCore::Layout::isNonCollapsedText):
(WebCore::Layout::isTrimmableContent):
(WebCore::Layout::InlineFormattingContext::Line::appendContent):
(WebCore::Layout::InlineFormattingContext::Line::close):

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

Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/layout/displaytree/DisplayBox.h
Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
Source/WebCore/layout/inlineformatting/InlineFormattingContext.h
Source/WebCore/layout/inlineformatting/InlineFormattingState.h
Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp
Source/WebCore/layout/inlineformatting/InlineLineBreaker.h
Source/WebCore/layout/inlineformatting/InlineRun.h [new file with mode: 0644]
Source/WebCore/layout/inlineformatting/Line.cpp [new file with mode: 0644]

index 43960b7..0871587 100644 (file)
@@ -1,5 +1,56 @@
 2018-10-19  Zalan Bujtas  <zalan@apple.com>
 
+        [LFC][IFC] Add generic inline content handling.
+        https://bugs.webkit.org/show_bug.cgi?id=190713
+
+        Reviewed by Antti Koivisto.
+
+        layoutInlineContent turns InlineLineBreaker::Run objects into final inline runs by
+        resolving heading/trailing whitespace, aligment, expansion opportunities etc.
+        These inline runs are input to the display tree construction.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/displaytree/DisplayBox.h:
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::layout const):
+        (WebCore::Layout::trimLeadingRun):
+        (WebCore::Layout::InlineFormattingContext::layoutInlineContent const):
+        (WebCore::Layout::InlineFormattingContext::computeWidthAndHeight const):
+        * layout/inlineformatting/InlineFormattingContext.h:
+        (WebCore::Layout::InlineFormattingContext::Line::hasContent const):
+        (WebCore::Layout::InlineFormattingContext::Line::contentLogicalLeft const):
+        (WebCore::Layout::InlineFormattingContext::Line::availableWidth const):
+        * layout/inlineformatting/InlineFormattingState.h:
+        (WebCore::Layout::InlineFormattingState::inlineRuns):
+        (WebCore::Layout::InlineFormattingState::appendInlineRun):
+        * layout/inlineformatting/InlineLineBreaker.cpp:
+        (WebCore::Layout::InlineLineBreaker::nextRun):
+        (WebCore::Layout::InlineLineBreaker::nextLayoutRun): Deleted.
+        * layout/inlineformatting/InlineLineBreaker.h:
+        * layout/inlineformatting/InlineRun.h: Added.
+        (WebCore::Layout::InlineRun::logicalLeft const):
+        (WebCore::Layout::InlineRun::logicalRight const):
+        (WebCore::Layout::InlineRun::width const):
+        (WebCore::Layout::InlineRun::setWidth):
+        (WebCore::Layout::InlineRun::setLogicalRight):
+        (WebCore::Layout::InlineRun::TextContext::position const):
+        (WebCore::Layout::InlineRun::TextContext::length const):
+        (WebCore::Layout::InlineRun::TextContext::setLength):
+        (WebCore::Layout::InlineRun::textContext):
+        (WebCore::Layout::InlineRun::inlineItem const):
+        (WebCore::Layout::InlineRun::InlineRun):
+        (WebCore::Layout::InlineRun::TextContext::TextContext):
+        * layout/inlineformatting/Line.cpp: Added.
+        (WebCore::Layout::InlineFormattingContext::Line::Line):
+        (WebCore::Layout::InlineFormattingContext::Line::setConstraints):
+        (WebCore::Layout::isNonCollapsedText):
+        (WebCore::Layout::isTrimmableContent):
+        (WebCore::Layout::InlineFormattingContext::Line::appendContent):
+        (WebCore::Layout::InlineFormattingContext::Line::close):
+
+2018-10-19  Zalan Bujtas  <zalan@apple.com>
+
         [LFC][IFC] Add generic inline line breaker
         https://bugs.webkit.org/show_bug.cgi?id=190698
 
index c4cddc1..77645f1 100644 (file)
@@ -1261,6 +1261,7 @@ layout/inlineformatting/InlineFormattingState.cpp
 layout/inlineformatting/InlineInvalidation.cpp
 layout/inlineformatting/InlineLineBreaker.cpp
 layout/inlineformatting/InlineRunProvider.cpp
+layout/inlineformatting/Line.cpp
 layout/inlineformatting/textlayout/TextContentProvider.cpp
 layout/inlineformatting/textlayout/TextUtil.cpp
 layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.cpp
index cbeb345..d4c1d75 100644 (file)
                6ED878C5147493F4004C3597 /* RenderTableCaption.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED878C3147493F4004C3597 /* RenderTableCaption.h */; };
                6ED8C37A183BFF8C009E53BD /* BoxShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED8C378183BFF8C009E53BD /* BoxShape.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6EE8A77310F803F3005A4A24 /* JSWebGLContextAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */; };
+               6F219D772178D37200BB033C /* InlineRun.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F219D742178D37100BB033C /* InlineRun.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6F222B761AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */; };
                6F3E1F622136142000A65A08 /* FloatBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F3E1F612136141700A65A08 /* FloatBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6F5217C72177F5A7006583BB /* InlineRunProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F5217C42177F5A6006583BB /* InlineRunProvider.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6EE8A77010F803F3005A4A24 /* JSWebGLContextAttributes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLContextAttributes.cpp; sourceTree = "<group>"; };
                6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLContextAttributes.h; sourceTree = "<group>"; };
                6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlockFormattingContextGeometry.cpp; sourceTree = "<group>"; };
+               6F219D742178D37100BB033C /* InlineRun.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineRun.h; sourceTree = "<group>"; };
+               6F219D762178D37100BB033C /* Line.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Line.cpp; sourceTree = "<group>"; };
                6F222B741AB52D640094651A /* WebGLVertexArrayObjectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGLVertexArrayObjectBase.h; sourceTree = "<group>"; };
                6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebGLVertexArrayObjectBase.cpp; sourceTree = "<group>"; };
                6F3E1F5F2136141700A65A08 /* FloatBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FloatBox.cpp; sourceTree = "<group>"; };
                115CFA9A208BC140001E6991 /* inlineformatting */ = {
                        isa = PBXGroup;
                        children = (
+                               6F219D742178D37100BB033C /* InlineRun.h */,
+                               6F219D762178D37100BB033C /* Line.cpp */,
                                6FE198132178397B00446F08 /* InlineLineBreaker.cpp */,
                                6FE198152178397C00446F08 /* InlineLineBreaker.h */,
                                6FE7DDDD20EC6E8B008B5B4E /* textlayout */,
                                A10BB5851484E3A700B2E87A /* RenderSVGRect.h in Headers */,
                                436708CD12D9CA4B00044234 /* RenderSVGResource.h in Headers */,
                                436708CF12D9CA4B00044234 /* RenderSVGResourceClipper.h in Headers */,
+                               6F219D772178D37200BB033C /* InlineRun.h in Headers */,
                                436708D112D9CA4B00044234 /* RenderSVGResourceContainer.h in Headers */,
                                436708D312D9CA4B00044234 /* RenderSVGResourceFilter.h in Headers */,
                                436708D512D9CA4B00044234 /* RenderSVGResourceFilterPrimitive.h in Headers */,
index 3630ee2..927eadc 100644 (file)
@@ -41,6 +41,7 @@ class FloatAvoider;
 class FloatBox;
 class FormattingContext;
 class FloatingContext;
+class InlineFormattingContext;
 class LayoutContext;
 }
 
@@ -54,6 +55,7 @@ public:
     friend class Layout::FloatBox;
     friend class Layout::FormattingContext;
     friend class Layout::FloatingContext;
+    friend class Layout::InlineFormattingContext;
     friend class Layout::LayoutContext;
 
     Box(const RenderStyle&);
index 7de23c1..ed7e5bd 100644 (file)
 
 #include "FloatingState.h"
 #include "InlineFormattingState.h"
+#include "InlineLineBreaker.h"
+#include "InlineRunProvider.h"
 #include "LayoutBox.h"
 #include "LayoutContainer.h"
 #include "LayoutContext.h"
 #include "LayoutInlineBox.h"
 #include "LayoutInlineContainer.h"
 #include "Logging.h"
-#include "SimpleLineBreaker.h"
-#include "TextContentProvider.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/text/TextStream.h>
 
@@ -51,14 +51,15 @@ InlineFormattingContext::InlineFormattingContext(const Box& formattingContextRoo
 {
 }
 
-void InlineFormattingContext::layout(LayoutContext& layoutContext, FormattingState& inlineFormattingState) const
+void InlineFormattingContext::layout(LayoutContext& layoutContext, FormattingState& formattingState) const
 {
     if (!is<Container>(root()))
         return;
 
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Start] -> inline formatting context -> layout context(" << &layoutContext << ") formatting root(" << &root() << ")");
 
-    TextContentProvider textContentProvider;
+    auto& inlineFormattingState = downcast<InlineFormattingState>(formattingState);
+    InlineRunProvider inlineRunProvider(inlineFormattingState);
     auto& formattingRoot = downcast<Container>(root());
     auto* layoutBox = formattingRoot.firstInFlowOrFloatingChild();
     // Casually walk through the block's descendants and place the inline boxes one after the other as much as we can (yeah, I am looking at you floats).
@@ -68,12 +69,11 @@ void InlineFormattingContext::layout(LayoutContext& layoutContext, FormattingSta
             layoutBox = downcast<Container>(*layoutBox).firstInFlowOrFloatingChild();
             continue;
         }
-        auto& inlineBox = downcast<InlineBox>(*layoutBox);
-        // Only text content at this point.
-        if (inlineBox.hasTextContent())
-            textContentProvider.appendText(inlineBox.textContent(), inlineBox.style(), true);
 
-        for (; layoutBox; layoutBox = layoutBox->containingBlock()) {
+        inlineRunProvider.append(*layoutBox);
+        computeWidthAndHeight(layoutContext, *layoutBox);
+
+        for (; layoutBox; layoutBox = layoutBox->parent()) {
             if (layoutBox == &formattingRoot) {
                 layoutBox = nullptr;
                 break;
@@ -86,20 +86,104 @@ void InlineFormattingContext::layout(LayoutContext& layoutContext, FormattingSta
         ASSERT(!layoutBox || layoutBox->isDescendantOf(formattingRoot));
     }
 
+    layoutInlineContent(layoutContext, inlineFormattingState, inlineRunProvider);
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> layout context(" << &layoutContext << ") formatting root(" << &root() << ")");
+}
+
+static bool trimLeadingRun(const InlineLineBreaker::Run& run)
+{
+    ASSERT(run.position == InlineLineBreaker::Run::Position::LineBegin);
+
+    auto& inlineRun = run.inlineRun;
+    if (!inlineRun.isWhitespace())
+        return false;
+
+    return inlineRun.style().collapseWhiteSpace();
+}
+
+void InlineFormattingContext::layoutInlineContent(const LayoutContext& layoutContext, InlineFormattingState& inlineFormattingState, const InlineRunProvider& inlineRunProvider) const
+{
+    auto& formattingRoot = downcast<Container>(root());
     auto& formattingRootDisplayBox = layoutContext.displayBoxForLayoutBox(formattingRoot);
-    auto lineLeft = formattingRootDisplayBox.contentBoxLeft();
-    auto lineRight = formattingRootDisplayBox.contentBoxRight();
 
-    SimpleLineBreaker::LineConstraintList constraints;
-    constraints.append({ { }, lineLeft, lineRight });
-    auto textRunList = textContentProvider.textRuns();
-    SimpleLineBreaker simpleLineBreaker(textRunList, textContentProvider, WTFMove(constraints), formattingRoot.style());
+    auto lineLogicalLeft = formattingRootDisplayBox.contentBoxLeft();
+    auto availableWidth = formattingRootDisplayBox.contentBoxWidth();
+    auto previousRunPositionIsLineEnd = false;
 
-    // Since we don't yet have a display tree context for inline boxes, let's just cache the runs on the state so that they can be verified against the sll/inline tree runs later.
-    ASSERT(is<InlineFormattingState>(inlineFormattingState));
-    downcast<InlineFormattingState>(inlineFormattingState).addLayoutRuns(simpleLineBreaker.runs());
+    Line line(inlineFormattingState);
+    line.setConstraints(lineLogicalLeft, availableWidth);
 
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> layout context(" << &layoutContext << ") formatting root(" << &root() << ")");
+    InlineLineBreaker lineBreaker(layoutContext, inlineFormattingState.inlineContent(), inlineRunProvider.runs());
+    while (auto run = lineBreaker.nextRun(line.contentLogicalLeft(), line.availableWidth(), !line.hasContent())) {
+
+        if (run->position == InlineLineBreaker::Run::Position::LineBegin) {
+            // First run on line.
+
+            // Previous run ended up being at the line end. Adjust the line accordingly.
+            if (!previousRunPositionIsLineEnd) {
+                line.close();
+                line.setConstraints(lineLogicalLeft, availableWidth);
+            }
+            // Skip leading whitespace.
+            if (!trimLeadingRun(*run))
+                line.appendContent(*run);
+            continue;
+        }
+
+        if (run->position == InlineLineBreaker::Run::Position::LineEnd) {
+            // Last run on line.
+            previousRunPositionIsLineEnd = true;
+            line.appendContent(*run);
+            // Move over to the next line.
+            line.close();
+            line.setConstraints(lineLogicalLeft, availableWidth);
+            continue;
+        }
+
+        // This may or may not be the last run on line -but definitely not the first one.
+        line.appendContent(*run);
+    }
+    line.close();
+}
+
+void InlineFormattingContext::computeWidthAndHeight(const LayoutContext& layoutContext, const Box& layoutBox) const
+{
+    if (is<InlineBox>(layoutBox) && downcast<InlineBox>(layoutBox).hasTextContent()) {
+        // Text content width is computed during text run generation. -It does not make any sense to measure unprocessed text here, since it will likely be
+        // split up (or concatenated).
+        return;
+    }
+
+    if (layoutBox.isFloatingPositioned()) {
+        ASSERT_NOT_IMPLEMENTED_YET();
+        return;
+    }
+
+    if (layoutBox.isInlineBlockBox()) {
+        ASSERT_NOT_IMPLEMENTED_YET();
+        return;
+    }
+
+    if (layoutBox.replaced()) {
+        computeBorderAndPadding(layoutContext, layoutBox);
+
+        auto& displayBox = layoutContext.displayBoxForLayoutBox(layoutBox);
+
+        auto widthAndMargin = Geometry::inlineReplacedWidthAndMargin(layoutContext, layoutBox);
+        displayBox.setContentBoxWidth(widthAndMargin.width);
+        displayBox.setHorizontalMargin(widthAndMargin.margin);
+        displayBox.setHorizontalNonComputedMargin(widthAndMargin.nonComputedMargin);
+
+        auto heightAndMargin = Geometry::inlineReplacedHeightAndMargin(layoutContext, layoutBox);
+        displayBox.setContentBoxHeight(heightAndMargin.height);
+        displayBox.setVerticalNonCollapsedMargin(heightAndMargin.margin);
+        displayBox.setVerticalMargin(heightAndMargin.collapsedMargin.value_or(heightAndMargin.margin));
+        return;
+    }
+
+    ASSERT_NOT_REACHED();
+    return;
 }
 
 void InlineFormattingContext::computeStaticPosition(const LayoutContext&, const Box&) const
index 324d9d5..1384c1d 100644 (file)
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "FormattingContext.h"
+#include "InlineLineBreaker.h"
 #include <wtf/IsoMalloc.h>
 
 namespace WebCore {
-
 namespace Layout {
 
 class InlineFormattingState;
+class InlineRunProvider;
 
 // This class implements the layout logic for inline formatting contexts.
 // https://www.w3.org/TR/CSS22/visuren.html#inline-formatting
@@ -46,6 +47,33 @@ public:
     void layout(LayoutContext&, FormattingState&) const override;
 
 private:
+    class Line {
+    public:
+        Line(InlineFormattingState&);
+
+        void setConstraints(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth);
+        void appendContent(const InlineLineBreaker::Run&);
+        void close();
+        bool hasContent() const { return !m_isEmpty; }
+        LayoutUnit contentLogicalLeft() const { return m_contentLogicalLeft; }
+        LayoutUnit availableWidth() const { return m_availableWidth; }
+
+    private:
+        struct TrailingTrimmableContent {
+            LayoutUnit width;
+            unsigned length;
+        };
+        std::optional<TrailingTrimmableContent> m_trailingTrimmableContent;
+        InlineFormattingState& m_inlineFormattingState;
+        LayoutUnit m_contentLogicalLeft;
+        LayoutUnit m_availableWidth;
+        bool m_isEmpty { true };
+        bool m_lastRunIsNotCollapsedText { true };
+    };
+
+    void layoutInlineContent(const LayoutContext&, InlineFormattingState&, const InlineRunProvider&) const;
+
+    void computeWidthAndHeight(const LayoutContext&, const Box&) const;
     void computeStaticPosition(const LayoutContext&, const Box&) const override;
     void computeInFlowPositionedPosition(const LayoutContext&, const Box&) const override;
 
index caace2e..dc6c9e8 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "FormattingState.h"
 #include "InlineItem.h"
+#include "InlineRun.h"
 #include "Runs.h"
 #include <wtf/IsoMalloc.h>
 
@@ -47,9 +48,14 @@ public:
     void addLayoutRuns(Vector<LayoutRun>&& layoutRuns) { m_layoutRuns = WTFMove(layoutRuns); }
     const Vector<LayoutRun>& layoutRuns() const { return m_layoutRuns; }
 
+    // Temp
+    InlineRuns& inlineRuns() { return m_inlineRuns; }
+    void appendInlineRun(InlineRun inlineRun) { m_inlineRuns.append(inlineRun); }
+
 private:
     InlineContent m_inlineContent;
     Vector<LayoutRun> m_layoutRuns;
+    InlineRuns m_inlineRuns;
 };
 
 }
index 44fc2a1..2b4ce59 100644 (file)
@@ -45,7 +45,7 @@ InlineLineBreaker::InlineLineBreaker(const LayoutContext& layoutContext, const I
 {
 }
 
-std::optional<InlineLineBreaker::Run> InlineLineBreaker::nextLayoutRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty)
+std::optional<InlineLineBreaker::Run> InlineLineBreaker::nextRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty)
 {
     if (isAtContentEnd())
         return std::nullopt;
index ab01ada..19a53ec 100644 (file)
@@ -45,7 +45,7 @@ public:
         InlineRunProvider::Run inlineRun;
         LayoutUnit width;
     };
-    std::optional<Run> nextLayoutRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty);
+    std::optional<Run> nextRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty);
 
 private:
     enum class LineBreakingBehavior { Keep, Break, WrapToNextLine };
diff --git a/Source/WebCore/layout/inlineformatting/InlineRun.h b/Source/WebCore/layout/inlineformatting/InlineRun.h
new file mode 100644 (file)
index 0000000..c277758
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "InlineRunProvider.h"
+#include "LayoutUnit.h"
+
+namespace WebCore {
+namespace Layout {
+
+struct InlineRun {
+    InlineRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&);
+    InlineRun(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 setLogicalRight(LayoutUnit logicalRight) { m_width -= (this->logicalRight() - logicalRight); }
+
+    struct TextContext {
+    public:
+        TextContext(ItemPosition, unsigned length);
+
+        ItemPosition position() const { return m_position; }
+        unsigned length() const { return m_length; }
+
+        void setLength(unsigned length) { m_length = length; }
+
+    private:
+        ItemPosition m_position;
+        unsigned m_length;
+    };
+    std::optional<TextContext>& textContext() { return m_textContext; }
+    const InlineItem& inlineItem() const { return m_inlineItem; }
+
+private:
+    LayoutUnit m_logicalLeft;
+    LayoutUnit m_width;
+
+    const InlineItem& m_inlineItem;
+    std::optional<TextContext> m_textContext;
+};
+
+using InlineRuns = Vector<InlineRun>;
+
+inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, const InlineItem& inlineItem)
+    : m_logicalLeft(logicalLeft)
+    , m_width(width)
+    , m_inlineItem(inlineItem)
+{
+}
+
+inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, ItemPosition position, unsigned length, const InlineItem& inlineItem)
+    : m_logicalLeft(logicalLeft)
+    , m_width(width)
+    , m_inlineItem(inlineItem)
+    , m_textContext(TextContext { position, length })
+{
+}
+
+inline InlineRun::TextContext::TextContext(ItemPosition position, unsigned length)
+    : m_position(position)
+    , m_length(length)
+{
+}
+
+}
+}
+#endif
diff --git a/Source/WebCore/layout/inlineformatting/Line.cpp b/Source/WebCore/layout/inlineformatting/Line.cpp
new file mode 100644 (file)
index 0000000..2342bee
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InlineFormattingContext.h"
+#include "InlineFormattingState.h"
+#include "InlineRunProvider.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+namespace WebCore {
+namespace Layout {
+
+InlineFormattingContext::Line::Line(InlineFormattingState& inlineFormattingState)
+    : m_inlineFormattingState(inlineFormattingState)
+{
+}
+
+void InlineFormattingContext::Line::setConstraints(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth)
+{
+    m_contentLogicalLeft = lineLogicalLeft;
+    m_availableWidth = availableWidth;
+}
+
+static bool isNonCollapsedText(const InlineRunProvider::Run& inlineRun)
+{
+    return inlineRun.isText() && !inlineRun.textContext()->isCollapsed();
+}
+
+static bool isTrimmableContent(const InlineRunProvider::Run& inlineRun)
+{
+    return inlineRun.isWhitespace() && inlineRun.style().collapseWhiteSpace();
+}
+
+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;
+
+    // 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();
+        auto runLength = textContext->isCollapsed() ? 1 : textContext->length();
+
+        if (isTrimmableContent(inlineRun))
+            m_trailingTrimmableContent = TrailingTrimmableContent { run.width, runLength };
+
+        if (hadContent && lastRunWasNotCollapsedText) {
+            auto& inlineRun = m_inlineFormattingState.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()});
+    }
+
+    m_inlineFormattingState.appendInlineRun({ contentLogicalLeft, run.width, inlineRun.inlineItem() });
+}
+
+void InlineFormattingContext::Line::close()
+{
+    auto trimTrailingContent = [&]() {
+
+        if (!m_trailingTrimmableContent)
+            return;
+
+        auto& lastInlineRun = m_inlineFormattingState.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();
+        m_availableWidth += m_trailingTrimmableContent->width;
+        m_trailingTrimmableContent = { };
+    };
+
+    trimTrailingContent();
+    m_isEmpty = true;
+}
+
+}
+}
+
+#endif