[LFC][IFC] Optimize LineLayoutContext::tryAddingInlineItems for the most common inline content
https://bugs.webkit.org/show_bug.cgi?id=206372
<rdar://problem/58657525>

Reviewed by Simon Fraser.

~4% progression on PerformanceTests/Layout/line-layout-simple.html.

* layout/inlineformatting/LineLayoutContext.cpp:
(WebCore::Layout::endsWithSoftWrapOpportunity):
(WebCore::Layout::isAtSoftWrapOpportunity):
(WebCore::Layout::nextWrapOpportunity):
(WebCore::Layout::LineCandidateContent::appendInlineContent):
(WebCore::Layout::LineCandidateContent::reset):
(WebCore::Layout::LineLayoutContext::tryAddingInlineItems):
(WebCore::Layout::LineLayoutContext::commitPartialContent):
(WebCore::Layout::LineLayoutContext::commitContent): Deleted.
* layout/inlineformatting/LineLayoutContext.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254736 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 6ee2a31..c3f7c6f 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,24 @@
+2020-01-16  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC][IFC] Optimize LineLayoutContext::tryAddingInlineItems for the most common inline content
+        https://bugs.webkit.org/show_bug.cgi?id=206372
+        <rdar://problem/58657525>
+
+        Reviewed by Simon Fraser.
+
+        ~4% progression on PerformanceTests/Layout/line-layout-simple.html.
+
+        * layout/inlineformatting/LineLayoutContext.cpp:
+        (WebCore::Layout::endsWithSoftWrapOpportunity):
+        (WebCore::Layout::isAtSoftWrapOpportunity):
+        (WebCore::Layout::nextWrapOpportunity):
+        (WebCore::Layout::LineCandidateContent::appendInlineContent):
+        (WebCore::Layout::LineCandidateContent::reset):
+        (WebCore::Layout::LineLayoutContext::tryAddingInlineItems):
+        (WebCore::Layout::LineLayoutContext::commitPartialContent):
+        (WebCore::Layout::LineLayoutContext::commitContent): Deleted.
+        * layout/inlineformatting/LineLayoutContext.h:
+
 2020-01-16  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         Unreviewed removing a stale FIXME comment
diff --git a/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp b/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp
index 65d636b..dfbf9ca 100644
--- a/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp
+++ b/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp
@@ -35,7 +35,7 @@
 namespace WebCore {
 namespace Layout {
 
-static bool endsWithSoftWrapOpportunity(const InlineTextItem& currentTextItem, const InlineTextItem& nextInlineTextItem)
+static inline bool endsWithSoftWrapOpportunity(const InlineTextItem& currentTextItem, const InlineTextItem& nextInlineTextItem)
 {
     ASSERT(!nextInlineTextItem.isWhitespace());
     // We are at the position after a whitespace.
@@ -61,7 +61,7 @@
     return !TextUtil::findNextBreakablePosition(lineBreakIterator, 0, nextInlineTextItem.style());
 }
 
-static bool isAtSoftWrapOpportunity(const InlineItem& current, const InlineItem& next)
+static inline bool isAtSoftWrapOpportunity(const InlineItem& current, const InlineItem& next)
 {
     // "is at" simple means that there's a soft wrap opportunity right after the [current].
     // [text][ ][text][container start]... (<div>text content<span>..</div>)
@@ -101,7 +101,7 @@
     return endsWithSoftWrapOpportunity(currentInlineTextItem, nextInlineTextItem);
 }
 
-static size_t nextWrapOpportunity(const InlineItems& inlineContent, unsigned startIndex)
+static inline size_t nextWrapOpportunity(const InlineItems& inlineContent, unsigned startIndex)
 {
     // 1. Find the start candidate by skipping leading non-content items e.g <span><span>start : skip "<span><span>"
     // 2. Find the end candidate by skipping non-content items inbetween e.g. <span><span>start</span>end: skip "</span>"
@@ -200,13 +200,13 @@
     const InlineItem* m_trailingLineBreak { nullptr };
 };
 
-void LineCandidateContent::appendInlineContent(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth)
+inline void LineCandidateContent::appendInlineContent(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth)
 {
     m_inlineContentLogicalWidth += logicalWidth;
     m_inlineRuns.append({ inlineItem, logicalWidth });
 }
 
-void LineCandidateContent::reset()
+inline void LineCandidateContent::reset()
 {
     m_inlineContentLogicalWidth = 0;
     m_inlineRuns.clear();
@@ -423,7 +423,8 @@
     auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, candidateContent.inlineContentLogicalWidth(), lineStatus);
     if (result.action == LineBreaker::Result::Action::Keep) {
         // This continuous content can be fully placed on the current line.
-        commitContent(line, candidateRuns, { });
+        for (auto& run : candidateRuns)
+            line.append(run.inlineItem, run.logicalWidth);
         // Consume trailing line break as well.
         if (auto* lineBreakItem = candidateContent.trailingLineBreak()) {
             line.append(*lineBreakItem, 0);
@@ -442,7 +443,7 @@
     if (result.action == LineBreaker::Result::Action::Split) {
         // Commit the combination of full and partial content on the current line.
         ASSERT(result.partialTrailingContent);
-        commitContent(line, candidateRuns, result.partialTrailingContent);
+        commitPartialContent(line, candidateRuns, *result.partialTrailingContent);
         // When splitting multiple runs <span style="word-break: break-all">text</span><span>content</span>, we might end up splitting them at run boundary.
         // It simply means we don't really have a partial run. Partial content yes, but not partial run.
         auto trailingRunIndex = result.partialTrailingContent->trailingRunIndex;
@@ -459,15 +460,15 @@
     return { LineBreaker::IsEndOfLine::No };
 }
 
-void LineLayoutContext::commitContent(LineBuilder& line, const LineBreaker::RunList& runs, Optional<LineBreaker::Result::PartialTrailingContent> partialTrailingContent)
+void LineLayoutContext::commitPartialContent(LineBuilder& line, const LineBreaker::RunList& runs, const LineBreaker::Result::PartialTrailingContent& partialTrailingContent)
 {
     for (size_t index = 0; index < runs.size(); ++index) {
         auto& run = runs[index];
-        if (partialTrailingContent && partialTrailingContent->trailingRunIndex == index) {
+        if (partialTrailingContent.trailingRunIndex == index) {
             ASSERT(run.inlineItem.isText());
             // Create and commit partial trailing item.
-            if (auto partialRun = partialTrailingContent->partialRun) {
-                auto& trailingInlineTextItem = downcast<InlineTextItem>(runs[partialTrailingContent->trailingRunIndex].inlineItem);
+            if (auto partialRun = partialTrailingContent.partialRun) {
+                auto& trailingInlineTextItem = downcast<InlineTextItem>(runs[partialTrailingContent.trailingRunIndex].inlineItem);
                 // FIXME: LineBuilder should not hold on to the InlineItem.
                 ASSERT(!m_partialTrailingTextItem);
                 m_partialTrailingTextItem = trailingInlineTextItem.left(partialRun->length);
diff --git a/Source/WebCore/layout/inlineformatting/LineLayoutContext.h b/Source/WebCore/layout/inlineformatting/LineLayoutContext.h
index d0df8e6..9cc65a3 100644
--- a/Source/WebCore/layout/inlineformatting/LineLayoutContext.h
+++ b/Source/WebCore/layout/inlineformatting/LineLayoutContext.h
@@ -63,7 +63,7 @@
     };
     Result tryAddingFloatItems(LineBuilder&, const FloatList&);
     Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const LineCandidateContent&);
-    void commitContent(LineBuilder&, const LineBreaker::RunList&, Optional<LineBreaker::Result::PartialTrailingContent>);
+    void commitPartialContent(LineBuilder&, const LineBreaker::RunList&, const LineBreaker::Result::PartialTrailingContent&);
     LineContent close(LineBuilder&, unsigned leadingInlineItemIndex, unsigned committedInlineItemCount, Optional<LineContent::PartialContent>);
 
     InlineLayoutUnit inlineItemWidth(const InlineItem&, InlineLayoutUnit contentLogicalLeft) const;