[LFC][IFC] Avoid infinite loop when stuck on partial content
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Mar 2020 14:59:44 +0000 (14:59 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Mar 2020 14:59:44 +0000 (14:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=209312
<rdar://problem/59954605>

Reviewed by Simon Fraser.

Speculative fix to address infinite loop/running out of inline run vector capacity at InlineFormattingContext::setDisplayBoxesForLine.
(Checking if we managed to progress on the content while having partial runs.)

* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::lineLayout):
* layout/inlineformatting/LineLayoutContext.cpp:
(WebCore::Layout::LineLayoutContext::nextContentForLine):
(WebCore::Layout::LineLayoutContext::handleFloatsAndInlineContent):

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

Source/WebCore/ChangeLog
Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp

index a510afb..df190cf 100644 (file)
@@ -1,3 +1,20 @@
+2020-03-20  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC][IFC] Avoid infinite loop when stuck on partial content
+        https://bugs.webkit.org/show_bug.cgi?id=209312
+        <rdar://problem/59954605>
+
+        Reviewed by Simon Fraser.
+
+        Speculative fix to address infinite loop/running out of inline run vector capacity at InlineFormattingContext::setDisplayBoxesForLine.
+        (Checking if we managed to progress on the content while having partial runs.)
+
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::lineLayout):
+        * layout/inlineformatting/LineLayoutContext.cpp:
+        (WebCore::Layout::LineLayoutContext::nextContentForLine):
+        (WebCore::Layout::LineLayoutContext::handleFloatsAndInlineContent):
+
 2020-03-20  Philippe Normand  <pnormand@igalia.com>
 
         [GStreamer] White-list vp09 in the codec registry
index 59ae895..59761ca 100644 (file)
@@ -139,29 +139,49 @@ void InlineFormattingContext::layoutInFlowContent(InvalidationState& invalidatio
 void InlineFormattingContext::lineLayout(InlineItems& inlineItems, LineLayoutContext::InlineItemRange layoutRange, const HorizontalConstraints& horizontalConstraints, const VerticalConstraints& verticalConstraints)
 {
     auto lineLogicalTop = verticalConstraints.logicalTop;
-    Optional<unsigned> partialLeadingContentLength;
+    struct PreviousLineEnd {
+        unsigned runIndex;
+        Optional<unsigned> overflowContentLength;
+    };
+    Optional<PreviousLineEnd> previousLineEnd;
     auto lineBuilder = LineBuilder { *this, root().style().textAlign(), LineBuilder::IntrinsicSizing::No };
     auto lineLayoutContext = LineLayoutContext { *this, root(), inlineItems };
 
     while (!layoutRange.isEmpty()) {
         lineBuilder.initialize(constraintsForLine(horizontalConstraints, lineLogicalTop));
-        auto lineContent = lineLayoutContext.layoutLine(lineBuilder, layoutRange, partialLeadingContentLength);
+        auto lineContent = lineLayoutContext.layoutLine(lineBuilder, layoutRange, previousLineEnd ? previousLineEnd->overflowContentLength : WTF::nullopt);
         setDisplayBoxesForLine(lineContent, horizontalConstraints);
 
-        partialLeadingContentLength = { };
         if (lineContent.trailingInlineItemIndex) {
             lineLogicalTop = lineContent.lineBox.logicalBottom();
-            // When the trailing content is partial, we need to reuse the last InlinItem.
+            // When the trailing content is partial, we need to reuse the last InlineTextItem.
+            auto trailingRunIndex = *lineContent.trailingInlineItemIndex;
             if (lineContent.partialContent) {
-                layoutRange.start = *lineContent.trailingInlineItemIndex;
+                ASSERT(lineContent.partialContent->overflowContentLength);
                 // Turn previous line's overflow content length into the next line's leading content partial length.
-                // "sp<->litcontent" -> overflow length: 10 -> leading partial content length: 10. 
-                partialLeadingContentLength = lineContent.partialContent->overflowContentLength;
-            } else
-                layoutRange.start = *lineContent.trailingInlineItemIndex + 1;
+                // "sp<->litcontent" -> overflow length: 10 -> leading partial content length: 10.
+                auto isNewInlineContent = !previousLineEnd
+                    || trailingRunIndex > previousLineEnd->runIndex
+                    || (previousLineEnd->overflowContentLength && *previousLineEnd->overflowContentLength > lineContent.partialContent->overflowContentLength);
+                if (isNewInlineContent) {
+                    // Strart the next line with the same, partial trailing InlineTextItem.
+                    previousLineEnd = PreviousLineEnd { trailingRunIndex, lineContent.partialContent->overflowContentLength };
+                    layoutRange.start = previousLineEnd->runIndex;
+                } else {
+                    ASSERT_NOT_REACHED();
+                    // Move over to the next run if we are stuck on this partial content (when the overflow content length remains the same).
+                    // We certainly lose some content, but we would be busy looping anyway.
+                    previousLineEnd = PreviousLineEnd { trailingRunIndex, { } };
+                    layoutRange.start = previousLineEnd->runIndex + 1;
+                }
+            } else {
+                previousLineEnd = PreviousLineEnd { trailingRunIndex, { } };
+                layoutRange.start = previousLineEnd->runIndex + 1;
+            }
             continue;
         }
         // Floats prevented us placing any content on the line.
+        ASSERT(lineContent.runList.isEmpty());
         ASSERT(lineBuilder.hasIntrusiveFloat());
         // Move the next line below the intrusive float.
         auto floatingContext = FloatingContext { root(), *this, formattingState().floatingState() };
index 8c39ee1..5bf7718 100644 (file)
@@ -496,6 +496,7 @@ LineLayoutContext::Result LineLayoutContext::handleFloatsAndInlineContent(LineBr
 
         auto partialRun = *result.partialTrailingContent->partialRun;
         auto& trailingInlineTextItem = downcast<InlineTextItem>(candidateRuns[trailingRunIndex].inlineItem);
+        ASSERT(partialRun.length < trailingInlineTextItem.length());
         auto overflowLength = trailingInlineTextItem.length() - partialRun.length;
         return { LineBreaker::IsEndOfLine::Yes, { committedInlineItemCount, false }, LineContent::PartialContent { partialRun.needsHyphen, overflowLength } };
     }