Diff
Modified: trunk/LayoutTests/ChangeLog (281733 => 281734)
--- trunk/LayoutTests/ChangeLog 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/LayoutTests/ChangeLog 2021-08-28 13:15:49 UTC (rev 281734)
@@ -1,3 +1,12 @@
+2021-08-28 Alan Bujtas <[email protected]>
+
+ [LFC][IFC] Move content builder functionality to a dedicated class
+ https://bugs.webkit.org/show_bug.cgi?id=229631
+
+ Reviewed by Antti Koivisto.
+
+ * TestExpectations:
+
2021-08-27 Myles C. Maxfield <[email protected]>
The simple text codepath does not handle unpaired surrogates
Modified: trunk/LayoutTests/TestExpectations (281733 => 281734)
--- trunk/LayoutTests/TestExpectations 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/LayoutTests/TestExpectations 2021-08-28 13:15:49 UTC (rev 281734)
@@ -5023,6 +5023,10 @@
[ Debug ] fast/layoutformattingcontext/table-fixed-width-with-max-distribution.html [ Skip ]
[ Debug ] fast/layoutformattingcontext/table-space-distribution-simple-mismatching.html [ Skip ]
+# Missing painting support for in-flow positioning
+fast/layoutformattingcontext/replaced-box-with-margin-on-baseline.html [ ImageOnlyFailure ]
+fast/layoutformattingcontext/table-cell-vertical-alignment-simple.html [ ImageOnlyFailure ]
+
# This webstorage test has crashed since it was imported.
imported/w3c/web-platform-tests/webstorage/storage_session_setitem_quotaexceedederr.window.html [ Skip ]
# This webstorage test has timed out since it was imported.
Modified: trunk/Source/WebCore/ChangeLog (281733 => 281734)
--- trunk/Source/WebCore/ChangeLog 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/ChangeLog 2021-08-28 13:15:49 UTC (rev 281734)
@@ -1,3 +1,41 @@
+2021-08-28 Alan Bujtas <[email protected]>
+
+ [LFC][IFC] Move content builder functionality to a dedicated class
+ https://bugs.webkit.org/show_bug.cgi?id=229631
+
+ Reviewed by Antti Koivisto.
+
+ Let's use a dedicated class for constructing the final line runs. This is also going to be used
+ for computing overflow and other "display" type of value once it's merged with LayoutIntegration::InlineContentBuilder.
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * layout/LayoutUnits.h:
+ * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp: Added.
+ (WebCore::Layout::InlineDisplayContentBuilder::InlineDisplayContentBuilder):
+ (WebCore::Layout::InlineDisplayContentBuilder::build):
+ (WebCore::Layout::InlineDisplayContentBuilder::createRunsAndUpdateGeometryForLineContent):
+ (WebCore::Layout::InlineDisplayContentBuilder::createRunsAndUpdateGeometryForLineSpanningInlineBoxes):
+ * layout/formattingContexts/inline/InlineDisplayContentBuilder.h: Copied from Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h.
+ (WebCore::Layout::InlineDisplayContentBuilder::root const):
+ (WebCore::Layout::InlineDisplayContentBuilder::formattingState const):
+ * layout/formattingContexts/inline/InlineFormattingContext.cpp:
+ (WebCore::Layout::InlineFormattingContext::lineLayout):
+ (WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
+ * layout/formattingContexts/inline/InlineFormattingContext.h:
+ * layout/formattingContexts/inline/InlineLevelBox.h:
+ (WebCore::Layout::InlineLevelBox::isInlineBox const):
+ (WebCore::Layout::InlineLevelBox::isLineSpanningInlineBox const):
+ (WebCore::Layout::InlineLevelBox::createInlineBox):
+ * layout/formattingContexts/inline/InlineLine.h:
+ (WebCore::Layout::Line::Run::type const):
+ * layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
+ (WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes):
+ * layout/formattingContexts/inline/InlineLineBoxBuilder.h:
+ * layout/integration/LayoutIntegrationInlineContentBuilder.cpp:
+ (WebCore::LayoutIntegration::lineOverflowWidth):
+ * layout/integration/LayoutIntegrationRun.h:
+
2021-08-27 Myles C. Maxfield <[email protected]>
The simple text codepath does not handle unpaired surrogates
Modified: trunk/Source/WebCore/Sources.txt (281733 => 281734)
--- trunk/Source/WebCore/Sources.txt 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/Sources.txt 2021-08-28 13:15:49 UTC (rev 281734)
@@ -1452,6 +1452,7 @@
layout/floats/FloatingContext.cpp
layout/floats/FloatingState.cpp
layout/formattingContexts/inline/InlineContentBreaker.cpp
+layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp
layout/formattingContexts/inline/InlineFormattingContext.cpp
layout/formattingContexts/inline/InlineFormattingGeometry.cpp
layout/formattingContexts/inline/InlineFormattingQuirks.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (281733 => 281734)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-08-28 13:15:49 UTC (rev 281734)
@@ -398,6 +398,7 @@
11310CF620BA4A560065A8D0 /* LayoutChildIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 11100FC920927CBC0081AA6C /* LayoutChildIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
113409DA203E038000C66915 /* RenderTreeBuilderContinuation.h in Headers */ = {isa = PBXBuildFile; fileRef = 113409D8203E038000C66915 /* RenderTreeBuilderContinuation.h */; };
113D0B521F9FDD2B00F611BB /* FrameViewLayoutContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 113D0B501F9FDD2B00F611BB /* FrameViewLayoutContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 11513D0326D981E8004D3FAA /* InlineDisplayContentBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 11513D0226D981E7004D3FAA /* InlineDisplayContentBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; };
115CFA6A208AF7D0001E6991 /* FormattingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 115CFA68208AF7D0001E6991 /* FormattingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
115CFA6E208AFAB7001E6991 /* BlockFormattingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 115CFA6C208AFAB6001E6991 /* BlockFormattingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
115CFA76208AFE30001E6991 /* FormattingState.h in Headers */ = {isa = PBXBuildFile; fileRef = 115CFA74208AFE30001E6991 /* FormattingState.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -6411,6 +6412,8 @@
113409D8203E038000C66915 /* RenderTreeBuilderContinuation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderContinuation.h; sourceTree = "<group>"; };
113D0B4F1F9FDD2B00F611BB /* FrameViewLayoutContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FrameViewLayoutContext.cpp; sourceTree = "<group>"; };
113D0B501F9FDD2B00F611BB /* FrameViewLayoutContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameViewLayoutContext.h; sourceTree = "<group>"; };
+ 11513D0026D981DD004D3FAA /* InlineDisplayContentBuilder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InlineDisplayContentBuilder.cpp; sourceTree = "<group>"; };
+ 11513D0226D981E7004D3FAA /* InlineDisplayContentBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineDisplayContentBuilder.h; sourceTree = "<group>"; };
115CA83023328B1E00FD3B08 /* LayoutUnits.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutUnits.cpp; sourceTree = "<group>"; };
115CFA68208AF7D0001E6991 /* FormattingContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FormattingContext.h; sourceTree = "<group>"; };
115CFA69208AF7D0001E6991 /* FormattingContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormattingContext.cpp; sourceTree = "<group>"; };
@@ -18031,6 +18034,8 @@
6FE7DDDD20EC6E8B008B5B4E /* text */,
6FE198132178397B00446F08 /* InlineContentBreaker.cpp */,
6FE198152178397C00446F08 /* InlineContentBreaker.h */,
+ 11513D0026D981DD004D3FAA /* InlineDisplayContentBuilder.cpp */,
+ 11513D0226D981E7004D3FAA /* InlineDisplayContentBuilder.h */,
6F7CA3C9208C2B2E002F29AB /* InlineFormattingContext.cpp */,
6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */,
6F35EFAF2187CBD50044E0F4 /* InlineFormattingGeometry.cpp */,
@@ -32431,6 +32436,7 @@
CD063F831E23FA8900812BE3 /* InitDataRegistry.h in Headers */,
E30592641E27A3AD00D57C98 /* InlineClassicScript.h in Headers */,
6FE198172178397C00446F08 /* InlineContentBreaker.h in Headers */,
+ 11513D0326D981E8004D3FAA /* InlineDisplayContentBuilder.h in Headers */,
6F7CA3CA208C2B2E002F29AB /* InlineFormattingContext.h in Headers */,
47C4D57D26508BCB00C7AB1F /* InlineFormattingGeometry.h in Headers */,
6FE636E82647962900F0951E /* InlineFormattingQuirks.h in Headers */,
@@ -32440,6 +32446,7 @@
6FAAE71326A2814B00E07502 /* InlineLevelBox.h in Headers */,
6F0CD695229ED32700C5994E /* InlineLine.h in Headers */,
6FB2400523DFF12800796458 /* InlineLineBox.h in Headers */,
+ 11C3227D26D958CE00328F4D /* InlineLineBoxBuilder.h in Headers */,
6F6EE74326D44EE300374CDA /* InlineLineBoxVerticalAligner.h in Headers */,
6F26EB48234004A5006906E2 /* InlineLineBuilder.h in Headers */,
6F91421125152138004E4FEA /* InlineLineGeometry.h in Headers */,
@@ -33306,7 +33313,6 @@
07846343145B151A00A58DF1 /* JSTrackEvent.h in Headers */,
E17B492116A9B8FF001C8839 /* JSTransitionEvent.h in Headers */,
1A750D5D0A90DEE1000FF215 /* JSTreeWalker.h in Headers */,
- 11C3227D26D958CE00328F4D /* InlineLineBoxBuilder.h in Headers */,
A86629CF09DA2B47009633A5 /* JSUIEvent.h in Headers */,
465307D01DB6EE4800E4137C /* JSUIEventInit.h in Headers */,
7C73FB12191EF6F4007DE061 /* JSUserMessageHandler.h in Headers */,
Modified: trunk/Source/WebCore/layout/LayoutUnits.h (281733 => 281734)
--- trunk/Source/WebCore/layout/LayoutUnits.h 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/LayoutUnits.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -36,6 +36,8 @@
namespace WebCore {
+namespace Layout {
+
#define USE_FLOAT_AS_INLINE_LAYOUT_UNIT 1
#if USE_FLOAT_AS_INLINE_LAYOUT_UNIT
@@ -50,8 +52,6 @@
using InlineLayoutRect = LayoutRect;
#endif
-namespace Layout {
-
struct Position {
operator LayoutUnit() const { return value; }
LayoutUnit value;
Added: trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp (0 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp 2021-08-28 13:15:49 UTC (rev 281734)
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InlineDisplayContentBuilder.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "LayoutBoxGeometry.h"
+
+namespace WebCore {
+namespace Layout {
+
+
+InlineDisplayContentBuilder::InlineDisplayContentBuilder(const ContainerBox& formattingContextRoot, InlineFormattingState& formattingState)
+ : m_formattingContextRoot(formattingContextRoot)
+ , m_formattingState(formattingState)
+{
+
+}
+
+void InlineDisplayContentBuilder::build(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, const size_t lineIndex)
+{
+ auto& formattingState = this->formattingState();
+ // Every line starts with a root run, even the empty ones.
+ formattingState.addLineRun({ lineIndex, LineRun::Type::RootInlineBox, root(), lineBox.logicalRectForRootInlineBox(), { }, { }, lineBox.rootInlineBox().hasContent()});
+
+ // Spanning inline boxes start at the very beginning of the line.
+ auto lineSpanningInlineBoxIndex = formattingState.lineRuns().size();
+ createRunsAndUpdateGeometryForLineContent(lineContent, lineBox, lineBoxLogicalTopLeft, lineIndex);
+ createRunsAndUpdateGeometryForLineSpanningInlineBoxes(lineBox, lineBoxLogicalTopLeft, lineIndex, lineSpanningInlineBoxIndex);
+}
+
+void InlineDisplayContentBuilder::createRunsAndUpdateGeometryForLineContent(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, const size_t lineIndex)
+{
+ auto& formattingState = this->formattingState();
+ // Create the inline runs on the current line. This is mostly text and atomic inline runs.
+ for (auto& lineRun : lineContent.runs) {
+ auto& layoutBox = lineRun.layoutBox();
+ switch (lineRun.type()) {
+ case InlineItem::Type::Text:
+ formattingState.addLineRun({ lineIndex, LineRun::Type::Text, layoutBox, lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() });
+ break;
+ case InlineItem::Type::SoftLineBreak:
+ formattingState.addLineRun({ lineIndex, LineRun::Type::SoftLineBreak, layoutBox, lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() });
+ break;
+ case InlineItem::Type::HardLineBreak: {
+ // Only hard linebreaks have associated layout boxes.
+ auto lineBreakBoxRect = lineBox.logicalRectForLineBreakBox(layoutBox);
+ formattingState.addLineRun({ lineIndex, LineRun::Type::LineBreakBox, layoutBox, lineBreakBoxRect, lineRun.expansion(), { } });
+
+ auto& boxGeometry = formattingState.boxGeometry(layoutBox);
+ lineBreakBoxRect.moveBy(lineBoxLogicalTopLeft);
+ boxGeometry.setLogicalTopLeft(toLayoutPoint(lineBreakBoxRect.topLeft()));
+ boxGeometry.setContentBoxHeight(toLayoutUnit(lineBreakBoxRect.height()));
+ break;
+ }
+ case InlineItem::Type::Box: {
+ ASSERT(layoutBox.isAtomicInlineLevelBox());
+ auto& boxGeometry = formattingState.boxGeometry(layoutBox);
+ auto logicalBorderBox = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry);
+ formattingState.addLineRun({ lineIndex, LineRun::Type::AtomicInlineLevelBox, layoutBox, logicalBorderBox, lineRun.expansion(), { } });
+
+ auto borderBoxLogicalTopLeft = logicalBorderBox.topLeft();
+ // Note that inline boxes are relative to the line and their top position can be negative.
+ borderBoxLogicalTopLeft.moveBy(lineBoxLogicalTopLeft);
+ // 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(borderBoxLogicalTopLeft));
+ break;
+ }
+ case InlineItem::Type::InlineBoxStart: {
+ // This inline box showed up first on this line.
+ auto& boxGeometry = formattingState.boxGeometry(layoutBox);
+ auto inlineBoxBorderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
+ if (lineBox.hasContent()) {
+ // FIXME: It's expected to not have any runs on empty lines. We should reconsider this.
+ formattingState.addLineRun({ lineIndex, LineRun::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, { }, { }, lineBox.inlineLevelBoxForLayoutBox(layoutBox).hasContent() });
+ }
+
+ auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
+ auto logicalRect = Rect { LayoutPoint { inlineBoxBorderBox.topLeft() }, inlineBoxSize };
+ logicalRect.moveBy(LayoutPoint { lineBoxLogicalTopLeft });
+ boxGeometry.setLogicalTopLeft(logicalRect.topLeft());
+ auto contentBoxHeight = logicalRect.height() - (boxGeometry.verticalBorder() + boxGeometry.verticalPadding().value_or(0_lu));
+ boxGeometry.setContentBoxHeight(contentBoxHeight);
+ auto contentBoxWidth = logicalRect.width() - (boxGeometry.horizontalBorder() + boxGeometry.horizontalPadding().value_or(0_lu));
+ boxGeometry.setContentBoxWidth(contentBoxWidth);
+ break;
+ }
+ default:
+ ASSERT(lineRun.isInlineBoxEnd() || lineRun.isWordBreakOpportunity());
+ break;
+ }
+ }
+}
+
+void InlineDisplayContentBuilder::createRunsAndUpdateGeometryForLineSpanningInlineBoxes(const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, const size_t lineIndex, size_t lineSpanningInlineBoxIndex)
+{
+ if (!lineBox.hasContent()) {
+ // When a spanning inline box (e.g. <div>text<span><br></span></div>) lands on an empty line
+ // (empty here means no content at all including line breaks, not just visually empty) then we
+ // don't extend the spanning line box over to this line -also there is no next line in cases like this.
+ return;
+ }
+
+ auto& formattingState = this->formattingState();
+ for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
+ if (!inlineLevelBox.isLineSpanningInlineBox())
+ continue;
+ auto& layoutBox = inlineLevelBox.layoutBox();
+ auto& boxGeometry = formattingState.boxGeometry(layoutBox);
+ // Inline boxes may or may not be wrapped and have runs on multiple lines (e.g. <span>first line<br>second line<br>third line</span>)
+ auto inlineBoxBorderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
+
+ formattingState.lineRuns().insert(lineSpanningInlineBoxIndex++, { lineIndex, LineRun::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, { }, { }, inlineLevelBox.hasContent(), true });
+
+ auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
+ auto logicalRect = Rect { LayoutPoint { inlineBoxBorderBox.topLeft() }, inlineBoxSize };
+ logicalRect.moveBy(LayoutPoint { lineBoxLogicalTopLeft });
+ // Middle or end of the inline box. Let's stretch the box as needed.
+ auto enclosingBorderBoxRect = BoxGeometry::borderBoxRect(boxGeometry);
+ enclosingBorderBoxRect.expandToContain(logicalRect);
+ boxGeometry.setLogicalLeft(enclosingBorderBoxRect.left());
+
+ boxGeometry.setContentBoxHeight(enclosingBorderBoxRect.height() - (boxGeometry.verticalBorder() + boxGeometry.verticalPadding().value_or(0_lu)));
+ boxGeometry.setContentBoxWidth(enclosingBorderBoxRect.width() - (boxGeometry.horizontalBorder() + boxGeometry.horizontalPadding().value_or(0_lu)));
+ }
+}
+
+}
+}
+
+#endif
Copied: trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h (from rev 281733, trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h) (0 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "InlineLineBuilder.h"
+#include "LayoutUnits.h"
+
+namespace WebCore {
+namespace Layout {
+
+class ContainerBox;
+class InlineFormattingState;
+class LineBox;
+
+class InlineDisplayContentBuilder {
+public:
+ InlineDisplayContentBuilder(const ContainerBox& formattingContextRoot, InlineFormattingState&);
+
+ void build(const LineBuilder::LineContent&, const LineBox&, const InlineLayoutPoint& lineBoxLogicalTopLeft, const size_t lineIndex);
+
+private:
+ void createRunsAndUpdateGeometryForLineContent(const LineBuilder::LineContent&, const LineBox&, const InlineLayoutPoint& lineBoxLogicalTopLeft, const size_t lineIndex);
+ void createRunsAndUpdateGeometryForLineSpanningInlineBoxes(const LineBox&, const InlineLayoutPoint& lineBoxLogicalTopLeft, const size_t lineIndex, size_t lineSpanningInlineBoxIndex);
+
+ const ContainerBox& root() const { return m_formattingContextRoot; }
+ InlineFormattingState& formattingState() const { return m_formattingState; }
+
+ const ContainerBox& m_formattingContextRoot;
+ InlineFormattingState& m_formattingState;
+};
+
+}
+}
+
+#endif
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp (281733 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp 2021-08-28 13:15:49 UTC (rev 281734)
@@ -30,6 +30,7 @@
#include "FloatingContext.h"
#include "FontCascade.h"
+#include "InlineDisplayContentBuilder.h"
#include "InlineFormattingState.h"
#include "InlineLineBox.h"
#include "InlineLineBoxBuilder.h"
@@ -205,7 +206,7 @@
}();
auto initialLineConstraints = InlineRect { lineLogicalTop, constraints.horizontal().logicalLeft, constraints.horizontal().logicalWidth, initialLineHeight };
auto lineContent = lineBuilder.layoutInlineContent(needsLayoutRange, partialLeadingContentLength, leadingLogicalWidth, initialLineConstraints, isFirstLine);
- auto lineLogicalRect = computeGeometryForLineContent(lineContent, constraints.horizontal());
+ auto lineLogicalRect = computeGeometryForLineContent(lineContent);
auto lineContentRange = lineContent.inlineItemRange;
if (!lineContentRange.isEmpty()) {
@@ -567,139 +568,18 @@
}
}
-InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuilder::LineContent& lineContent, const HorizontalConstraints& horizontalConstraints)
+InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuilder::LineContent& lineContent)
{
auto& formattingState = this->formattingState();
- auto& formattingGeometry = this->formattingGeometry();
- auto lineIndex = formattingState.lines().size();
+ auto currentLineIndex = formattingState.lines().size();
auto lineBoxAndGeometry = LineBoxBuilder(*this).build(lineContent);
formattingState.addLineBox(WTFMove(lineBoxAndGeometry.lineBox));
formattingState.addLine(lineBoxAndGeometry.lineGeometry);
- const auto& lineBox = formattingState.lineBoxes().last();
auto lineBoxLogicalRect = lineBoxAndGeometry.lineGeometry.lineBoxLogicalRect();
- // Every line starts with a root run, even the empty ones.
- formattingState.addLineRun({ lineIndex, LineRun::Type::RootInlineBox, root(), lineBox.logicalRectForRootInlineBox(), { }, { }, lineBox.rootInlineBox().hasContent()});
-
- if (!lineBox.hasContent()) {
- // Fast path for lines with no content e.g. <div><span></span><span></span></div> or <span><div></div></span> where we construct empty pre and post blocks.
- ASSERT(!lineBox.rootInlineBox().hasContent() && !lineBoxLogicalRect.height());
- auto updateInlineBoxesGeometryIfApplicable = [&] {
- if (!lineBox.hasInlineBox())
- return;
- Vector<const Box*> layoutBoxList;
- // Collect the empty inline boxes that showed up first on this line.
- // Note that an inline box end on an empty line does not make the inline box taller.
- // (e.g. <div>text<span><br></span></div>) <- the <span> inline box is as tall as the line even though the </span> is after a <br> so technically is on the following (empty)line.
- for (auto& lineRun : lineContent.runs) {
- if (lineRun.isInlineBoxStart())
- layoutBoxList.append(&lineRun.layoutBox());
- }
- for (auto* layoutBox : layoutBoxList) {
- auto& boxGeometry = formattingState.boxGeometry(*layoutBox);
- auto inlineBoxLogicalHeight = LayoutUnit::fromFloatCeil(lineBox.logicalBorderBoxForInlineBox(*layoutBox, boxGeometry).height());
- boxGeometry.setContentBoxHeight(inlineBoxLogicalHeight);
- boxGeometry.setContentBoxWidth({ });
- boxGeometry.setLogicalTopLeft(toLayoutPoint(lineBoxLogicalRect.topLeft()));
- }
- };
- updateInlineBoxesGeometryIfApplicable();
- return lineBoxLogicalRect;
- }
-
- // Spanning inline boxes start at the very beginning of the line.
- auto lineSpanningInlineBoxIndex = formattingState.lineRuns().size();
- HashSet<const Box*> inlineBoxStartSet;
- auto constructLineRunsAndUpdateBoxGeometry = [&] {
- // Create the inline runs on the current line. This is mostly text and atomic inline runs.
- for (auto& lineRun : lineContent.runs) {
- // FIXME: We should not need to construct a line run for <br>.
- auto& layoutBox = lineRun.layoutBox();
- if (lineRun.isText()) {
- formattingState.addLineRun({ lineIndex, LineRun::Type::Text, layoutBox, lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() });
- continue;
- }
- if (lineRun.isLineBreak()) {
- if (layoutBox.isLineBreakBox()) {
- // Only hard linebreaks have associated layout boxes.
- auto lineBreakBoxRect = lineBox.logicalRectForLineBreakBox(layoutBox);
- formattingState.addLineRun({ lineIndex, LineRun::Type::LineBreakBox, layoutBox, lineBreakBoxRect, lineRun.expansion(), { } });
-
- auto& boxGeometry = formattingState.boxGeometry(layoutBox);
- lineBreakBoxRect.moveBy(lineBoxLogicalRect.topLeft());
- boxGeometry.setLogicalTopLeft(toLayoutPoint(lineBreakBoxRect.topLeft()));
- boxGeometry.setContentBoxHeight(toLayoutUnit(lineBreakBoxRect.height()));
- } else
- formattingState.addLineRun({ lineIndex, LineRun::Type::SoftLineBreak, layoutBox, lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() });
- continue;
- }
- if (lineRun.isBox()) {
- ASSERT(layoutBox.isAtomicInlineLevelBox());
- auto& boxGeometry = formattingState.boxGeometry(layoutBox);
- auto logicalBorderBox = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry);
- formattingState.addLineRun({ lineIndex, LineRun::Type::AtomicInlineLevelBox, layoutBox, logicalBorderBox, lineRun.expansion(), { } });
-
- auto borderBoxLogicalTopLeft = logicalBorderBox.topLeft();
- // Note that inline boxes are relative to the line and their top position can be negative.
- borderBoxLogicalTopLeft.moveBy(lineBoxLogicalRect.topLeft());
- if (layoutBox.isInFlowPositioned())
- borderBoxLogicalTopLeft += formattingGeometry.inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
- // 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(borderBoxLogicalTopLeft));
- continue;
- }
- if (lineRun.isInlineBoxStart()) {
- auto& boxGeometry = formattingState.boxGeometry(layoutBox);
- auto inlineBoxLogicalRect = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
- formattingState.addLineRun({ lineIndex, LineRun::Type::NonRootInlineBox, layoutBox, inlineBoxLogicalRect, lineRun.expansion(), { }, lineBox.inlineLevelBoxForLayoutBox(layoutBox).hasContent() });
- inlineBoxStartSet.add(&layoutBox);
- continue;
- }
- ASSERT(lineRun.isInlineBoxEnd() || lineRun.isWordBreakOpportunity());
- }
- };
- constructLineRunsAndUpdateBoxGeometry();
-
- auto updateBoxGeometryForInlineBoxes = [&] {
- // FIXME: We may want to keep around an inline box only set.
- if (!lineBox.hasInlineBox())
- return;
- // 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& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
- if (!inlineLevelBox.isInlineBox())
- continue;
- auto& layoutBox = inlineLevelBox.layoutBox();
- auto& boxGeometry = formattingState.boxGeometry(layoutBox);
- // Inline boxes may or may not be wrapped and have runs on multiple lines (e.g. <span>first line<br>second line<br>third line</span>)
- auto inlineBoxBorderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
- auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
- auto logicalRect = Rect { LayoutPoint { inlineBoxBorderBox.topLeft() }, inlineBoxSize };
- logicalRect.moveBy(LayoutPoint { lineBoxLogicalRect.topLeft() });
- if (inlineBoxStartSet.contains(&layoutBox)) {
- // This inline box showed up first on this line.
- boxGeometry.setLogicalTopLeft(logicalRect.topLeft());
- auto contentBoxHeight = logicalRect.height() - (boxGeometry.verticalBorder() + boxGeometry.verticalPadding().value_or(0_lu));
- boxGeometry.setContentBoxHeight(contentBoxHeight);
- auto contentBoxWidth = logicalRect.width() - (boxGeometry.horizontalBorder() + boxGeometry.horizontalPadding().value_or(0_lu));
- boxGeometry.setContentBoxWidth(contentBoxWidth);
- continue;
- }
- // Middle or end of the inline box. Let's stretch the box as needed.
- formattingState.lineRuns().insert(lineSpanningInlineBoxIndex++, { lineIndex, LineRun::Type::NonRootInlineBox, layoutBox, inlineBoxBorderBox, { }, { }, inlineLevelBox.hasContent(), true });
-
- auto enclosingBorderBoxRect = BoxGeometry::borderBoxRect(boxGeometry);
- enclosingBorderBoxRect.expandToContain(logicalRect);
- boxGeometry.setLogicalLeft(enclosingBorderBoxRect.left());
-
- boxGeometry.setContentBoxHeight(enclosingBorderBoxRect.height() - (boxGeometry.verticalBorder() + boxGeometry.verticalPadding().value_or(0_lu)));
- boxGeometry.setContentBoxWidth(enclosingBorderBoxRect.width() - (boxGeometry.horizontalBorder() + boxGeometry.horizontalPadding().value_or(0_lu)));
- }
- };
- updateBoxGeometryForInlineBoxes();
-
+ InlineDisplayContentBuilder(root(), formattingState).build(lineContent, formattingState.lineBoxes().last(), lineBoxLogicalRect.topLeft(), currentLineIndex);
return lineBoxLogicalRect;
}
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h (281733 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -72,7 +72,7 @@
void computeWidthAndMargin(const Box&, const HorizontalConstraints&);
void collectContentIfNeeded();
- InlineRect computeGeometryForLineContent(const LineBuilder::LineContent&, const HorizontalConstraints&);
+ InlineRect computeGeometryForLineContent(const LineBuilder::LineContent&);
void invalidateFormattingState(const InvalidationState&);
const InlineFormattingGeometry m_inlineFormattingGeometry;
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h (281733 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLevelBox.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -41,7 +41,8 @@
class InlineLevelBox {
public:
- static InlineLevelBox createInlineBox(const Box&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth);
+ enum class LineSpanningInlineBox { Yes, No };
+ static InlineLevelBox createInlineBox(const Box&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, LineSpanningInlineBox = LineSpanningInlineBox::No);
static InlineLevelBox createAtomicInlineLevelBox(const Box&, InlineLayoutUnit logicalLeft, InlineLayoutSize);
static InlineLevelBox createLineBreakBox(const Box&, InlineLayoutUnit logicalLeft);
static InlineLevelBox createGenericInlineLevelBox(const Box&, InlineLayoutUnit logicalLeft);
@@ -65,8 +66,9 @@
const Box& layoutBox() const { return *m_layoutBox; }
const RenderStyle& style() const { return m_layoutBox->style(); }
- bool isInlineBox() const { return m_type == Type::InlineBox || m_type == Type::RootInlineBox; }
+ bool isInlineBox() const { return m_type == Type::InlineBox || isRootInlineBox() || isLineSpanningInlineBox(); }
bool isRootInlineBox() const { return m_type == Type::RootInlineBox; }
+ bool isLineSpanningInlineBox() const { return m_type == Type::LineSpanningInlineBox; }
bool isAtomicInlineLevelBox() const { return m_type == Type::AtomicInlineLevelBox; }
bool isLineBreakBox() const { return m_type == Type::LineBreakBox; }
bool hasLineBoxRelativeAlignment() const;
@@ -73,6 +75,7 @@
enum class Type : uint8_t {
InlineBox = 1 << 0,
+ LineSpanningInlineBox = 1 << 1,
RootInlineBox = 1 << 1,
AtomicInlineLevelBox = 1 << 2,
LineBreakBox = 1 << 3,
@@ -138,9 +141,9 @@
return InlineLevelBox { layoutBox, logicalLeft, logicalSize, Type::AtomicInlineLevelBox };
}
-inline InlineLevelBox InlineLevelBox::createInlineBox(const Box& layoutBox, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth)
+inline InlineLevelBox InlineLevelBox::createInlineBox(const Box& layoutBox, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, LineSpanningInlineBox isLineSpanning)
{
- return InlineLevelBox { layoutBox, logicalLeft, InlineLayoutSize { logicalWidth, { } }, Type::InlineBox };
+ return InlineLevelBox { layoutBox, logicalLeft, InlineLayoutSize { logicalWidth, { } }, isLineSpanning == LineSpanningInlineBox::Yes ? Type::LineSpanningInlineBox : Type::InlineBox };
}
inline InlineLevelBox InlineLevelBox::createLineBreakBox(const Box& layoutBox, InlineLayoutUnit logicalLeft)
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h (281733 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -68,6 +68,7 @@
bool isWordBreakOpportunity() const { return m_type == InlineItem::Type::WordBreakOpportunity; }
bool isInlineBoxStart() const { return m_type == InlineItem::Type::InlineBoxStart; }
bool isInlineBoxEnd() const { return m_type == InlineItem::Type::InlineBoxEnd; }
+ auto type() const { return m_type; }
const Box& layoutBox() const { return *m_layoutBox; }
const RenderStyle& style() const { return m_layoutBox->style(); }
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp (281733 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp 2021-08-28 13:15:49 UTC (rev 281734)
@@ -26,7 +26,10 @@
#include "config.h"
#include "InlineLineBoxBuilder.h"
+#include "InlineLineBoxVerticalAligner.h"
#include "InlineLineBuilder.h"
+#include "LayoutBoxGeometry.h"
+#include "LayoutReplacedBox.h"
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
@@ -191,7 +194,7 @@
canUseSimplifiedAlignment = LineBoxVerticalAligner::canUseSimplifiedAlignmentForInlineLevelBox(rootInlineBox, inlineLevelBox, boxGeometry);
};
- auto createWrappedInlineBoxes = [&] {
+ auto createLineSpanningInlineBoxes = [&] {
if (runs.isEmpty())
return;
// An inline box may not necessarily start on the current line:
@@ -220,13 +223,13 @@
}
// Construct the missing LineBox::InlineBoxes starting with the topmost layout box.
for (auto* layoutBox : WTF::makeReversedRange(layoutBoxesWithoutInlineBoxes)) {
- auto inlineBox = InlineLevelBox::createInlineBox(*layoutBox, rootInlineBox.logicalLeft(), rootInlineBox.logicalWidth());
+ auto inlineBox = InlineLevelBox::createInlineBox(*layoutBox, rootInlineBox.logicalLeft(), rootInlineBox.logicalWidth(), InlineLevelBox::LineSpanningInlineBox::Yes);
setVerticalGeometryForInlineBox(inlineBox);
updateCanUseSimplifiedAlignment(inlineBox);
lineBox.addInlineLevelBox(WTFMove(inlineBox));
}
};
- createWrappedInlineBoxes();
+ createLineSpanningInlineBoxes();
auto lineHasContent = false;
for (auto& run : runs) {
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h (281733 => 281734)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -27,7 +27,9 @@
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+#include "InlineFormattingContext.h"
#include "InlineLineBox.h"
+#include "InlineLineBuilder.h"
#include "InlineLineGeometry.h"
namespace WebCore {
@@ -35,7 +37,6 @@
class Box;
class ContainerBox;
-class InlineFormattingContext;
class LayoutState;
class LineBoxBuilder {
Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContentBuilder.cpp (281733 => 281734)
--- trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContentBuilder.cpp 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContentBuilder.cpp 2021-08-28 13:15:49 UTC (rev 281734)
@@ -55,7 +55,7 @@
return { enclosingTopAndBottom.top + offset, enclosingTopAndBottom.bottom + offset };
}
-inline static float lineOverflowWidth(const RenderBlockFlow& flow, InlineLayoutUnit lineBoxLogicalWidth, InlineLayoutUnit lineContentLogicalWidth)
+inline static float lineOverflowWidth(const RenderBlockFlow& flow, Layout::InlineLayoutUnit lineBoxLogicalWidth, Layout::InlineLayoutUnit lineContentLogicalWidth)
{
// FIXME: It's the copy of the lets-adjust-overflow-for-the-caret behavior from LegacyLineLayout::addOverflowFromInlineChildren.
auto endPadding = flow.hasNonVisibleOverflow() ? flow.paddingEnd() : 0_lu;
Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationRun.h (281733 => 281734)
--- trunk/Source/WebCore/layout/integration/LayoutIntegrationRun.h 2021-08-28 06:53:18 UTC (rev 281733)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationRun.h 2021-08-28 13:15:49 UTC (rev 281734)
@@ -73,7 +73,7 @@
struct Expansion {
ExpansionBehavior behavior { DefaultExpansion };
- InlineLayoutUnit horizontalExpansion { 0 };
+ Layout::InlineLayoutUnit horizontalExpansion { 0 };
};
Expansion expansion() const { return m_expansion; }