Title: [281714] trunk/Source/WebCore
Revision
281714
Author
[email protected]
Date
2021-08-27 12:32:52 -0700 (Fri, 27 Aug 2021)

Log Message

[LFC][IFC] Move LineBoxBuilder to its own file
https://bugs.webkit.org/show_bug.cgi?id=229616

Reviewed by Antti Koivisto.

This is in preparation for supporting incremental line layout.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
* layout/formattingContexts/inline/InlineFormattingGeometry.cpp:
(WebCore::Layout::LineBoxBuilder::formattingContext const): Deleted.
(WebCore::Layout::LineBoxBuilder::rootBox const): Deleted.
(WebCore::Layout::LineBoxBuilder::layoutState const): Deleted.
(WebCore::Layout::LineBoxBuilder::isRootLayoutBox const): Deleted.
(WebCore::Layout::hangingGlyphWidth): Deleted.
(WebCore::Layout::horizontalAlignmentOffset): Deleted.
(WebCore::Layout::LineBoxBuilder::LineBoxBuilder): Deleted.
(WebCore::Layout::LineBoxBuilder::build): Deleted.
(WebCore::Layout::LineBoxBuilder::setVerticalGeometryForInlineBox const): Deleted.
(WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes): Deleted.
(WebCore::Layout::InlineFormattingGeometry::lineBoxForLineContent const): Deleted.
* layout/formattingContexts/inline/InlineFormattingGeometry.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (281713 => 281714)


--- trunk/Source/WebCore/ChangeLog	2021-08-27 19:31:57 UTC (rev 281713)
+++ trunk/Source/WebCore/ChangeLog	2021-08-27 19:32:52 UTC (rev 281714)
@@ -1,5 +1,32 @@
 2021-08-27  Alan Bujtas  <[email protected]>
 
+        [LFC][IFC] Move LineBoxBuilder to its own file
+        https://bugs.webkit.org/show_bug.cgi?id=229616
+
+        Reviewed by Antti Koivisto.
+
+        This is in preparation for supporting incremental line layout.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/formattingContexts/inline/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
+        * layout/formattingContexts/inline/InlineFormattingGeometry.cpp:
+        (WebCore::Layout::LineBoxBuilder::formattingContext const): Deleted.
+        (WebCore::Layout::LineBoxBuilder::rootBox const): Deleted.
+        (WebCore::Layout::LineBoxBuilder::layoutState const): Deleted.
+        (WebCore::Layout::LineBoxBuilder::isRootLayoutBox const): Deleted.
+        (WebCore::Layout::hangingGlyphWidth): Deleted.
+        (WebCore::Layout::horizontalAlignmentOffset): Deleted.
+        (WebCore::Layout::LineBoxBuilder::LineBoxBuilder): Deleted.
+        (WebCore::Layout::LineBoxBuilder::build): Deleted.
+        (WebCore::Layout::LineBoxBuilder::setVerticalGeometryForInlineBox const): Deleted.
+        (WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes): Deleted.
+        (WebCore::Layout::InlineFormattingGeometry::lineBoxForLineContent const): Deleted.
+        * layout/formattingContexts/inline/InlineFormattingGeometry.h:
+
+2021-08-27  Alan Bujtas  <[email protected]>
+
         [IFC][Integration] Generate runs for the root inlinebox
         https://bugs.webkit.org/show_bug.cgi?id=229599
 

Modified: trunk/Source/WebCore/Sources.txt (281713 => 281714)


--- trunk/Source/WebCore/Sources.txt	2021-08-27 19:31:57 UTC (rev 281713)
+++ trunk/Source/WebCore/Sources.txt	2021-08-27 19:32:52 UTC (rev 281714)
@@ -1459,6 +1459,7 @@
 layout/formattingContexts/inline/InlineItem.cpp
 layout/formattingContexts/inline/InlineLine.cpp
 layout/formattingContexts/inline/InlineLineBox.cpp
+layout/formattingContexts/inline/InlineLineBoxBuilder.cpp
 layout/formattingContexts/inline/InlineLineBuilder.cpp
 layout/formattingContexts/inline/InlineLineBoxVerticalAligner.cpp
 layout/formattingContexts/inline/InlineTextItem.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (281713 => 281714)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-08-27 19:31:57 UTC (rev 281713)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-08-27 19:32:52 UTC (rev 281714)
@@ -417,6 +417,7 @@
 		119340971FED715500935F1E /* RenderTreeBuilderFormControls.h in Headers */ = {isa = PBXBuildFile; fileRef = 119340951FED715500935F1E /* RenderTreeBuilderFormControls.h */; };
 		119340A31FEE024000935F1E /* RenderTreeBuilderBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 119340A11FEE024000935F1E /* RenderTreeBuilderBlock.h */; };
 		1199FA46208E35A3002358CC /* LayoutContainerBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 1199FA44208E35A3002358CC /* LayoutContainerBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		11C3227D26D958CE00328F4D /* InlineLineBoxBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 11C3227C26D958CE00328F4D /* InlineLineBoxBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		11CB2789203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 11CB2787203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h */; };
 		11E51638261E1A0600E69F25 /* WebXRInputSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 11E51635261E1A0500E69F25 /* WebXRInputSpace.h */; };
 		11E51639261E1A0600E69F25 /* WebXRInputSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11E51637261E1A0500E69F25 /* WebXRInputSpace.cpp */; };
@@ -6454,6 +6455,8 @@
 		1199FA44208E35A3002358CC /* LayoutContainerBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutContainerBox.h; sourceTree = "<group>"; };
 		1199FA45208E35A3002358CC /* LayoutContainerBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutContainerBox.cpp; sourceTree = "<group>"; };
 		11B042FB20B0E21400828A6B /* LayoutDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutDescendantIterator.h; sourceTree = "<group>"; };
+		11C3227A26D958B500328F4D /* InlineLineBoxBuilder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InlineLineBoxBuilder.cpp; sourceTree = "<group>"; };
+		11C3227C26D958CE00328F4D /* InlineLineBoxBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineBoxBuilder.h; sourceTree = "<group>"; };
 		11C5F1162003E7750001AE60 /* RenderTreeBuilderInline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeBuilderInline.cpp; sourceTree = "<group>"; };
 		11C5F1182003E7760001AE60 /* RenderTreeBuilderInline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderInline.h; sourceTree = "<group>"; };
 		11C5F11D2003F69E0001AE60 /* RenderTreeBuilderBlockFlow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderBlockFlow.h; sourceTree = "<group>"; };
@@ -18045,6 +18048,8 @@
 				6F0CD694229ED32700C5994E /* InlineLine.h */,
 				6F69A79924D6FAB800E6B85D /* InlineLineBox.cpp */,
 				6FB2400323DFF12700796458 /* InlineLineBox.h */,
+				11C3227A26D958B500328F4D /* InlineLineBoxBuilder.cpp */,
+				11C3227C26D958CE00328F4D /* InlineLineBoxBuilder.h */,
 				6F6EE74426D44F0300374CDA /* InlineLineBoxVerticalAligner.cpp */,
 				6F6EE74126D44EE200374CDA /* InlineLineBoxVerticalAligner.h */,
 				6F25B200220A85AB0000011B /* InlineLineBuilder.cpp */,
@@ -33304,6 +33309,7 @@
 				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/formattingContexts/inline/InlineFormattingContext.cpp (281713 => 281714)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp	2021-08-27 19:31:57 UTC (rev 281713)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp	2021-08-27 19:32:52 UTC (rev 281714)
@@ -32,6 +32,7 @@
 #include "FontCascade.h"
 #include "InlineFormattingState.h"
 #include "InlineLineBox.h"
+#include "InlineLineBoxBuilder.h"
 #include "InlineLineRun.h"
 #include "InlineTextItem.h"
 #include "InvalidationState.h"
@@ -572,7 +573,7 @@
     auto& formattingGeometry = this->formattingGeometry();
     auto lineIndex = formattingState.lines().size();
 
-    auto lineBoxAndGeometry = formattingGeometry.lineBoxForLineContent(lineContent);
+    auto lineBoxAndGeometry = LineBoxBuilder(*this).build(lineContent);
     formattingState.addLineBox(WTFMove(lineBoxAndGeometry.lineBox));
     formattingState.addLine(lineBoxAndGeometry.lineGeometry);
 

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp (281713 => 281714)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp	2021-08-27 19:31:57 UTC (rev 281713)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp	2021-08-27 19:32:52 UTC (rev 281714)
@@ -42,338 +42,11 @@
 namespace WebCore {
 namespace Layout {
 
-class LineBoxBuilder {
-public:
-    LineBoxBuilder(const InlineFormattingContext&);
-
-    InlineFormattingGeometry::LineBoxAndGeometry build(const LineBuilder::LineContent&);
-
-private:
-    void setVerticalGeometryForInlineBox(InlineLevelBox&) const;
-    InlineLayoutUnit constructAndAlignInlineLevelBoxes(LineBox&, const Line::RunList&);
-
-    const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
-    const Box& rootBox() const { return formattingContext().root(); }
-    LayoutState& layoutState() const { return formattingContext().layoutState(); }
-
-    bool isRootLayoutBox(const ContainerBox& containerBox) const { return &containerBox == &rootBox(); }
-
-private:
-    const InlineFormattingContext& m_inlineFormattingContext;
-};
-
-static InlineLayoutUnit hangingGlyphWidth(InlineLayoutUnit extraHorizontalSpace, const Line::RunList& runs, bool isLastLineWithInlineContent)
-{
-    // When a glyph at the start or end edge of a line hangs, it is not considered when measuring the line’s contents for fit, alignment, or justification.
-    // Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
-    // https://drafts.csswg.org/css-text-3/#hanging
-    auto isConditional = isLastLineWithInlineContent;
-    auto hangingWidth = InlineLayoutUnit { };
-    for (auto& run : WTF::makeReversedRange(runs)) {
-        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
-            continue;
-        if (run.isLineBreak()) {
-            isConditional = true;
-            continue;
-        }
-        if (!run.hasTrailingWhitespace())
-            break;
-        // Check if we have a preserved or hung whitespace.
-        if (run.style().whiteSpace() != WhiteSpace::PreWrap)
-            break;
-        // This is either a normal or conditionally hanging trailing whitespace.
-        hangingWidth += run.trailingWhitespaceWidth();
-    }
-    // In some cases, a glyph at the end of a line can conditionally hang: it hangs only if it does not otherwise fit in the line prior to justification.
-    return !isConditional || extraHorizontalSpace < 0 ? hangingWidth : InlineLayoutUnit { };
-}
-
-static std::optional<InlineLayoutUnit> horizontalAlignmentOffset(const Line::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, bool isLastLine)
-{
-    auto extraHorizontalSpace = lineLogicalWidth - contentLogicalWidth;
-    // Depending on the line’s alignment/justification, the hanging glyph can be placed outside the line box.
-    extraHorizontalSpace += hangingGlyphWidth(extraHorizontalSpace, runs, isLastLine);
-    if (extraHorizontalSpace <= 0)
-        return { };
-
-    auto computedHorizontalAlignment = [&] {
-        if (textAlign != TextAlignMode::Justify)
-            return textAlign;
-        // Text is justified according to the method specified by the text-justify property,
-        // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
-        // the last line before a forced break or the end of the block is start-aligned.
-        if (isLastLine || (!runs.isEmpty() && runs.last().isLineBreak()))
-            return TextAlignMode::Start;
-        return TextAlignMode::Justify;
-    };
-
-    switch (computedHorizontalAlignment()) {
-    case TextAlignMode::Left:
-    case TextAlignMode::WebKitLeft:
-    case TextAlignMode::Start:
-        return { };
-    case TextAlignMode::Right:
-    case TextAlignMode::WebKitRight:
-    case TextAlignMode::End:
-        return extraHorizontalSpace;
-    case TextAlignMode::Center:
-    case TextAlignMode::WebKitCenter:
-        return extraHorizontalSpace / 2;
-    case TextAlignMode::Justify:
-        // TextAlignMode::Justify is a run alignment (and we only do inline box alignment here)
-        return { };
-    default:
-        ASSERT_NOT_IMPLEMENTED_YET();
-        return { };
-    }
-    ASSERT_NOT_REACHED();
-    return { };
-}
-
-LineBoxBuilder::LineBoxBuilder(const InlineFormattingContext& inlineFormattingContext)
-    : m_inlineFormattingContext(inlineFormattingContext)
-{
-}
-
-InlineFormattingGeometry::LineBoxAndGeometry LineBoxBuilder::build(const LineBuilder::LineContent& lineContent)
-{
-    auto& runs = lineContent.runs;
-    auto contentLogicalWidth = lineContent.contentLogicalWidth;
-    auto contentLogicalLeft = Layout::horizontalAlignmentOffset(runs, rootBox().style().textAlign(), lineContent.lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent).value_or(InlineLayoutUnit { });
-    auto lineBox = LineBox { rootBox(), contentLogicalLeft, contentLogicalWidth, lineContent.nonSpanningInlineLevelBoxCount };
-
-    auto lineBoxLogicalHeight = constructAndAlignInlineLevelBoxes(lineBox, runs);
-
-    auto lineGeometry = [&] {
-        auto lineBoxLogicalRect = InlineRect { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, lineBoxLogicalHeight };
-        auto& rootInlineBox = lineBox.rootInlineBox();
-        auto enclosingTopAndBottom = LineGeometry::EnclosingTopAndBottom { rootInlineBox.logicalTop(), rootInlineBox.logicalBottom() };
-
-        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
-            if (!inlineLevelBox.isAtomicInlineLevelBox() || !inlineLevelBox.isInlineBox())
-                continue;
-
-            auto& layoutBox = inlineLevelBox.layoutBox();
-            auto borderBox = InlineRect { };
-
-            if (inlineLevelBox.isAtomicInlineLevelBox())
-                borderBox = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, formattingContext().geometryForBox(layoutBox));
-            else if (inlineLevelBox.isInlineBox())
-                borderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, formattingContext().geometryForBox(layoutBox));
-            else
-                ASSERT_NOT_REACHED();
-
-            borderBox.moveBy(lineBoxLogicalRect.topLeft());
-            enclosingTopAndBottom.top = std::min(enclosingTopAndBottom.top, borderBox.top());
-            enclosingTopAndBottom.bottom = std::max(enclosingTopAndBottom.bottom, borderBox.bottom());
-        }
-        return LineGeometry { lineBoxLogicalRect, enclosingTopAndBottom, rootInlineBox.logicalTop() + rootInlineBox.baseline(), rootInlineBox.logicalLeft(), rootInlineBox.logicalWidth() };
-    };
-    return { lineBox, lineGeometry() };
-}
-
-void LineBoxBuilder::setVerticalGeometryForInlineBox(InlineLevelBox& inlineLevelBox) const
-{
-    ASSERT(inlineLevelBox.isInlineBox() || inlineLevelBox.isLineBreakBox());
-    auto& fontMetrics = inlineLevelBox.style().fontMetrics();
-    InlineLayoutUnit ascent = fontMetrics.ascent();
-    InlineLayoutUnit descent = fontMetrics.descent();
-    auto logicalHeight = ascent + descent;
-    // We need floor/ceil to match legacy layout integral positioning.
-    inlineLevelBox.setBaseline(floorf(ascent));
-    inlineLevelBox.setDescent(ceil(descent));
-    inlineLevelBox.setLogicalHeight(logicalHeight);
-
-    // FIXME: Adjust layout bounds with fallback font when applicable.
-    auto& style = inlineLevelBox.layoutBox().style();
-    auto lineHeight = style.lineHeight();
-    if (lineHeight.isNegative()) {
-        // If line-height computes to normal and either text-edge is leading or this is the root inline box,
-        // the font’s line gap metric may also be incorporated into A and D by adding half to each side as half-leading.
-        // https://www.w3.org/TR/css-inline-3/#inline-height
-        // Since text-edge is not supported yet and the initial value is leading, we should just apply it to
-        // all inline boxes.
-        auto halfLineGap = (fontMetrics.lineSpacing() - logicalHeight) / 2;
-        ascent += halfLineGap;
-        descent += halfLineGap;
-    } else {
-        InlineLayoutUnit lineHeight = style.computedLineHeight();
-        InlineLayoutUnit halfLeading = (lineHeight - (ascent + descent)) / 2;
-        ascent += halfLeading;
-        descent += halfLeading;
-    }
-    // We need floor/ceil to match legacy layout integral positioning.
-    inlineLevelBox.setLayoutBounds(InlineLevelBox::LayoutBounds { floorf(ascent), ceil(descent) });
-}
-
-InlineLayoutUnit LineBoxBuilder::constructAndAlignInlineLevelBoxes(LineBox& lineBox, const Line::RunList& runs)
-{
-    auto& rootInlineBox = lineBox.rootInlineBox();
-    setVerticalGeometryForInlineBox(rootInlineBox);
-
-    // FIXME: Add fast path support for line-height content.
-    // FIXME: We should always be able to exercise the fast path when the line has no content at all, even in non-standards mode or with line-height set.
-    auto canUseSimplifiedAlignment = layoutState().inStandardsMode() && rootBox().style().lineHeight().isNegative();
-    auto updateCanUseSimplifiedAlignment = [&](auto& inlineLevelBox, std::optional<const BoxGeometry> boxGeometry = std::nullopt) {
-        if (!canUseSimplifiedAlignment)
-            return;
-        canUseSimplifiedAlignment = LineBoxVerticalAligner::canUseSimplifiedAlignmentForInlineLevelBox(rootInlineBox, inlineLevelBox, boxGeometry);
-    };
-
-    auto createWrappedInlineBoxes = [&] {
-        if (runs.isEmpty())
-            return;
-        // An inline box may not necessarily start on the current line:
-        // <span id=outer>line break<br>this content's parent inline box('outer') <span id=inner>starts on the previous line</span></span>
-        // We need to make sure that there's an InlineLevelBox for every inline box that's present on the current line.
-        // In nesting case we need to create InlineLevelBoxes for the inline box ancestors.
-        // We only have to do it on the first run as any subsequent inline content is either at the same/higher nesting level or
-        // nested with a [inline box start] run.
-        auto& firstRun = runs[0];
-        auto& firstRunParentLayoutBox = firstRun.layoutBox().parent();
-        // If the parent is the formatting root, we can stop here. This is root inline box content, there's no nesting inline box from the previous line(s)
-        // unless the inline box closing is forced over to the current line.
-        // e.g.
-        // <span>normally the inline box closing forms a continuous content</span>
-        // <span>unless it's forced to the next line<br></span>
-        auto firstRunNeedsInlineBox = firstRun.isInlineBoxEnd();
-        if (!firstRunNeedsInlineBox && isRootLayoutBox(firstRunParentLayoutBox))
-            return;
-        Vector<const Box*> layoutBoxesWithoutInlineBoxes;
-        if (firstRunNeedsInlineBox)
-            layoutBoxesWithoutInlineBoxes.append(&firstRun.layoutBox());
-        auto* ancestor = &firstRunParentLayoutBox;
-        while (!isRootLayoutBox(*ancestor)) {
-            layoutBoxesWithoutInlineBoxes.append(ancestor);
-            ancestor = &ancestor->parent();
-        }
-        // 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());
-            setVerticalGeometryForInlineBox(inlineBox);
-            updateCanUseSimplifiedAlignment(inlineBox);
-            lineBox.addInlineLevelBox(WTFMove(inlineBox));
-        }
-    };
-    createWrappedInlineBoxes();
-
-    auto lineHasContent = false;
-    for (auto& run : runs) {
-        auto& layoutBox = run.layoutBox();
-        auto runHasContent = [&] () -> bool {
-            ASSERT(!lineHasContent);
-            if (run.isText() || run.isBox() || run.isSoftLineBreak() || run.isHardLineBreak())
-                return true;
-            auto& inlineBoxGeometry = formattingContext().geometryForBox(layoutBox);
-            // Even negative horizontal margin makes the line "contentful".
-            if (run.isInlineBoxStart())
-                return inlineBoxGeometry.marginStart() || inlineBoxGeometry.borderLeft() || inlineBoxGeometry.paddingLeft().value_or(0_lu);
-            if (run.isInlineBoxEnd())
-                return inlineBoxGeometry.marginEnd() || inlineBoxGeometry.borderRight() || inlineBoxGeometry.paddingRight().value_or(0_lu);
-            if (run.isWordBreakOpportunity())
-                return false;
-            ASSERT_NOT_REACHED();
-            return true;
-        };
-        lineHasContent = lineHasContent || runHasContent();
-        auto logicalLeft = rootInlineBox.logicalLeft() + run.logicalLeft();
-        if (run.isBox()) {
-            auto& inlineLevelBoxGeometry = formattingContext().geometryForBox(layoutBox);
-            auto marginBoxHeight = inlineLevelBoxGeometry.marginBoxHeight();
-            auto ascent = InlineLayoutUnit { };
-            if (layoutState().shouldNotSynthesizeInlineBlockBaseline()) {
-                // Integration codepath constructs replaced boxes for inline-block content.
-                ASSERT(layoutBox.isReplacedBox());
-                ascent = *downcast<ReplacedBox>(layoutBox).baseline();
-            } else if (layoutBox.isInlineBlockBox()) {
-                // The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or
-                // if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.
-                auto synthesizeBaseline = !layoutBox.establishesInlineFormattingContext() || !layoutBox.style().isOverflowVisible();
-                if (synthesizeBaseline)
-                    ascent = marginBoxHeight;
-                else {
-                    auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
-                    auto& lastLine = formattingState.lines().last();
-                    auto inlineBlockBaseline = lastLine.lineBoxLogicalRect().top() + lastLine.baseline();
-                    ascent = inlineLevelBoxGeometry.marginBefore() + inlineLevelBoxGeometry.borderTop() + inlineLevelBoxGeometry.paddingTop().value_or(0) + inlineBlockBaseline;
-                }
-            } else if (layoutBox.isReplacedBox())
-                ascent = downcast<ReplacedBox>(layoutBox).baseline().value_or(marginBoxHeight);
-            else
-                ascent = marginBoxHeight;
-            logicalLeft += std::max(0_lu, inlineLevelBoxGeometry.marginStart());
-            auto atomicInlineLevelBox = InlineLevelBox::createAtomicInlineLevelBox(layoutBox, logicalLeft, { inlineLevelBoxGeometry.borderBoxWidth(), marginBoxHeight });
-            atomicInlineLevelBox.setBaseline(ascent);
-            atomicInlineLevelBox.setLayoutBounds(InlineLevelBox::LayoutBounds { ascent, marginBoxHeight - ascent });
-            updateCanUseSimplifiedAlignment(atomicInlineLevelBox, inlineLevelBoxGeometry);
-            lineBox.addInlineLevelBox(WTFMove(atomicInlineLevelBox));
-            continue;
-        }
-        if (run.isInlineBoxStart()) {
-            // At this point we don't know yet how wide this inline box is. Let's assume it's as long as the line is
-            // and adjust it later if we come across an inlineBoxEnd run (see below).
-            // Inline box run is based on margin box. Let's convert it to border box.
-            auto marginStart = formattingContext().geometryForBox(layoutBox).marginStart();
-            auto initialLogicalWidth = rootInlineBox.logicalWidth() - (run.logicalLeft() + marginStart);
-            ASSERT(initialLogicalWidth >= 0);
-            auto inlineBox = InlineLevelBox::createInlineBox(layoutBox, logicalLeft + marginStart, initialLogicalWidth);
-            setVerticalGeometryForInlineBox(inlineBox);
-            updateCanUseSimplifiedAlignment(inlineBox);
-            lineBox.addInlineLevelBox(WTFMove(inlineBox));
-            continue;
-        }
-        if (run.isInlineBoxEnd()) {
-            // Adjust the logical width when the inline box closes on this line.
-            // Note that margin end does not affect the logical width (e.g. positive margin right does not make the run wider).
-            auto& inlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox);
-            ASSERT(inlineBox.isInlineBox());
-            // Inline box run is based on margin box. Let's convert it to border box.
-            // Negative margin end makes the run have negative width.
-            auto marginEndAdjustemnt = -formattingContext().geometryForBox(layoutBox).marginEnd();
-            auto logicalWidth = run.logicalWidth() + marginEndAdjustemnt;
-            auto inlineBoxLogicalRight = logicalLeft + logicalWidth;
-            // 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()));
-            updateCanUseSimplifiedAlignment(inlineBox);
-            continue;
-        }
-        if (run.isText() || run.isSoftLineBreak()) {
-            // FIXME: Adjust non-empty inline box height when glyphs from the non-primary font stretch the box.
-            lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()).setHasContent();
-            continue;
-        }
-        if (run.isHardLineBreak()) {
-            auto lineBreakBox = InlineLevelBox::createLineBreakBox(layoutBox, logicalLeft);
-            setVerticalGeometryForInlineBox(lineBreakBox);
-            updateCanUseSimplifiedAlignment(lineBreakBox);
-            lineBox.addInlineLevelBox(WTFMove(lineBreakBox));
-            continue;
-        }
-        if (run.isWordBreakOpportunity()) {
-            lineBox.addInlineLevelBox(InlineLevelBox::createGenericInlineLevelBox(layoutBox, logicalLeft));
-            continue;
-        }
-        ASSERT_NOT_REACHED();
-    }
-
-    lineBox.setHasContent(lineHasContent);
-
-    auto verticalAligner = LineBoxVerticalAligner { formattingContext() };
-    canUseSimplifiedAlignment = canUseSimplifiedAlignment || !lineHasContent;
-    return verticalAligner.computeLogicalHeightAndAlign(lineBox, canUseSimplifiedAlignment);
-}
-
 InlineFormattingGeometry::InlineFormattingGeometry(const InlineFormattingContext& inlineFormattingContext)
     : FormattingGeometry(inlineFormattingContext)
 {
 }
 
-InlineFormattingGeometry::LineBoxAndGeometry InlineFormattingGeometry::lineBoxForLineContent(const LineBuilder::LineContent& lineContent) const
-{
-    return LineBoxBuilder(formattingContext()).build(lineContent);
-}
-
 InlineLayoutUnit InlineFormattingGeometry::logicalTopForNextLine(const LineBuilder::LineContent& lineContent, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext& floatingContext) const
 {
     // Normally the next line's logical top is the previous line's logical bottom, but when the line ends

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h (281713 => 281714)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h	2021-08-27 19:31:57 UTC (rev 281713)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h	2021-08-27 19:32:52 UTC (rev 281714)
@@ -28,12 +28,12 @@
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "FormattingGeometry.h"
-#include "InlineLineBox.h"
 #include "InlineLineBuilder.h"
 
 namespace WebCore {
 namespace Layout {
 
+class FloatingContext;
 class InlineFormattingContext;
 
 class InlineFormattingGeometry : public FormattingGeometry {
@@ -40,11 +40,6 @@
 public:
     InlineFormattingGeometry(const InlineFormattingContext&);
 
-    struct LineBoxAndGeometry {
-        LineBox lineBox;
-        LineGeometry lineGeometry;
-    };
-    LineBoxAndGeometry lineBoxForLineContent(const LineBuilder::LineContent&) const;
     InlineLayoutUnit logicalTopForNextLine(const LineBuilder::LineContent&, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext&) const;
 
     ContentHeightAndMargin inlineBlockContentHeightAndMargin(const Box&, const HorizontalConstraints&, const OverriddenVerticalValues&) const;

Copied: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp (from rev 281711, trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp) (0 => 281714)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp	                        (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp	2021-08-27 19:32:52 UTC (rev 281714)
@@ -0,0 +1,341 @@
+/*
+ * 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 "InlineLineBoxBuilder.h"
+
+#include "InlineLineBuilder.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+namespace WebCore {
+namespace Layout {
+
+static InlineLayoutUnit hangingGlyphWidth(InlineLayoutUnit extraHorizontalSpace, const Line::RunList& runs, bool isLastLineWithInlineContent)
+{
+    // When a glyph at the start or end edge of a line hangs, it is not considered when measuring the line’s contents for fit, alignment, or justification.
+    // Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
+    // https://drafts.csswg.org/css-text-3/#hanging
+    auto isConditional = isLastLineWithInlineContent;
+    auto hangingWidth = InlineLayoutUnit { };
+    for (auto& run : WTF::makeReversedRange(runs)) {
+        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
+            continue;
+        if (run.isLineBreak()) {
+            isConditional = true;
+            continue;
+        }
+        if (!run.hasTrailingWhitespace())
+            break;
+        // Check if we have a preserved or hung whitespace.
+        if (run.style().whiteSpace() != WhiteSpace::PreWrap)
+            break;
+        // This is either a normal or conditionally hanging trailing whitespace.
+        hangingWidth += run.trailingWhitespaceWidth();
+    }
+    // In some cases, a glyph at the end of a line can conditionally hang: it hangs only if it does not otherwise fit in the line prior to justification.
+    return !isConditional || extraHorizontalSpace < 0 ? hangingWidth : InlineLayoutUnit { };
+}
+
+static std::optional<InlineLayoutUnit> horizontalAlignmentOffset(const Line::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, bool isLastLine)
+{
+    auto extraHorizontalSpace = lineLogicalWidth - contentLogicalWidth;
+    // Depending on the line’s alignment/justification, the hanging glyph can be placed outside the line box.
+    extraHorizontalSpace += hangingGlyphWidth(extraHorizontalSpace, runs, isLastLine);
+    if (extraHorizontalSpace <= 0)
+        return { };
+
+    auto computedHorizontalAlignment = [&] {
+        if (textAlign != TextAlignMode::Justify)
+            return textAlign;
+        // Text is justified according to the method specified by the text-justify property,
+        // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
+        // the last line before a forced break or the end of the block is start-aligned.
+        if (isLastLine || (!runs.isEmpty() && runs.last().isLineBreak()))
+            return TextAlignMode::Start;
+        return TextAlignMode::Justify;
+    };
+
+    switch (computedHorizontalAlignment()) {
+    case TextAlignMode::Left:
+    case TextAlignMode::WebKitLeft:
+    case TextAlignMode::Start:
+        return { };
+    case TextAlignMode::Right:
+    case TextAlignMode::WebKitRight:
+    case TextAlignMode::End:
+        return extraHorizontalSpace;
+    case TextAlignMode::Center:
+    case TextAlignMode::WebKitCenter:
+        return extraHorizontalSpace / 2;
+    case TextAlignMode::Justify:
+        // TextAlignMode::Justify is a run alignment (and we only do inline box alignment here)
+        return { };
+    default:
+        ASSERT_NOT_IMPLEMENTED_YET();
+        return { };
+    }
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+LineBoxBuilder::LineBoxBuilder(const InlineFormattingContext& inlineFormattingContext)
+    : m_inlineFormattingContext(inlineFormattingContext)
+{
+}
+
+LineBoxBuilder::LineBoxAndGeometry LineBoxBuilder::build(const LineBuilder::LineContent& lineContent)
+{
+    auto& runs = lineContent.runs;
+    auto contentLogicalWidth = lineContent.contentLogicalWidth;
+    auto contentLogicalLeft = Layout::horizontalAlignmentOffset(runs, rootBox().style().textAlign(), lineContent.lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent).value_or(InlineLayoutUnit { });
+    auto lineBox = LineBox { rootBox(), contentLogicalLeft, contentLogicalWidth, lineContent.nonSpanningInlineLevelBoxCount };
+
+    auto lineBoxLogicalHeight = constructAndAlignInlineLevelBoxes(lineBox, runs);
+
+    auto lineGeometry = [&] {
+        auto lineBoxLogicalRect = InlineRect { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, lineBoxLogicalHeight };
+        auto& rootInlineBox = lineBox.rootInlineBox();
+        auto enclosingTopAndBottom = LineGeometry::EnclosingTopAndBottom { rootInlineBox.logicalTop(), rootInlineBox.logicalBottom() };
+
+        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
+            if (!inlineLevelBox.isAtomicInlineLevelBox() || !inlineLevelBox.isInlineBox())
+                continue;
+
+            auto& layoutBox = inlineLevelBox.layoutBox();
+            auto borderBox = InlineRect { };
+
+            if (inlineLevelBox.isAtomicInlineLevelBox())
+                borderBox = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, formattingContext().geometryForBox(layoutBox));
+            else if (inlineLevelBox.isInlineBox())
+                borderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, formattingContext().geometryForBox(layoutBox));
+            else
+                ASSERT_NOT_REACHED();
+
+            borderBox.moveBy(lineBoxLogicalRect.topLeft());
+            enclosingTopAndBottom.top = std::min(enclosingTopAndBottom.top, borderBox.top());
+            enclosingTopAndBottom.bottom = std::max(enclosingTopAndBottom.bottom, borderBox.bottom());
+        }
+        return LineGeometry { lineBoxLogicalRect, enclosingTopAndBottom, rootInlineBox.logicalTop() + rootInlineBox.baseline(), rootInlineBox.logicalLeft(), rootInlineBox.logicalWidth() };
+    };
+    return { lineBox, lineGeometry() };
+}
+
+void LineBoxBuilder::setVerticalGeometryForInlineBox(InlineLevelBox& inlineLevelBox) const
+{
+    ASSERT(inlineLevelBox.isInlineBox() || inlineLevelBox.isLineBreakBox());
+    auto& fontMetrics = inlineLevelBox.style().fontMetrics();
+    InlineLayoutUnit ascent = fontMetrics.ascent();
+    InlineLayoutUnit descent = fontMetrics.descent();
+    auto logicalHeight = ascent + descent;
+    // We need floor/ceil to match legacy layout integral positioning.
+    inlineLevelBox.setBaseline(floorf(ascent));
+    inlineLevelBox.setDescent(ceil(descent));
+    inlineLevelBox.setLogicalHeight(logicalHeight);
+
+    // FIXME: Adjust layout bounds with fallback font when applicable.
+    auto& style = inlineLevelBox.layoutBox().style();
+    auto lineHeight = style.lineHeight();
+    if (lineHeight.isNegative()) {
+        // If line-height computes to normal and either text-edge is leading or this is the root inline box,
+        // the font’s line gap metric may also be incorporated into A and D by adding half to each side as half-leading.
+        // https://www.w3.org/TR/css-inline-3/#inline-height
+        // Since text-edge is not supported yet and the initial value is leading, we should just apply it to
+        // all inline boxes.
+        auto halfLineGap = (fontMetrics.lineSpacing() - logicalHeight) / 2;
+        ascent += halfLineGap;
+        descent += halfLineGap;
+    } else {
+        InlineLayoutUnit lineHeight = style.computedLineHeight();
+        InlineLayoutUnit halfLeading = (lineHeight - (ascent + descent)) / 2;
+        ascent += halfLeading;
+        descent += halfLeading;
+    }
+    // We need floor/ceil to match legacy layout integral positioning.
+    inlineLevelBox.setLayoutBounds(InlineLevelBox::LayoutBounds { floorf(ascent), ceil(descent) });
+}
+
+InlineLayoutUnit LineBoxBuilder::constructAndAlignInlineLevelBoxes(LineBox& lineBox, const Line::RunList& runs)
+{
+    auto& rootInlineBox = lineBox.rootInlineBox();
+    setVerticalGeometryForInlineBox(rootInlineBox);
+
+    // FIXME: Add fast path support for line-height content.
+    // FIXME: We should always be able to exercise the fast path when the line has no content at all, even in non-standards mode or with line-height set.
+    auto canUseSimplifiedAlignment = layoutState().inStandardsMode() && rootBox().style().lineHeight().isNegative();
+    auto updateCanUseSimplifiedAlignment = [&](auto& inlineLevelBox, std::optional<const BoxGeometry> boxGeometry = std::nullopt) {
+        if (!canUseSimplifiedAlignment)
+            return;
+        canUseSimplifiedAlignment = LineBoxVerticalAligner::canUseSimplifiedAlignmentForInlineLevelBox(rootInlineBox, inlineLevelBox, boxGeometry);
+    };
+
+    auto createWrappedInlineBoxes = [&] {
+        if (runs.isEmpty())
+            return;
+        // An inline box may not necessarily start on the current line:
+        // <span id=outer>line break<br>this content's parent inline box('outer') <span id=inner>starts on the previous line</span></span>
+        // We need to make sure that there's an InlineLevelBox for every inline box that's present on the current line.
+        // In nesting case we need to create InlineLevelBoxes for the inline box ancestors.
+        // We only have to do it on the first run as any subsequent inline content is either at the same/higher nesting level or
+        // nested with a [inline box start] run.
+        auto& firstRun = runs[0];
+        auto& firstRunParentLayoutBox = firstRun.layoutBox().parent();
+        // If the parent is the formatting root, we can stop here. This is root inline box content, there's no nesting inline box from the previous line(s)
+        // unless the inline box closing is forced over to the current line.
+        // e.g.
+        // <span>normally the inline box closing forms a continuous content</span>
+        // <span>unless it's forced to the next line<br></span>
+        auto firstRunNeedsInlineBox = firstRun.isInlineBoxEnd();
+        if (!firstRunNeedsInlineBox && isRootLayoutBox(firstRunParentLayoutBox))
+            return;
+        Vector<const Box*> layoutBoxesWithoutInlineBoxes;
+        if (firstRunNeedsInlineBox)
+            layoutBoxesWithoutInlineBoxes.append(&firstRun.layoutBox());
+        auto* ancestor = &firstRunParentLayoutBox;
+        while (!isRootLayoutBox(*ancestor)) {
+            layoutBoxesWithoutInlineBoxes.append(ancestor);
+            ancestor = &ancestor->parent();
+        }
+        // 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());
+            setVerticalGeometryForInlineBox(inlineBox);
+            updateCanUseSimplifiedAlignment(inlineBox);
+            lineBox.addInlineLevelBox(WTFMove(inlineBox));
+        }
+    };
+    createWrappedInlineBoxes();
+
+    auto lineHasContent = false;
+    for (auto& run : runs) {
+        auto& layoutBox = run.layoutBox();
+        auto runHasContent = [&] () -> bool {
+            ASSERT(!lineHasContent);
+            if (run.isText() || run.isBox() || run.isSoftLineBreak() || run.isHardLineBreak())
+                return true;
+            auto& inlineBoxGeometry = formattingContext().geometryForBox(layoutBox);
+            // Even negative horizontal margin makes the line "contentful".
+            if (run.isInlineBoxStart())
+                return inlineBoxGeometry.marginStart() || inlineBoxGeometry.borderLeft() || inlineBoxGeometry.paddingLeft().value_or(0_lu);
+            if (run.isInlineBoxEnd())
+                return inlineBoxGeometry.marginEnd() || inlineBoxGeometry.borderRight() || inlineBoxGeometry.paddingRight().value_or(0_lu);
+            if (run.isWordBreakOpportunity())
+                return false;
+            ASSERT_NOT_REACHED();
+            return true;
+        };
+        lineHasContent = lineHasContent || runHasContent();
+        auto logicalLeft = rootInlineBox.logicalLeft() + run.logicalLeft();
+        if (run.isBox()) {
+            auto& inlineLevelBoxGeometry = formattingContext().geometryForBox(layoutBox);
+            auto marginBoxHeight = inlineLevelBoxGeometry.marginBoxHeight();
+            auto ascent = InlineLayoutUnit { };
+            if (layoutState().shouldNotSynthesizeInlineBlockBaseline()) {
+                // Integration codepath constructs replaced boxes for inline-block content.
+                ASSERT(layoutBox.isReplacedBox());
+                ascent = *downcast<ReplacedBox>(layoutBox).baseline();
+            } else if (layoutBox.isInlineBlockBox()) {
+                // The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or
+                // if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.
+                auto synthesizeBaseline = !layoutBox.establishesInlineFormattingContext() || !layoutBox.style().isOverflowVisible();
+                if (synthesizeBaseline)
+                    ascent = marginBoxHeight;
+                else {
+                    auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
+                    auto& lastLine = formattingState.lines().last();
+                    auto inlineBlockBaseline = lastLine.lineBoxLogicalRect().top() + lastLine.baseline();
+                    ascent = inlineLevelBoxGeometry.marginBefore() + inlineLevelBoxGeometry.borderTop() + inlineLevelBoxGeometry.paddingTop().value_or(0) + inlineBlockBaseline;
+                }
+            } else if (layoutBox.isReplacedBox())
+                ascent = downcast<ReplacedBox>(layoutBox).baseline().value_or(marginBoxHeight);
+            else
+                ascent = marginBoxHeight;
+            logicalLeft += std::max(0_lu, inlineLevelBoxGeometry.marginStart());
+            auto atomicInlineLevelBox = InlineLevelBox::createAtomicInlineLevelBox(layoutBox, logicalLeft, { inlineLevelBoxGeometry.borderBoxWidth(), marginBoxHeight });
+            atomicInlineLevelBox.setBaseline(ascent);
+            atomicInlineLevelBox.setLayoutBounds(InlineLevelBox::LayoutBounds { ascent, marginBoxHeight - ascent });
+            updateCanUseSimplifiedAlignment(atomicInlineLevelBox, inlineLevelBoxGeometry);
+            lineBox.addInlineLevelBox(WTFMove(atomicInlineLevelBox));
+            continue;
+        }
+        if (run.isInlineBoxStart()) {
+            // At this point we don't know yet how wide this inline box is. Let's assume it's as long as the line is
+            // and adjust it later if we come across an inlineBoxEnd run (see below).
+            // Inline box run is based on margin box. Let's convert it to border box.
+            auto marginStart = formattingContext().geometryForBox(layoutBox).marginStart();
+            auto initialLogicalWidth = rootInlineBox.logicalWidth() - (run.logicalLeft() + marginStart);
+            ASSERT(initialLogicalWidth >= 0);
+            auto inlineBox = InlineLevelBox::createInlineBox(layoutBox, logicalLeft + marginStart, initialLogicalWidth);
+            setVerticalGeometryForInlineBox(inlineBox);
+            updateCanUseSimplifiedAlignment(inlineBox);
+            lineBox.addInlineLevelBox(WTFMove(inlineBox));
+            continue;
+        }
+        if (run.isInlineBoxEnd()) {
+            // Adjust the logical width when the inline box closes on this line.
+            // Note that margin end does not affect the logical width (e.g. positive margin right does not make the run wider).
+            auto& inlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox);
+            ASSERT(inlineBox.isInlineBox());
+            // Inline box run is based on margin box. Let's convert it to border box.
+            // Negative margin end makes the run have negative width.
+            auto marginEndAdjustemnt = -formattingContext().geometryForBox(layoutBox).marginEnd();
+            auto logicalWidth = run.logicalWidth() + marginEndAdjustemnt;
+            auto inlineBoxLogicalRight = logicalLeft + logicalWidth;
+            // 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()));
+            updateCanUseSimplifiedAlignment(inlineBox);
+            continue;
+        }
+        if (run.isText() || run.isSoftLineBreak()) {
+            // FIXME: Adjust non-empty inline box height when glyphs from the non-primary font stretch the box.
+            lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()).setHasContent();
+            continue;
+        }
+        if (run.isHardLineBreak()) {
+            auto lineBreakBox = InlineLevelBox::createLineBreakBox(layoutBox, logicalLeft);
+            setVerticalGeometryForInlineBox(lineBreakBox);
+            updateCanUseSimplifiedAlignment(lineBreakBox);
+            lineBox.addInlineLevelBox(WTFMove(lineBreakBox));
+            continue;
+        }
+        if (run.isWordBreakOpportunity()) {
+            lineBox.addInlineLevelBox(InlineLevelBox::createGenericInlineLevelBox(layoutBox, logicalLeft));
+            continue;
+        }
+        ASSERT_NOT_REACHED();
+    }
+
+    lineBox.setHasContent(lineHasContent);
+
+    auto verticalAligner = LineBoxVerticalAligner { formattingContext() };
+    canUseSimplifiedAlignment = canUseSimplifiedAlignment || !lineHasContent;
+    return verticalAligner.computeLogicalHeightAndAlign(lineBox, canUseSimplifiedAlignment);
+}
+
+}
+}
+
+#endif

Copied: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h (from rev 281711, trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h) (0 => 281714)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h	                        (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.h	2021-08-27 19:32:52 UTC (rev 281714)
@@ -0,0 +1,68 @@
+/*
+ * 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 "InlineLineBox.h"
+#include "InlineLineGeometry.h"
+
+namespace WebCore {
+namespace Layout {
+
+class Box;
+class ContainerBox;
+class InlineFormattingContext;
+class LayoutState;
+
+class LineBoxBuilder {
+public:
+    LineBoxBuilder(const InlineFormattingContext&);
+
+    struct LineBoxAndGeometry {
+        LineBox lineBox;
+        LineGeometry lineGeometry;
+    };
+    LineBoxAndGeometry build(const LineBuilder::LineContent&);
+
+private:
+    void setVerticalGeometryForInlineBox(InlineLevelBox&) const;
+    InlineLayoutUnit constructAndAlignInlineLevelBoxes(LineBox&, const Line::RunList&);
+
+    const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
+    const Box& rootBox() const { return formattingContext().root(); }
+    LayoutState& layoutState() const { return formattingContext().layoutState(); }
+
+    bool isRootLayoutBox(const ContainerBox& containerBox) const { return &containerBox == &rootBox(); }
+
+private:
+    const InlineFormattingContext& m_inlineFormattingContext;
+};
+
+}
+}
+
+#endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to