<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[283549] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/283549">283549</a></dd>
<dt>Author</dt> <dd>zalan@apple.com</dd>
<dt>Date</dt> <dd>2021-10-05 07:49:52 -0700 (Tue, 05 Oct 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>[LFC][IFC] Move tryBreaking*Run logic to standalone functions
https://bugs.webkit.org/show_bug.cgi?id=231198

Reviewed by Antti Koivisto.

InlineContentBreaker::processOverflowingContentWithText is getting way to long and while I love keeping logic like this local, the upcoming WordBreak::BreakWord functionality
makes this function body overlap multiple pages.

* layout/formattingContexts/inline/InlineContentBreaker.cpp:
(WebCore::Layout::findTrailingRunIndex):
(WebCore::Layout::isWrappableRun):
(WebCore::Layout::InlineContentBreaker::tryBreakingOverflowingRun const):
(WebCore::Layout::InlineContentBreaker::tryBreakingPreviousNonOverflowingRuns const):
(WebCore::Layout::InlineContentBreaker::tryBreakingNextOverflowingRuns const):
(WebCore::Layout::InlineContentBreaker::processOverflowingContentWithText const):
(): Deleted.
* layout/formattingContexts/inline/InlineContentBreaker.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineContentBreakercpp">trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp</a></li>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineContentBreakerh">trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (283548 => 283549)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-10-05 13:57:34 UTC (rev 283548)
+++ trunk/Source/WebCore/ChangeLog      2021-10-05 14:49:52 UTC (rev 283549)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2021-10-05  Alan Bujtas  <zalan@apple.com>
+
+        [LFC][IFC] Move tryBreaking*Run logic to standalone functions
+        https://bugs.webkit.org/show_bug.cgi?id=231198
+
+        Reviewed by Antti Koivisto.
+
+        InlineContentBreaker::processOverflowingContentWithText is getting way to long and while I love keeping logic like this local, the upcoming WordBreak::BreakWord functionality
+        makes this function body overlap multiple pages.
+
+        * layout/formattingContexts/inline/InlineContentBreaker.cpp:
+        (WebCore::Layout::findTrailingRunIndex):
+        (WebCore::Layout::isWrappableRun):
+        (WebCore::Layout::InlineContentBreaker::tryBreakingOverflowingRun const):
+        (WebCore::Layout::InlineContentBreaker::tryBreakingPreviousNonOverflowingRuns const):
+        (WebCore::Layout::InlineContentBreaker::tryBreakingNextOverflowingRuns const):
+        (WebCore::Layout::InlineContentBreaker::processOverflowingContentWithText const):
+        (): Deleted.
+        * layout/formattingContexts/inline/InlineContentBreaker.h:
+
</ins><span class="cx"> 2021-10-05  Chris Lord  <clord@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         [GTK][WPE] REGRESSION: Async scrolling jumps to the top of the page until keyboard-initiated paging
</span></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineContentBreakercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp (283548 => 283549)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp   2021-10-05 13:57:34 UTC (rev 283548)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp      2021-10-05 14:49:52 UTC (rev 283549)
</span><span class="lines">@@ -155,21 +155,6 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-struct OverflowingTextContent {
-    size_t runIndex { 0 }; // Overflowing run index. There's always an overflowing run.
-    struct BreakingPosition {
-        size_t runIndex { 0 };
-        struct TrailingContent {
-            // Trailing content is either the run's left side (when we break the run somewhere in the middle) or the previous run.
-            // Sometimes the breaking position is at the very beginning of the first run, so there's no trailing run at all.
-            bool overflows { false };
-            std::optional<InlineContentBreaker::PartialRun> partialRun { };
-        };
-        std::optional<TrailingContent> trailingContent { };
-    };
-    std::optional<BreakingPosition> breakingPosition { }; // Where we actually break this overflowing content.
-};
-
</del><span class="cx"> InlineContentBreaker::Result InlineContentBreaker::processOverflowingContent(const ContinuousContent& overflowContent, const LineStatus& lineStatus) const
</span><span class="cx"> {
</span><span class="cx">     auto continuousContent = ContinuousContent { overflowContent };
</span><span class="lines">@@ -275,130 +260,140 @@
</span><span class="cx">     return { Result::Action::Keep, IsEndOfLine::No };
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-OverflowingTextContent InlineContentBreaker::processOverflowingContentWithText(const ContinuousContent& continuousContent, const LineStatus& lineStatus) const
</del><ins>+static std::optional<size_t> findTrailingRunIndex(const InlineContentBreaker::ContinuousContent::RunList& runs, size_t breakableRunIndex)
</ins><span class="cx"> {
</span><del>-    auto& runs = continuousContent.runs();
-    ASSERT(!runs.isEmpty());
</del><ins>+    // When the breaking position is at the beginning of the run, the trailing run is the previous one.
+    if (!breakableRunIndex)
+        return { };
+    // Try not break content at inline box boundary
+    // e.g. <span>fits</span><span>overflows</span>
+    // when the text "overflows" completely overflows, let's break the content right before the '<span>'.
+    // FIXME: Add support for subsequent empty inline boxes e.g.
+    auto trailingCandidateIndex = breakableRunIndex - 1;
+    auto isAtInlineBox = runs[trailingCandidateIndex].inlineItem.isInlineBoxStart();
+    return !isAtInlineBox ? trailingCandidateIndex : trailingCandidateIndex ? std::make_optional(trailingCandidateIndex - 1) : std::nullopt;
+}
</ins><span class="cx"> 
</span><del>-    auto isBreakableRun = [] (auto& run) {
-        ASSERT(run.inlineItem.isText() || run.inlineItem.isInlineBoxStart() || run.inlineItem.isInlineBoxEnd() || run.inlineItem.layoutBox().isImage());
-        if (!run.inlineItem.isText()) {
-            // Can't break horizontal spacing -> e.g. <span style="padding-right: 100px;">textcontent</span>, if the [inline box end] is the overflown inline item
-            // we need to check if there's another inline item beyond the [inline box end] to split.
-            return false;
</del><ins>+static bool isWrappableRun(const InlineContentBreaker::ContinuousContent::Run& run)
+{
+    ASSERT(run.inlineItem.isText() || run.inlineItem.isInlineBoxStart() || run.inlineItem.isInlineBoxEnd() || run.inlineItem.layoutBox().isImage());
+    if (!run.inlineItem.isText()) {
+        // Can't break horizontal spacing -> e.g. <span style="padding-right: 100px;">textcontent</span>, if the [inline box end] is the overflown inline item
+        // we need to check if there's another inline item beyond the [inline box end] to split.
+        return false;
+    }
+    // Check if this text run needs to stay on the current line.
+    return InlineContentBreaker::isWrappingAllowed(run);
+}
+
+std::optional<InlineContentBreaker::OverflowingTextContent::BreakingPosition> InlineContentBreaker::tryBreakingOverflowingRun(const LineStatus& lineStatus, const ContinuousContent::RunList& runs, size_t overflowingRunIndex, InlineLayoutUnit nonOverflowingContentWidth) const
+{
+    auto overflowingRun = runs[overflowingRunIndex];
+    if (!isWrappableRun(overflowingRun))
+        return { };
+    auto partialOverflowingRun = tryBreakingTextRun(overflowingRun, lineStatus.contentLogicalRight + nonOverflowingContentWidth, std::max(0.0f, lineStatus.availableWidth - nonOverflowingContentWidth), lineStatus.hasWrapOpportunityAtPreviousPosition);
+    if (!partialOverflowingRun)
+        return { };
+    if (partialOverflowingRun->length)
+        return OverflowingTextContent::BreakingPosition { overflowingRunIndex, OverflowingTextContent::BreakingPosition::TrailingContent { false, partialOverflowingRun } };
+    // When the breaking position is at the beginning of the run, the trailing run is the previous one.
+    if (auto trailingRunIndex = findTrailingRunIndex(runs, overflowingRunIndex))
+        return OverflowingTextContent::BreakingPosition { *trailingRunIndex, OverflowingTextContent::BreakingPosition::TrailingContent { } };
+    // Sometimes we can't accommodate even the very first character.
+    // Note that this is different from when there's no breakable run in this set.
+    return OverflowingTextContent::BreakingPosition { };
+}
+
+std::optional<InlineContentBreaker::OverflowingTextContent::BreakingPosition> InlineContentBreaker::tryBreakingPreviousNonOverflowingRuns(const LineStatus& lineStatus, const ContinuousContent::RunList& runs, size_t overflowingRunIndex, InlineLayoutUnit nonOverflowingContentWidth) const
+{
+    auto previousContentWidth = nonOverflowingContentWidth;
+    for (auto index = overflowingRunIndex; index--;) {
+        auto& run = runs[index];
+        previousContentWidth -= run.logicalWidth;
+        if (!isWrappableRun(run))
+            continue;
+        ASSERT(run.inlineItem.isText());
+        if (auto partialRun = tryBreakingTextRun(run, lineStatus.contentLogicalRight + previousContentWidth, { }, lineStatus.hasWrapOpportunityAtPreviousPosition)) {
+            // We know this run fits, so if breaking is allowed on the run, it should return a non-empty left-side
+            // since it's either at hyphen position or the entire run is returned.
+            ASSERT(partialRun->length);
+            auto runIsFullyAccommodated = partialRun->length == downcast<InlineTextItem>(run.inlineItem).length();
+            return OverflowingTextContent::BreakingPosition { index, OverflowingTextContent::BreakingPosition::TrailingContent { false, runIsFullyAccommodated ? std::nullopt : partialRun } };
</ins><span class="cx">         }
</span><del>-        // Check if this text run needs to stay on the current line.  
-        return isWrappingAllowed(run);
-    };
</del><ins>+    }
+    return { };
+}
</ins><span class="cx"> 
</span><del>-    auto findTrailingRunIndex = [&] (auto breakableRunIndex) -> std::optional<size_t> {
-        // When the breaking position is at the beginning of the run, the trailing run is the previous one.
-        if (!breakableRunIndex)
-            return { };
-        // Try not break content at inline box boundary
-        // e.g. <span>fits</span><span>overflows</span>
-        // when the text "overflows" completely overflows, let's break the content right before the '<span>'.
-        // FIXME: Add support for subsequent empty inline boxes e.g.
-        auto trailingCandidateIndex = breakableRunIndex - 1;
-        auto isAtInlineBox = runs[trailingCandidateIndex].inlineItem.isInlineBoxStart();
-        return !isAtInlineBox ? trailingCandidateIndex : trailingCandidateIndex ? std::make_optional(trailingCandidateIndex - 1) : std::nullopt;
-    };
</del><ins>+std::optional<InlineContentBreaker::OverflowingTextContent::BreakingPosition> InlineContentBreaker::tryBreakingNextOverflowingRuns(const LineStatus& lineStatus, const ContinuousContent::RunList& runs, size_t overflowingRunIndex, InlineLayoutUnit nonOverflowingContentWidth) const
+{
+    auto nextContentWidth = nonOverflowingContentWidth + runs[overflowingRunIndex].logicalWidth;
+    for (auto index = overflowingRunIndex + 1; index < runs.size(); ++index) {
+        auto& run = runs[index];
+        if (!isWrappableRun(run)) {
+            nextContentWidth += run.logicalWidth;
+            continue;
+        }
+        ASSERT(run.inlineItem.isText());
+        // We know that this run does not fit the available space. If we can break it at any position, let's just use the start of the run.
+        if (wordBreakBehavior(run.style, lineStatus.hasWrapOpportunityAtPreviousPosition) == WordBreakRule::AtArbitraryPosition) {
+            // We must be on an inline box boundary. Let's go back to the run in front of the inline box start run.
+            // e.g. <span>unbreakable_and_overflow<span style="word-break: break-all">breakable</span>
+            // We are at "breakable", <span> is at index - 1 and the trailing run is at index - 2.
+            ASSERT(runs[index - 1].inlineItem.isInlineBoxStart());
+            auto trailingRunIndex = findTrailingRunIndex(runs, index);
+            if (!trailingRunIndex) {
+                // This continuous content did not fit from the get-go. No trailing run.
+                return OverflowingTextContent::BreakingPosition { };
+            }
+            // At worst we are back to the overflowing run, like in the example above.
+            ASSERT(*trailingRunIndex >= overflowingRunIndex);
+            return OverflowingTextContent::BreakingPosition { *trailingRunIndex, OverflowingTextContent::BreakingPosition::TrailingContent { true } };
+        }
+        if (auto partialRun = tryBreakingTextRun(run, lineStatus.contentLogicalRight + nextContentWidth, { }, lineStatus.hasWrapOpportunityAtPreviousPosition)) {
+            ASSERT(partialRun->length);
+            // We managed to break this text run mid content. It has to be a hyphen break.
+            return OverflowingTextContent::BreakingPosition { index, OverflowingTextContent::BreakingPosition::TrailingContent { true, partialRun } };
+        }
+        nextContentWidth += run.logicalWidth;
+    }
+    return { };
+}
</ins><span class="cx"> 
</span><del>-    // Check where the overflow occurs and use the corresponding style to figure out the breaking behaviour.
</del><ins>+InlineContentBreaker::OverflowingTextContent InlineContentBreaker::processOverflowingContentWithText(const ContinuousContent& continuousContent, const LineStatus& lineStatus) const
+{
+    auto& runs = continuousContent.runs();
+    ASSERT(!runs.isEmpty());
+
+    // Check where the overflow occurs and use the corresponding style to figure out the breaking behavior.
</ins><span class="cx">     // <span style="word-break: normal">first</span><span style="word-break: break-all">second</span><span style="word-break: normal">third</span>
</span><span class="cx"> 
</span><span class="cx">     // First find the overflowing run. 
</span><del>-    auto accumulatedContentWidth = InlineLayoutUnit { };
</del><ins>+    auto nonOverflowingContentWidth = InlineLayoutUnit { };
</ins><span class="cx">     auto overflowingRunIndex = runs.size(); 
</span><span class="cx">     for (size_t index = 0; index < runs.size(); ++index) {
</span><span class="cx">         auto runLogicalWidth = runs[index].logicalWidth;
</span><del>-        if (accumulatedContentWidth + runLogicalWidth  > lineStatus.availableWidth) {
</del><ins>+        if (nonOverflowingContentWidth + runLogicalWidth  > lineStatus.availableWidth) {
</ins><span class="cx">             overflowingRunIndex = index;
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        accumulatedContentWidth += runLogicalWidth;
</del><ins>+        nonOverflowingContentWidth += runLogicalWidth;
</ins><span class="cx">     }
</span><span class="cx">     // We have to have an overflowing run.
</span><span class="cx">     RELEASE_ASSERT(overflowingRunIndex < runs.size());
</span><span class="cx"> 
</span><del>-    auto tryBreakingOverflowingRun = [&]() -> std::optional<OverflowingTextContent::BreakingPosition> {
-        auto overflowingRun = runs[overflowingRunIndex];
-        if (!isBreakableRun(overflowingRun))
-            return { };
-        if (auto partialRun = tryBreakingTextRun(overflowingRun, lineStatus.contentLogicalRight + accumulatedContentWidth, std::max(0.0f, lineStatus.availableWidth - accumulatedContentWidth), lineStatus.hasWrapOpportunityAtPreviousPosition)) {
-            if (partialRun->length)
-                return OverflowingTextContent::BreakingPosition { overflowingRunIndex, OverflowingTextContent::BreakingPosition::TrailingContent { false, partialRun } };
-            // When the breaking position is at the beginning of the run, the trailing run is the previous one.
-            if (auto trailingRunIndex = findTrailingRunIndex(overflowingRunIndex))
-                return OverflowingTextContent::BreakingPosition { *trailingRunIndex, OverflowingTextContent::BreakingPosition::TrailingContent { } };
-            // Sometimes we can't accommodate even the very first character. 
-            // Note that this is different from when there's no breakable run in this set.
-            return OverflowingTextContent::BreakingPosition { };
-        }
-        return { };
-    };
</del><span class="cx">     // Check if we actually break this run.
</span><del>-    if (auto breakingPosition = tryBreakingOverflowingRun())
</del><ins>+    if (auto breakingPosition = tryBreakingOverflowingRun(lineStatus, runs, overflowingRunIndex, nonOverflowingContentWidth))
</ins><span class="cx">         return { overflowingRunIndex, breakingPosition };
</span><span class="cx"> 
</span><del>-    auto tryBreakingPreviousNonOverflowingRuns = [&]() -> std::optional<OverflowingTextContent::BreakingPosition> {
-        auto previousContentWidth = accumulatedContentWidth;
-        for (auto index = overflowingRunIndex; index--;) {
-            auto& run = runs[index];
-            previousContentWidth -= run.logicalWidth;
-            if (!isBreakableRun(run))
-                continue;
-            ASSERT(run.inlineItem.isText());
-            if (auto partialRun = tryBreakingTextRun(run, lineStatus.contentLogicalRight + previousContentWidth, { }, lineStatus.hasWrapOpportunityAtPreviousPosition)) {
-                // We know this run fits, so if breaking is allowed on the run, it should return a non-empty left-side
-                // since it's either at hyphen position or the entire run is returned.
-                ASSERT(partialRun->length);
-                auto runIsFullyAccommodated = partialRun->length == downcast<InlineTextItem>(run.inlineItem).length();
-                return OverflowingTextContent::BreakingPosition { index, OverflowingTextContent::BreakingPosition::TrailingContent { false, runIsFullyAccommodated ? std::nullopt : partialRun } };
-            }
-        }
-        return { };
-    };
</del><span class="cx">     // We did not manage to break the run that actually overflows the line.
</span><span class="cx">     // Let's try to find a previous breaking position starting from the overflowing run. It surely fits.
</span><del>-    if (auto breakingPosition = tryBreakingPreviousNonOverflowingRuns())
</del><ins>+    if (auto breakingPosition = tryBreakingPreviousNonOverflowingRuns(lineStatus, runs, overflowingRunIndex, nonOverflowingContentWidth))
</ins><span class="cx">         return { overflowingRunIndex, breakingPosition };
</span><span class="cx"> 
</span><del>-    auto tryBreakingNextOverflowingRuns = [&]() -> std::optional<OverflowingTextContent::BreakingPosition> {
-        auto nextContentWidth = accumulatedContentWidth + runs[overflowingRunIndex].logicalWidth;
-        for (auto index = overflowingRunIndex + 1; index < runs.size(); ++index) {
-            auto& run = runs[index];
-            if (isBreakableRun(run)) {
-                ASSERT(run.inlineItem.isText());
-                // We know that this run does not fit the available space. If we can break it at any position, let's just use the start of the run.
-                if (wordBreakBehavior(run.style, lineStatus.hasWrapOpportunityAtPreviousPosition) == WordBreakRule::AtArbitraryPosition) {
-                    // We must be on an inline box boundary. Let's go back to the run in front of the inline box start run.
-                    // e.g. <span>unbreakable_and_overflow<span style="word-break: break-all">breakable</span>
-                    // We are at "breakable", <span> is at index - 1 and the trailing run is at index - 2.
-                    ASSERT(runs[index - 1].inlineItem.isInlineBoxStart());
-                    auto trailingRunIndex = findTrailingRunIndex(index);
-                    if (!trailingRunIndex) {
-                        // This continuous content did not fit from the get-go. No trailing run.
-                        return OverflowingTextContent::BreakingPosition { };
-                    }
-                    // At worst we are back to the overflowing run, like in the example above.
-                    ASSERT(*trailingRunIndex >= overflowingRunIndex);
-                    return OverflowingTextContent::BreakingPosition { *trailingRunIndex, OverflowingTextContent::BreakingPosition::TrailingContent { true } };
-                }
-                if (auto partialRun = tryBreakingTextRun(run, lineStatus.contentLogicalRight + nextContentWidth, { }, lineStatus.hasWrapOpportunityAtPreviousPosition)) {
-                    ASSERT(partialRun->length);
-                    // We managed to break this text run mid content. It has to be a hyphen break.
-                    return OverflowingTextContent::BreakingPosition { index, OverflowingTextContent::BreakingPosition::TrailingContent { true, partialRun } };
-                }
-            }
-            nextContentWidth += run.logicalWidth;
-        }
-        return { };
-    };
</del><span class="cx">     // At this point we know that there's no breakable run all the way to the overflowing run.
</span><span class="cx">     // Now we need to check if any run after the overflowing content can break.
</span><span class="cx">     // e.g. <span>this_content_overflows_but_not_breakable<span><span style="word-break: break-all">but_this_is_breakable</span>
</span><del>-    if (auto breakingPosition = tryBreakingNextOverflowingRuns())
</del><ins>+    if (auto breakingPosition = tryBreakingNextOverflowingRuns(lineStatus, runs, overflowingRunIndex, nonOverflowingContentWidth))
</ins><span class="cx">         return { overflowingRunIndex, breakingPosition };
</span><span class="cx"> 
</span><span class="cx">     // Give up, there's no breakable run in here.
</span></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineContentBreakerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h (283548 => 283549)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h     2021-10-05 13:57:34 UTC (rev 283548)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h        2021-10-05 14:49:52 UTC (rev 283549)
</span><span class="lines">@@ -34,7 +34,6 @@
</span><span class="cx"> namespace Layout {
</span><span class="cx"> 
</span><span class="cx"> class InlineItem;
</span><del>-struct OverflowingTextContent;
</del><span class="cx"> 
</span><span class="cx"> class InlineContentBreaker {
</span><span class="cx"> public:
</span><span class="lines">@@ -119,8 +118,26 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     Result processOverflowingContent(const ContinuousContent&, const LineStatus&) const;
</span><ins>+
+    struct OverflowingTextContent {
+        size_t runIndex { 0 }; // Overflowing run index. There's always an overflowing run.
+        struct BreakingPosition {
+            size_t runIndex { 0 };
+            struct TrailingContent {
+                // Trailing content is either the run's left side (when we break the run somewhere in the middle) or the previous run.
+                // Sometimes the breaking position is at the very beginning of the first run, so there's no trailing run at all.
+                bool overflows { false };
+                std::optional<InlineContentBreaker::PartialRun> partialRun { };
+            };
+            std::optional<TrailingContent> trailingContent { };
+        };
+        std::optional<BreakingPosition> breakingPosition { }; // Where we actually break this overflowing content.
+    };
</ins><span class="cx">     OverflowingTextContent processOverflowingContentWithText(const ContinuousContent&, const LineStatus&) const;
</span><span class="cx">     std::optional<PartialRun> tryBreakingTextRun(const ContinuousContent::Run& overflowRun, InlineLayoutUnit logicalLeft, std::optional<InlineLayoutUnit> availableWidth, bool hasWrapOpportunityAtPreviousPosition) const;
</span><ins>+    std::optional<OverflowingTextContent::BreakingPosition> tryBreakingOverflowingRun(const LineStatus&, const ContinuousContent::RunList&, size_t overflowingRunIndex, InlineLayoutUnit nonOverflowingContentWidth) const;
+    std::optional<OverflowingTextContent::BreakingPosition> tryBreakingPreviousNonOverflowingRuns(const LineStatus&, const ContinuousContent::RunList&, size_t overflowingRunIndex, InlineLayoutUnit nonOverflowingContentWidth) const;
+    std::optional<OverflowingTextContent::BreakingPosition> tryBreakingNextOverflowingRuns(const LineStatus&, const ContinuousContent::RunList&, size_t overflowingRunIndex, InlineLayoutUnit nonOverflowingContentWidth) const;
</ins><span class="cx"> 
</span><span class="cx">     enum class WordBreakRule {
</span><span class="cx">         AtArbitraryPosition        = 1 << 0,
</span></span></pre>
</div>
</div>

</body>
</html>