Title: [283715] trunk/Source/WebCore
Revision
283715
Author
[email protected]
Date
2021-10-07 08:40:41 -0700 (Thu, 07 Oct 2021)

Log Message

[LFC][IFC] InlineDisplay::Box should be able to tell if it's the first or the last box within the associated Layout::Box
https://bugs.webkit.org/show_bug.cgi?id=231341

Reviewed by Antti Koivisto.

This patch helps the iterators to jump right to the first/last display box inside a layout box. This is used when a certain Layout::Box (e.g. <span>)
overlaps multiple lines producing multiple display boxes.

* layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::isFirstLastBox):
(WebCore::Layout::InlineDisplayContentBuilder::build):
(WebCore::Layout::InlineDisplayContentBuilder::createBoxesAndUpdateGeometryForLineContent):
(WebCore::Layout::InlineDisplayContentBuilder::createBoxesAndUpdateGeometryForLineSpanningInlineBoxes):
* layout/formattingContexts/inline/InlineLevelBox.h:
(WebCore::Layout::InlineLevelBox::isFirstBox const):
(WebCore::Layout::InlineLevelBox::isLastBox const):
(WebCore::Layout::InlineLevelBox::InlineLevelBox):
(WebCore::Layout::InlineLevelBox::setIsFirstBox):
(WebCore::Layout::InlineLevelBox::setIsLastBox):
(WebCore::Layout::m_isLastWithinLayoutBox):
(WebCore::Layout::InlineLevelBox::createInlineBox):
* layout/formattingContexts/inline/InlineLineBox.cpp:
(WebCore::Layout::LineBox::LineBox):
(): Deleted.
* layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
(WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes):
* layout/formattingContexts/inline/display/InlineDisplayBox.h:
(WebCore::InlineDisplay::Box::Box):
(WebCore::InlineDisplay::Box::isFirstBox const):
(WebCore::InlineDisplay::Box::isLastBox const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (283714 => 283715)


--- trunk/Source/WebCore/ChangeLog	2021-10-07 15:20:34 UTC (rev 283714)
+++ trunk/Source/WebCore/ChangeLog	2021-10-07 15:40:41 UTC (rev 283715)
@@ -1,3 +1,36 @@
+2021-10-07  Alan Bujtas  <[email protected]>
+
+        [LFC][IFC] InlineDisplay::Box should be able to tell if it's the first or the last box within the associated Layout::Box
+        https://bugs.webkit.org/show_bug.cgi?id=231341
+
+        Reviewed by Antti Koivisto.
+
+        This patch helps the iterators to jump right to the first/last display box inside a layout box. This is used when a certain Layout::Box (e.g. <span>)
+        overlaps multiple lines producing multiple display boxes.
+
+        * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
+        (WebCore::Layout::isFirstLastBox):
+        (WebCore::Layout::InlineDisplayContentBuilder::build):
+        (WebCore::Layout::InlineDisplayContentBuilder::createBoxesAndUpdateGeometryForLineContent):
+        (WebCore::Layout::InlineDisplayContentBuilder::createBoxesAndUpdateGeometryForLineSpanningInlineBoxes):
+        * layout/formattingContexts/inline/InlineLevelBox.h:
+        (WebCore::Layout::InlineLevelBox::isFirstBox const):
+        (WebCore::Layout::InlineLevelBox::isLastBox const):
+        (WebCore::Layout::InlineLevelBox::InlineLevelBox):
+        (WebCore::Layout::InlineLevelBox::setIsFirstBox):
+        (WebCore::Layout::InlineLevelBox::setIsLastBox):
+        (WebCore::Layout::m_isLastWithinLayoutBox):
+        (WebCore::Layout::InlineLevelBox::createInlineBox):
+        * layout/formattingContexts/inline/InlineLineBox.cpp:
+        (WebCore::Layout::LineBox::LineBox):
+        (): Deleted.
+        * layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
+        (WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes):
+        * layout/formattingContexts/inline/display/InlineDisplayBox.h:
+        (WebCore::InlineDisplay::Box::Box):
+        (WebCore::InlineDisplay::Box::isFirstBox const):
+        (WebCore::InlineDisplay::Box::isLastBox const):
+
 2021-10-07  Antti Koivisto  <[email protected]>
 
         [LFC][Integration] Optimize InlineContent::boxesForRect

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp (283714 => 283715)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp	2021-10-07 15:20:34 UTC (rev 283714)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp	2021-10-07 15:40:41 UTC (rev 283715)
@@ -36,6 +36,16 @@
 namespace WebCore {
 namespace Layout {
 
+static inline OptionSet<InlineDisplay::Box::PositionWithinInlineLevelBox> isFirstLastBox(const InlineLevelBox& inlineBox)
+{
+    auto positionWithinInlineLevelBox = OptionSet<InlineDisplay::Box::PositionWithinInlineLevelBox> { };
+    if (inlineBox.isFirstBox())
+        positionWithinInlineLevelBox.add(InlineDisplay::Box::PositionWithinInlineLevelBox::First);
+    if (inlineBox.isLastBox())
+        positionWithinInlineLevelBox.add(InlineDisplay::Box::PositionWithinInlineLevelBox::Last);
+    return positionWithinInlineLevelBox;
+}
+
 InlineDisplayContentBuilder::InlineDisplayContentBuilder(const ContainerBox& formattingContextRoot, InlineFormattingState& formattingState)
     : m_formattingContextRoot(formattingContextRoot)
     , m_formattingState(formattingState)
@@ -50,7 +60,7 @@
     // Every line starts with a root box, even the empty ones.
     auto rootInlineBoxRect = lineBox.logicalRectForRootInlineBox();
     rootInlineBoxRect.moveBy(lineBoxLogicalTopLeft);
-    boxes.append({ lineIndex, InlineDisplay::Box::Type::RootInlineBox, root(), rootInlineBoxRect, rootInlineBoxRect, { }, { },  lineBox.rootInlineBox().hasContent()});
+    boxes.append({ lineIndex, InlineDisplay::Box::Type::RootInlineBox, root(), rootInlineBoxRect, rootInlineBoxRect, { }, { }, lineBox.rootInlineBox().hasContent() });
 
     createBoxesAndUpdateGeometryForLineSpanningInlineBoxes(lineBox, lineBoxLogicalTopLeft, lineIndex, boxes);
     createBoxesAndUpdateGeometryForLineContent(lineContent, lineBox, lineBoxLogicalTopLeft, lineIndex, boxes);
@@ -161,7 +171,11 @@
             if (lineBox.hasContent()) {
                 // FIXME: It's expected to not have any boxes on empty lines. We should reconsider this.
                 m_inlineBoxIndexMap.add(&layoutBox, boxes.size());
-                boxes.append({ lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, inlineBoxBorderBox, { }, { }, lineBox.inlineLevelBoxForLayoutBox(layoutBox).hasContent() });
+
+                auto& inlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox);
+                ASSERT(inlineBox.isInlineBox());
+                ASSERT(inlineBox.isFirstBox());
+                boxes.append({ lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, inlineBoxBorderBox, { }, { }, inlineBox.hasContent(), isFirstLastBox(inlineBox) });
             }
 
             auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
@@ -193,6 +207,8 @@
     for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
         if (!inlineLevelBox.isLineSpanningInlineBox())
             continue;
+        ASSERT(inlineLevelBox.isInlineBox());
+
         auto& layoutBox = inlineLevelBox.layoutBox();
         auto& boxGeometry = formattingState.boxGeometry(layoutBox);
         // Inline boxes may or may not be wrapped and have boxes on multiple lines (e.g. <span>first line<br>second line<br>third line</span>)
@@ -200,8 +216,10 @@
         inlineBoxBorderBox.moveBy(lineBoxLogicalTopLeft);
 
         m_inlineBoxIndexMap.add(&layoutBox, boxes.size());
-        boxes.append({ lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, inlineBoxBorderBox, { }, { }, inlineLevelBox.hasContent() });
 
+        ASSERT(!inlineLevelBox.isFirstBox());
+        boxes.append({ lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, inlineBoxBorderBox, { }, { }, inlineLevelBox.hasContent(), isFirstLastBox(inlineLevelBox) });
+
         auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
         auto logicalRect = Rect { LayoutPoint { inlineBoxBorderBox.topLeft() }, inlineBoxSize };
         // Middle or end of the inline box. Let's stretch the box as needed.

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h (283714 => 283715)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h	2021-10-07 15:20:34 UTC (rev 283714)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h	2021-10-07 15:40:41 UTC (rev 283715)
@@ -31,6 +31,7 @@
 #include "InlineRect.h"
 #include "LayoutBox.h"
 #include "LayoutUnits.h"
+#include <wtf/OptionSet.h>
 
 namespace WebCore {
 namespace Layout {
@@ -91,9 +92,16 @@
 
     const Box& layoutBox() const { return m_layoutBox; }
 
-    InlineLevelBox(const Box&, const RenderStyle&, InlineLayoutUnit logicalLeft, InlineLayoutSize, Type);
+    bool isFirstBox() const { return m_isFirstWithinLayoutBox; }
+    bool isLastBox() const { return m_isLastWithinLayoutBox; }
 
 private:
+    enum class PositionWithinLayoutBox {
+        First = 1 << 0,
+        Last  = 1 << 1
+    };
+    InlineLevelBox(const Box&, const RenderStyle&, InlineLayoutUnit logicalLeft, InlineLayoutSize, Type, OptionSet<PositionWithinLayoutBox> = { PositionWithinLayoutBox::First, PositionWithinLayoutBox::Last });
+
     friend class LineBox;
     friend class LineBoxBuilder;
     friend class LineBoxVerticalAligner;
@@ -113,6 +121,9 @@
     void setDescent(InlineLayoutUnit descent) { m_descent = roundToInt(descent); }
     void setLayoutBounds(const LayoutBounds& layoutBounds) { m_layoutBounds = { InlineLayoutUnit(roundToInt(layoutBounds.ascent)), InlineLayoutUnit(roundToInt(layoutBounds.descent)) }; }
 
+    void setIsFirstBox() { m_isFirstWithinLayoutBox = true; }
+    void setIsLastBox() { m_isLastWithinLayoutBox = true; }
+
 private:
     CheckedRef<const Box> m_layoutBox;
     // This is the combination of margin and border boxes. Inline level boxes are vertically aligned using their margin boxes.
@@ -121,6 +132,10 @@
     InlineLayoutUnit m_baseline { 0 };
     std::optional<InlineLayoutUnit> m_descent;
     bool m_hasContent { false };
+    // These bits are about whether this inline level box is the first/last generated box of the associated Layout::Box
+    // (e.g. always true for atomic inline level boxes, but inline boxes spanning over multiple lines can produce separate first/last boxes).
+    bool m_isFirstWithinLayoutBox { false };
+    bool m_isLastWithinLayoutBox { false };
     Type m_type { Type::InlineBox };
 
     struct Style {
@@ -132,9 +147,11 @@
     Style m_style;
 };
 
-inline InlineLevelBox::InlineLevelBox(const Box& layoutBox, const RenderStyle& style, InlineLayoutUnit logicalLeft, InlineLayoutSize logicalSize, Type type)
+inline InlineLevelBox::InlineLevelBox(const Box& layoutBox, const RenderStyle& style, InlineLayoutUnit logicalLeft, InlineLayoutSize logicalSize, Type type, OptionSet<PositionWithinLayoutBox> positionWithinLayoutBox)
     : m_layoutBox(layoutBox)
     , m_logicalRect({ }, logicalLeft, logicalSize.width(), logicalSize.height())
+    , m_isFirstWithinLayoutBox(positionWithinLayoutBox.contains(PositionWithinLayoutBox::First))
+    , m_isLastWithinLayoutBox(positionWithinLayoutBox.contains(PositionWithinLayoutBox::Last))
     , m_type(type)
     , m_style({ style.fontCascade().primaryFont().fontMetrics(), style.lineHeight(), InlineLayoutUnit(style.fontCascade().fontDescription().computedPixelSize()), { } })
 {
@@ -194,7 +211,7 @@
 
 inline InlineLevelBox InlineLevelBox::createInlineBox(const Box& layoutBox, const RenderStyle& style, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, LineSpanningInlineBox isLineSpanning)
 {
-    return InlineLevelBox { layoutBox, style, logicalLeft, InlineLayoutSize { logicalWidth, { } }, isLineSpanning == LineSpanningInlineBox::Yes ? Type::LineSpanningInlineBox : Type::InlineBox };
+    return InlineLevelBox { layoutBox, style, logicalLeft, InlineLayoutSize { logicalWidth, { } }, isLineSpanning == LineSpanningInlineBox::Yes ? Type::LineSpanningInlineBox : Type::InlineBox, { } };
 }
 
 inline InlineLevelBox InlineLevelBox::createLineBreakBox(const Box& layoutBox, const RenderStyle& style, InlineLayoutUnit logicalLeft)

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBox.cpp (283714 => 283715)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBox.cpp	2021-10-07 15:20:34 UTC (rev 283714)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBox.cpp	2021-10-07 15:40:41 UTC (rev 283715)
@@ -35,7 +35,7 @@
 namespace Layout {
 
 LineBox::LineBox(const Box& rootLayoutBox, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth, size_t lineIndex, size_t nonSpanningInlineLevelBoxCount)
-    : m_rootInlineBox(rootLayoutBox, !lineIndex ? rootLayoutBox.firstLineStyle() : rootLayoutBox.style(), contentLogicalLeft, InlineLayoutSize { contentLogicalWidth, { } }, InlineLevelBox::Type::RootInlineBox)
+    : m_rootInlineBox({ rootLayoutBox, !lineIndex ? rootLayoutBox.firstLineStyle() : rootLayoutBox.style(), contentLogicalLeft, InlineLayoutSize { contentLogicalWidth, { } }, InlineLevelBox::Type::RootInlineBox })
 {
     m_nonRootInlineLevelBoxList.reserveInitialCapacity(nonSpanningInlineLevelBoxCount);
     m_nonRootInlineLevelBoxMap.reserveInitialCapacity(nonSpanningInlineLevelBoxCount);

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp (283714 => 283715)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp	2021-10-07 15:20:34 UTC (rev 283714)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp	2021-10-07 15:40:41 UTC (rev 283715)
@@ -350,6 +350,7 @@
             auto initialLogicalWidth = rootInlineBox.logicalWidth() - (run.logicalLeft() + marginStart);
             ASSERT(initialLogicalWidth >= 0);
             auto inlineBox = InlineLevelBox::createInlineBox(layoutBox, style, logicalLeft + marginStart, initialLogicalWidth);
+            inlineBox.setIsFirstBox();
             setInitialVerticalGeometryForInlineBox(inlineBox);
             updateCanUseSimplifiedAlignment(inlineBox);
             lineBox.addInlineLevelBox(WTFMove(inlineBox));
@@ -368,6 +369,7 @@
             // When the content pulls the </span> to the logical left direction (e.g. negative letter space)
             // make sure we don't end up with negative logical width on the inline box.
             inlineBox.setLogicalWidth(std::max(0.f, inlineBoxLogicalRight - inlineBox.logicalLeft()));
+            inlineBox.setIsLastBox();
             updateCanUseSimplifiedAlignment(inlineBox);
             continue;
         }

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h (283714 => 283715)


--- trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h	2021-10-07 15:20:34 UTC (rev 283714)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h	2021-10-07 15:40:41 UTC (rev 283715)
@@ -30,6 +30,7 @@
 #include "InlineRect.h"
 #include "LayoutBox.h"
 #include "TextFlags.h"
+#include <wtf/OptionSet.h>
 
 namespace WebCore {
 namespace InlineDisplay {
@@ -67,7 +68,11 @@
         GenericInlineLevelBox
     };
     struct Expansion;
-    Box(size_t lineIndex, Type, const Layout::Box&, const Layout::InlineRect&, const Layout::InlineRect& inkOverflow, Expansion, std::optional<Text> = std::nullopt, bool hasContent = true);
+    enum class PositionWithinInlineLevelBox {
+        First = 1 << 0,
+        Last  = 1 << 1
+    };
+    Box(size_t lineIndex, Type, const Layout::Box&, const Layout::InlineRect&, const Layout::InlineRect& inkOverflow, Expansion, std::optional<Text> = std::nullopt, bool hasContent = true, OptionSet<PositionWithinInlineLevelBox> = { PositionWithinInlineLevelBox::First, PositionWithinInlineLevelBox::Last });
 
     bool isText() const { return m_type == Type::Text; }
     bool isSoftLineBreak() const { return m_type == Type::SoftLineBreak; }
@@ -111,6 +116,10 @@
     const RenderStyle& style() const { return !lineIndex() ? layoutBox().firstLineStyle() : layoutBox().style(); }
 
     size_t lineIndex() const { return m_lineIndex; }
+    // These functions tell you whether this display box is the first/last for the associated inline level box (Layout::Box) and not whether it's the first/last box on the line.
+    // (e.g. always true for atomic boxes, but inline boxes spanning over multiple lines can produce individual first/last boxes).
+    bool isFirstBox() const { return m_isFirstWithinInlineLevelBox; }
+    bool isLastBox() const { return m_isLastWithinInlineLevelBox; }
 
 private:
     const size_t m_lineIndex { 0 };
@@ -118,12 +127,14 @@
     CheckedRef<const Layout::Box> m_layoutBox;
     Layout::InlineRect m_logicalRect;
     Layout::InlineRect m_inkOverflow;
-    bool m_hasContent { true };
+    bool m_hasContent : 1;
+    bool m_isFirstWithinInlineLevelBox : 1;
+    bool m_isLastWithinInlineLevelBox : 1;
     Expansion m_expansion;
     std::optional<Text> m_text;
 };
 
-inline Box::Box(size_t lineIndex, Type type, const Layout::Box& layoutBox, const Layout::InlineRect& logicalRect, const Layout::InlineRect& inkOverflow, Expansion expansion, std::optional<Text> text, bool hasContent)
+inline Box::Box(size_t lineIndex, Type type, const Layout::Box& layoutBox, const Layout::InlineRect& logicalRect, const Layout::InlineRect& inkOverflow, Expansion expansion, std::optional<Text> text, bool hasContent, OptionSet<PositionWithinInlineLevelBox> positionWithinInlineLevelBox)
     : m_lineIndex(lineIndex)
     , m_type(type)
     , m_layoutBox(layoutBox)
@@ -130,6 +141,8 @@
     , m_logicalRect(logicalRect)
     , m_inkOverflow(inkOverflow)
     , m_hasContent(hasContent)
+    , m_isFirstWithinInlineLevelBox(positionWithinInlineLevelBox.contains(PositionWithinInlineLevelBox::First))
+    , m_isLastWithinInlineLevelBox(positionWithinInlineLevelBox.contains(PositionWithinInlineLevelBox::Last))
     , m_expansion(expansion)
     , m_text(text)
 {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to