Title: [267434] trunk/Source/WebCore
Revision
267434
Author
[email protected]
Date
2020-09-22 13:07:19 -0700 (Tue, 22 Sep 2020)

Log Message

[LFC][IFC] Add support for multiline inline box geometry.
https://bugs.webkit.org/show_bug.cgi?id=216835

Reviewed by Antti Koivisto.

This patch computes the geometry for inline boxes spanning multiple lines (e.g. <span>first line<br>next line</span).
However this is not the getBoundingClientRect() type of geometry where we provide geometry for each fragments. This is more like the
element.offset* geometry where we compute the enclosing rectangle for all the fragments.

* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::layoutInFlowContent): Decouple the run construction and inline box geometry update logic,
where we loop through the runs and create "line runs" when needed and then we loop through the inline boxes on the current line and
update the box geometries.

(WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
* layout/inlineformatting/InlineFormattingState.h:
(WebCore::Layout::InlineFormattingState::lineBoxes const):
(WebCore::Layout::InlineFormattingState::addLineBox):
(WebCore::Layout::InlineFormattingState::clearLineAndRuns):
(WebCore::Layout::InlineFormattingState::shrinkToFit):
* layout/inlineformatting/InlineLineBox.h:
(WebCore::Layout::LineBox::containsInlineLevelBox const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (267433 => 267434)


--- trunk/Source/WebCore/ChangeLog	2020-09-22 19:31:47 UTC (rev 267433)
+++ trunk/Source/WebCore/ChangeLog	2020-09-22 20:07:19 UTC (rev 267434)
@@ -1,3 +1,28 @@
+2020-09-22  Zalan Bujtas  <[email protected]>
+
+        [LFC][IFC] Add support for multiline inline box geometry.
+        https://bugs.webkit.org/show_bug.cgi?id=216835
+
+        Reviewed by Antti Koivisto.
+
+        This patch computes the geometry for inline boxes spanning multiple lines (e.g. <span>first line<br>next line</span).
+        However this is not the getBoundingClientRect() type of geometry where we provide geometry for each fragments. This is more like the
+        element.offset* geometry where we compute the enclosing rectangle for all the fragments.
+
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::layoutInFlowContent): Decouple the run construction and inline box geometry update logic,
+        where we loop through the runs and create "line runs" when needed and then we loop through the inline boxes on the current line and
+        update the box geometries.
+ 
+        (WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
+        * layout/inlineformatting/InlineFormattingState.h:
+        (WebCore::Layout::InlineFormattingState::lineBoxes const):
+        (WebCore::Layout::InlineFormattingState::addLineBox):
+        (WebCore::Layout::InlineFormattingState::clearLineAndRuns):
+        (WebCore::Layout::InlineFormattingState::shrinkToFit):
+        * layout/inlineformatting/InlineLineBox.h:
+        (WebCore::Layout::LineBox::containsInlineLevelBox const):
+
 2020-09-22  Chris Dumez  <[email protected]>
 
         AudioParams with automations must process timelines

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (267433 => 267434)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp	2020-09-22 19:31:47 UTC (rev 267433)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp	2020-09-22 20:07:19 UTC (rev 267434)
@@ -113,7 +113,7 @@
                 computeHeightAndMargin(*layoutBox, constraints.horizontal);
             }
         } else if (layoutBox->isInlineBox()) {
-            // Text wrapper boxes (anonymous inline level boxes) and <br>s don't generate display boxes (only display runs).
+            // Text wrapper boxes (anonymous inline level boxes) and <br>s don't have box geometries (they only generate runs).
             if (!layoutBox->isInlineTextBox() && !layoutBox->isLineBreakBox()) {
                 // Inline boxes (<span>) can't get sized/positioned yet. At this point we can only compute their margins, borders and padding.
                 computeBorderAndPadding(*layoutBox, constraints.horizontal);
@@ -396,19 +396,17 @@
 {
     auto& formattingState = this->formattingState();
     auto geometry = this->geometry();
-    const auto lineBox = geometry.lineBoxForLineContent(lineContent);
+
+    formattingState.addLineBox(geometry.lineBoxForLineContent(lineContent));
+    const auto& lineBox = formattingState.lineBoxes().last();
+
     auto lineRectAndLineBoxOffset = geometry.computedLineLogicalRect(lineBox, root().style(), lineContent);
     auto lineLogicalRect = lineRectAndLineBoxOffset.logicalRect;
     auto lineBoxVerticalOffset = lineRectAndLineBoxOffset.lineBoxVerticalOffset;
-    auto lineIndex = formattingState.lines().size();
 
-    auto constructLineGeometry = [&] {
-        auto lineBoxLogicalRect = InlineRect { lineLogicalRect.top() + lineBoxVerticalOffset, lineLogicalRect.left(), lineBox.logicalWidth(), lineBox.logicalHeight() };
-        formattingState.addLine({ lineLogicalRect, lineBoxLogicalRect, lineBoxVerticalOffset + lineBox.alignmentBaseline(), lineBox.horizontalAlignmentOffset().valueOr(InlineLayoutUnit { }) });
-    };
-    constructLineGeometry();
-
-    if (!lineContent.floats.isEmpty()) {
+    auto updateFloatGeometry = [&] {
+        if (lineContent.floats.isEmpty())
+            return;
         auto floatingContext = FloatingContext { root(), *this, formattingState.floatingState() };
         // Move floats to their final position.
         for (const auto& floatCandidate : lineContent.floats) {
@@ -421,36 +419,67 @@
             boxGeometry.setLogicalTopLeft(floatingContext.positionForFloat(floatBox, horizontalConstraints));
             floatingContext.append(floatBox);
         }
-    }
+    };
+    updateFloatGeometry();
 
-    for (auto& lineRun : lineContent.runs) {
-        auto& layoutBox = lineRun.layoutBox();
-        // Inline level containers (<span>) don't generate display runs and neither do completely collapsed runs.
-        auto initiatesInlineRun = lineRun.isText() || lineRun.isLineBreak() || lineRun.isBox();
-        if (initiatesInlineRun) {
-            auto logicalRect = lineRun.isBox() ? lineBox.inlineBoxForLayoutBox(layoutBox).logicalRect() : lineBox.logicalRectForTextRun(lineRun);
-            formattingState.addLineRun({ lineIndex, layoutBox, logicalRect, lineRun.expansion(), lineRun.textContent() });
+    auto constructLineRuns = [&] {
+        auto lineIndex = formattingState.lines().size();
+        // Create the inline runs on the current line. This is mostly text and atomic inline runs.
+        for (auto& lineRun : lineContent.runs) {
+            if (lineRun.isText() || lineRun.isLineBreak())
+                formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() });
+            else if (lineRun.isBox())
+                formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox.inlineBoxForLayoutBox(lineRun.layoutBox()).logicalRect(), lineRun.expansion(), { } });
         }
+    };
+    constructLineRuns();
 
-        // FIXME: Since <br> and <wbr> runs have associated DOM elements, we might need to construct a display box here. 
-        auto needsBoxGeometry = lineRun.isBox() || lineRun.isContainerStart();
-        if (needsBoxGeometry) {
+    auto updateBoxGeometry = [&] {
+        // Grab the inline boxes (even those that don't have associated layout boxes on the current line due to line wrapping)
+        // and update their geometries.
+        for (auto& inlineBox : lineBox.inlineBoxList()) {
+            auto& layoutBox = inlineBox->layoutBox();
+            if (&layoutBox == &root()) {
+                // Ignore root inline box.
+                continue;
+            }
             auto& boxGeometry = formattingState.boxGeometry(layoutBox);
-            auto& inlineBox = lineBox.inlineBoxForLayoutBox(layoutBox);
-            auto topLeft = inlineBox.logicalRect().topLeft();
-            topLeft.move({ }, lineBoxVerticalOffset);
+            auto logicalTopLeft = inlineBox->logicalRect().topLeft();
+
+            logicalTopLeft.move({ }, lineBoxVerticalOffset);
             if (layoutBox.isInFlowPositioned())
-                topLeft += geometry.inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
-            boxGeometry.setLogicalTopLeft(toLayoutPoint(topLeft));
-            if (lineRun.isContainerStart()) {
-                auto marginBoxWidth = inlineBox.logicalWidth();
-                auto contentBoxWidth = marginBoxWidth - (boxGeometry.marginStart() + boxGeometry.borderLeft() + boxGeometry.paddingLeft().valueOr(0));
-                // FIXME: Fix it for multiline.
+                logicalTopLeft += geometry.inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
+
+            if (layoutBox.isAtomicInlineLevelBox()) {
+                // Atomic inline boxes are all set. Their margin/border/content box geometries are already computed. We just have to position them here.
+                boxGeometry.setLogicalTopLeft(toLayoutPoint(logicalTopLeft));
+                continue;
+            }
+            auto marginBoxWidth = inlineBox->logicalWidth();
+            auto contentBoxWidth = marginBoxWidth - (boxGeometry.marginStart() + boxGeometry.borderLeft() + boxGeometry.paddingLeft().valueOr(0));
+            // Non-atomic inline level boxes may or may not be wrapped and have geometries on multiple lines.
+            int previousLineIndex = formattingState.lineBoxes().size() - 2;
+            auto isSpanningInlineBox = previousLineIndex > 0 && formattingState.lineBoxes()[previousLineIndex].containsInlineLevelBox(layoutBox);
+            if (!isSpanningInlineBox) {
+                // This box showed up on this line the first time.
+                boxGeometry.setLogicalTopLeft(toLayoutPoint(logicalTopLeft));
                 boxGeometry.setContentBoxWidth(toLayoutUnit(contentBoxWidth));
-                boxGeometry.setContentBoxHeight(toLayoutUnit(inlineBox.logicalHeight()));
+                boxGeometry.setContentBoxHeight(toLayoutUnit(inlineBox->logicalHeight()));
+                continue;
             }
+            // This is a just a simple box geometry for the line spanning inline box. getBoundingClientRect looks into each line boxes (will turn into fragmented boxes).
+            boxGeometry.setLogicalLeft(std::min(boxGeometry.logicalLeft(), toLayoutUnit(logicalTopLeft.x())));
+            boxGeometry.setContentBoxWidth(std::max(toLayoutUnit(contentBoxWidth), boxGeometry.contentBoxWidth()));
+            boxGeometry.setContentBoxHeight(boxGeometry.contentBoxHeight() + toLayoutUnit(inlineBox->logicalHeight()));
         }
-    }
+    };
+    updateBoxGeometry();
+
+    auto constructLineGeometry = [&] {
+        auto lineBoxLogicalRect = InlineRect { lineLogicalRect.top() + lineBoxVerticalOffset, lineLogicalRect.left(), lineBox.logicalWidth(), lineBox.logicalHeight() };
+        formattingState.addLine({ lineLogicalRect, lineBoxLogicalRect, lineBoxVerticalOffset + lineBox.alignmentBaseline(), lineBox.horizontalAlignmentOffset().valueOr(InlineLayoutUnit { }) });
+    };
+    constructLineGeometry();
     return lineLogicalRect;
 }
 

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h (267433 => 267434)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h	2020-09-22 19:31:47 UTC (rev 267433)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h	2020-09-22 20:07:19 UTC (rev 267434)
@@ -29,6 +29,7 @@
 
 #include "FormattingState.h"
 #include "InlineItem.h"
+#include "InlineLineBox.h"
 #include "InlineLineGeometry.h"
 #include "InlineLineRun.h"
 #include <wtf/IsoMalloc.h>
@@ -38,6 +39,7 @@
 
 using InlineItems = Vector<InlineItem>;
 using InlineLines = Vector<InlineLineGeometry>;
+using InlineLineBoxes = Vector<LineBox>;
 using InlineLineRuns = Vector<LineRun>;
 
 // InlineFormattingState holds the state for a particular inline formatting context tree.
@@ -55,6 +57,9 @@
     InlineLines& lines() { return m_lines; }
     void addLine(const InlineLineGeometry& line) { m_lines.append(line); }
 
+    const InlineLineBoxes& lineBoxes() const { return m_lineBoxes; }
+    void addLineBox(LineBox&& lineBox) { m_lineBoxes.append(WTFMove(lineBox)); }
+
     const InlineLineRuns& lineRuns() const { return m_lineRuns; }
     InlineLineRuns& lineRuns() { return m_lineRuns; }
     void addLineRun(const LineRun& run) { m_lineRuns.append(run); }
@@ -66,6 +71,7 @@
     // Cacheable input to line layout.
     InlineItems m_inlineItems;
     InlineLines m_lines;
+    InlineLineBoxes m_lineBoxes;
     InlineLineRuns m_lineRuns;
 };
 
@@ -72,6 +78,7 @@
 inline void InlineFormattingState::clearLineAndRuns()
 {
     m_lines.clear();
+    m_lineBoxes.clear();
     m_lineRuns.clear();
 }
 
@@ -78,6 +85,7 @@
 inline void InlineFormattingState::shrinkToFit()
 {
     m_lines.shrinkToFit();
+    m_lineBoxes.shrinkToFit();
     m_lineRuns.shrinkToFit();
 }
 

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h (267433 => 267434)


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h	2020-09-22 19:31:47 UTC (rev 267433)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h	2020-09-22 20:07:19 UTC (rev 267434)
@@ -111,9 +111,8 @@
 
     const InlineBox& inlineBoxForLayoutBox(const Box& layoutBox) const { return *m_inlineBoxRectMap.get(&layoutBox); }
     InlineRect logicalRectForTextRun(const Line::Run&) const;
-
-    using InlineBoxMap = HashMap<const Box*, InlineBox*>;
     auto inlineBoxList() const { return m_inlineBoxRectMap.values(); }
+    bool containsInlineLevelBox(const Box& layoutBox) const { return m_inlineBoxRectMap.contains(&layoutBox); }
 
     InlineLayoutUnit alignmentBaseline() const { return m_rootInlineBox->logicalTop() + m_rootInlineBox->baseline(); }
 
@@ -140,7 +139,7 @@
     std::unique_ptr<InlineBox> m_rootInlineBox;
     InlineBoxList m_nonRootInlineBoxList;
 
-    InlineBoxMap m_inlineBoxRectMap;
+    HashMap<const Box*, InlineBox*> m_inlineBoxRectMap;
 };
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to