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)
{