Skip to content

Commit

Permalink
[IFC] Introduce RangeBasedLineBuilder
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=271359

Reviewed by Antti Koivisto.

RangeBasedLineBuilder is meant to support a mix of content where a simplified line builder can be used on
well-defined content range(s).
Currently it supports a very simple case only where text content is nested inside an inline box.

  e.g. <div><span>this is text only content</span></div>

In this case we can use the TextOnlySimpleLineBuilder for the nested content while adjusting the result
with the enclosing inline box geometry.

* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::layout):
* Source/WebCore/layout/formattingContexts/inline/InlineLine.h:
* Source/WebCore/layout/formattingContexts/inline/RangeBasedLineBuilder.cpp: Added.
(WebCore::Layout::RangeBasedLineBuilder::RangeBasedLineBuilder):
(WebCore::Layout::RangeBasedLineBuilder::layoutInlineContent):
(WebCore::Layout::RangeBasedLineBuilder::isEligibleForRangeInlineLayout):
* Source/WebCore/layout/formattingContexts/inline/RangeBasedLineBuilder.h: Added.

Canonical link: https://commits.webkit.org/276509@main
  • Loading branch information
alanbaradlay committed Mar 22, 2024
1 parent b29e92b commit 639f7f3
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 33 deletions.
1 change: 1 addition & 0 deletions Source/WebCore/Sources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,7 @@ layout/formattingContexts/inline/InlineLineBoxVerticalAligner.cpp
layout/formattingContexts/inline/InlineTextItem.cpp
layout/formattingContexts/inline/InlineQuirks.cpp
layout/formattingContexts/inline/IntrinsicWidthHandler.cpp
layout/formattingContexts/inline/RangeBasedLineBuilder.cpp
layout/formattingContexts/inline/TextOnlySimpleLineBuilder.cpp
layout/formattingContexts/inline/display/InlineDisplayContent.cpp
layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp
Expand Down
6 changes: 6 additions & 0 deletions Source/WebCore/WebCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -5412,6 +5412,7 @@
DDDFE83F2846ECE5006F1EE5 /* content-script.js in Copy PDF.js Extras */ = {isa = PBXBuildFile; fileRef = DDDFE83C2846ECD4006F1EE5 /* content-script.js */; };
DDE9931E278D0E4B00F60D26 /* libWebKitAdditions.a in Product Dependencies */ = {isa = PBXBuildFile; fileRef = DDE99308278D080B00F60D26 /* libWebKitAdditions.a */; };
DDEA91BA29946E43007E9FDA /* InlineLineTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DDEA91B929946E43007E9FDA /* InlineLineTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
DDECCC1F2BABA8490041CD3C /* RangeBasedLineBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = DDECCC1E2BABA8480041CD3C /* RangeBasedLineBuilder.h */; };
DDFCB4812917014600C799C6 /* InlineFormattingConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = DDFCB4802917014500C799C6 /* InlineFormattingConstraints.h */; settings = {ATTRIBUTES = (Private, ); }; };
DE5F84161FA186E9006DB63A /* UnifiedSource301.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5F83B21FA18676006DB63A /* UnifiedSource301.cpp */; };
DE5F84171FA186E9006DB63A /* UnifiedSource302.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5F83EB1FA186AD006DB63A /* UnifiedSource302.cpp */; };
Expand Down Expand Up @@ -18791,6 +18792,8 @@
DDDFE83C2846ECD4006F1EE5 /* content-script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "content-script.js"; sourceTree = "<group>"; };
DDE99308278D080B00F60D26 /* libWebKitAdditions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libWebKitAdditions.a; sourceTree = BUILT_PRODUCTS_DIR; };
DDEA91B929946E43007E9FDA /* InlineLineTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineTypes.h; sourceTree = "<group>"; };
DDECCC1D2BABA83E0041CD3C /* RangeBasedLineBuilder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RangeBasedLineBuilder.cpp; sourceTree = "<group>"; };
DDECCC1E2BABA8480041CD3C /* RangeBasedLineBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangeBasedLineBuilder.h; sourceTree = "<group>"; };
DDFCB4802917014500C799C6 /* InlineFormattingConstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineFormattingConstraints.h; sourceTree = "<group>"; };
DE5F83B21FA18676006DB63A /* UnifiedSource301.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource301.cpp; sourceTree = "<group>"; };
DE5F83B31FA18677006DB63A /* UnifiedSource355.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource355.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -21832,6 +21835,8 @@
DD9467D52A92D3A300458979 /* IntrinsicWidthHandler.cpp */,
DD9467D62A92D3B800458979 /* IntrinsicWidthHandler.h */,
DDD517EB2A9FC5440069AF81 /* LineLayoutResult.h */,
DDECCC1D2BABA83E0041CD3C /* RangeBasedLineBuilder.cpp */,
DDECCC1E2BABA8480041CD3C /* RangeBasedLineBuilder.h */,
DDA3D5D02A7D847E000ECEE1 /* TextOnlySimpleLineBuilder.cpp */,
DDA3D5CE2A7D844D000ECEE1 /* TextOnlySimpleLineBuilder.h */,
);
Expand Down Expand Up @@ -41529,6 +41534,7 @@
F55B3DCC1251F12D003EF269 /* RadioInputType.h in Headers */,
B658FFA61522EFAA00DD5595 /* RadioNodeList.h in Headers */,
93F1991808245E59001E9ABC /* Range.h in Headers */,
DDECCC1F2BABA8490041CD3C /* RangeBasedLineBuilder.h in Headers */,
93D9D53C0DA27E180077216C /* RangeBoundaryPoint.h in Headers */,
F55B3DCE1251F12D003EF269 /* RangeInputType.h in Headers */,
5C4A0FD725C3435000D9EE97 /* RangeResponseGenerator.h in Headers */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@
namespace WebCore {
namespace Layout {

AbstractLineBuilder::AbstractLineBuilder(InlineFormattingContext& inlineFormattingContext, HorizontalConstraints rootHorizontalConstraints, const InlineItemList& inlineItemList)
AbstractLineBuilder::AbstractLineBuilder(InlineFormattingContext& inlineFormattingContext, const ElementBox& rootBox, HorizontalConstraints rootHorizontalConstraints, const InlineItemList& inlineItemList)
: m_line(inlineFormattingContext)
, m_inlineItemList(inlineItemList)
, m_inlineFormattingContext(inlineFormattingContext)
, m_rootBox(rootBox)
, m_rootHorizontalConstraints(rootHorizontalConstraints)
{
}
Expand Down Expand Up @@ -95,11 +96,6 @@ void AbstractLineBuilder::setIntrinsicWidthMode(IntrinsicWidthMode intrinsicWidt
m_inlineContentBreaker.setIsMinimumInIntrinsicWidthMode(m_intrinsicWidthMode == IntrinsicWidthMode::Minimum);
}

const ElementBox& AbstractLineBuilder::root() const
{
return formattingContext().root();
}

const RenderStyle& AbstractLineBuilder::rootStyle() const
{
return isFirstFormattedLine() ? root().firstLineStyle() : root().style();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class AbstractLineBuilder {
void setIntrinsicWidthMode(IntrinsicWidthMode);

protected:
AbstractLineBuilder(InlineFormattingContext&, HorizontalConstraints rootHorizontalConstraints, const InlineItemList&);
AbstractLineBuilder(InlineFormattingContext&, const ElementBox& rootBox, HorizontalConstraints rootHorizontalConstraints, const InlineItemList&);

void reset();

Expand All @@ -67,7 +67,7 @@ class AbstractLineBuilder {
const InlineLayoutState& layoutState() const;
InlineLayoutState& layoutState();
const BlockLayoutState& blockLayoutState() const { return layoutState().parentBlockLayoutState(); }
const ElementBox& root() const;
const ElementBox& root() const { return m_rootBox; }
const RenderStyle& rootStyle() const;

protected:
Expand All @@ -80,6 +80,7 @@ class AbstractLineBuilder {

private:
InlineFormattingContext& m_inlineFormattingContext;
const ElementBox& m_rootBox;
HorizontalConstraints m_rootHorizontalConstraints;

InlineContentBreaker m_inlineContentBreaker;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "LayoutInlineTextBox.h"
#include "LayoutState.h"
#include "Logging.h"
#include "RangeBasedLineBuilder.h"
#include "RenderStyleInlines.h"
#include "TextOnlySimpleLineBuilder.h"
#include "TextUtil.h"
Expand Down Expand Up @@ -147,10 +148,14 @@ InlineLayoutResult InlineFormattingContext::layout(const ConstraintsForInlineCon
layoutState().setAvailableLineWidthOverride({ *balancedLineWidths });
}

if (TextOnlySimpleLineBuilder::isEligibleForSimplifiedTextOnlyInlineLayoutByContent(inlineContentCache().inlineItems(), placedFloats) && TextOnlySimpleLineBuilder::isEligibleForSimplifiedInlineLayoutByStyle(root())) {
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { *this, constraints.horizontal(), inlineItemList };
if (TextOnlySimpleLineBuilder::isEligibleForSimplifiedTextOnlyInlineLayoutByContent(inlineContentCache().inlineItems(), placedFloats) && TextOnlySimpleLineBuilder::isEligibleForSimplifiedInlineLayoutByStyle(root().style())) {
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { *this, root(), constraints.horizontal(), inlineItemList };
return lineLayout(simplifiedLineBuilder, inlineItemList, needsLayoutRange, previousLine(), constraints, lineDamage);
}
if (RangeBasedLineBuilder::isEligibleForRangeInlineLayout(*this, inlineContentCache().inlineItems(), placedFloats)) {
auto rangeBasedLineBuilder = RangeBasedLineBuilder { *this, constraints.horizontal(), inlineItemList };
return lineLayout(rangeBasedLineBuilder, inlineItemList, needsLayoutRange, previousLine(), constraints, lineDamage);
}
auto lineBuilder = LineBuilder { *this, constraints.horizontal(), inlineItemList };
return lineLayout(lineBuilder, inlineItemList, needsLayoutRange, previousLine(), constraints, lineDamage);
}
Expand Down
6 changes: 4 additions & 2 deletions Source/WebCore/layout/formattingContexts/inline/InlineLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ class Line {

UBiDiLevel bidiLevel() const { return m_bidiLevel; }

// FIXME: Maybe add create functions intead?
Run(const InlineItem&, const RenderStyle&, InlineLayoutUnit logicalLeft);
Run(const InlineItem& lineSpanningInlineBoxItem, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth);

private:
friend class Line;
friend class InlineContentAligner;
Expand All @@ -148,8 +152,6 @@ class Line {
Run(const InlineTextItem&, const RenderStyle&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth);
Run(const InlineSoftLineBreakItem&, const RenderStyle&, InlineLayoutUnit logicalLeft);
Run(const InlineItem&, const RenderStyle&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth);
Run(const InlineItem&, const RenderStyle&, InlineLayoutUnit logicalLeft);
Run(const InlineItem& lineSpanningInlineBoxItem, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth);

const RenderStyle& style() const { return m_style; }
void expand(const InlineTextItem&, InlineLayoutUnit logicalWidth);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ inline void LineCandidate::reset()


LineBuilder::LineBuilder(InlineFormattingContext& inlineFormattingContext, HorizontalConstraints rootHorizontalConstraints, const InlineItemList& inlineItemList)
: AbstractLineBuilder(inlineFormattingContext, rootHorizontalConstraints, inlineItemList)
: AbstractLineBuilder(inlineFormattingContext, inlineFormattingContext.root(), rootHorizontalConstraints, inlineItemList)
, m_floatingContext(inlineFormattingContext.floatingContext())
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ IntrinsicWidthHandler::IntrinsicWidthHandler(InlineFormattingContext& inlineForm
{
auto initializeRangeAndTextOnlyBuilderEligibility = [&] {
m_inlineItemRange = { 0, inlineItems.content().size() };
m_mayUseSimplifiedTextOnlyInlineLayoutInRange = TextOnlySimpleLineBuilder::isEligibleForSimplifiedInlineLayoutByStyle(root());
m_mayUseSimplifiedTextOnlyInlineLayoutInRange = TextOnlySimpleLineBuilder::isEligibleForSimplifiedInlineLayoutByStyle(root().style());
if (!m_mayUseSimplifiedTextOnlyInlineLayoutInRange)
return;

Expand Down Expand Up @@ -130,7 +130,7 @@ InlineLayoutUnit IntrinsicWidthHandler::minimumContentSize()
if (isContentEligibleForNonLineBuilderMinimumWidth(root(), m_mayUseSimplifiedTextOnlyInlineLayoutInRange))
minimumContentSize = simplifiedMinimumWidth(root());
else if (m_mayUseSimplifiedTextOnlyInlineLayoutInRange) {
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { formattingContext(), { }, inlineItemList() };
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { formattingContext(), formattingContext().root(), { }, inlineItemList() };
minimumContentSize = computedIntrinsicWidthForConstraint(IntrinsicWidthMode::Minimum, simplifiedLineBuilder, MayCacheLayoutResult::No);
} else {
auto lineBuilder = LineBuilder { formattingContext(), { }, inlineItemList() };
Expand All @@ -151,11 +151,11 @@ InlineLayoutUnit IntrinsicWidthHandler::maximumContentSize()
if (m_maximumContentWidthBetweenLineBreaks && mayUseContentWidthBetweenLineBreaksAsMaximumSize(root(), inlineItemList())) {
maximumContentSize = *m_maximumContentWidthBetweenLineBreaks;
#ifndef NDEBUG
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { formattingContext(), { }, inlineItemList() };
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { formattingContext(), formattingContext().root(), { }, inlineItemList() };
ASSERT(std::abs(maximumContentSize - computedIntrinsicWidthForConstraint(IntrinsicWidthMode::Maximum, simplifiedLineBuilder, MayCacheLayoutResult::No)) < 1);
#endif
} else {
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { formattingContext(), { }, inlineItemList() };
auto simplifiedLineBuilder = TextOnlySimpleLineBuilder { formattingContext(), formattingContext().root(), { }, inlineItemList() };
maximumContentSize = computedIntrinsicWidthForConstraint(IntrinsicWidthMode::Maximum, simplifiedLineBuilder, mayCacheLayoutResult);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2024 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 "RangeBasedLineBuilder.h"

namespace WebCore {
namespace Layout {

RangeBasedLineBuilder::RangeBasedLineBuilder(InlineFormattingContext& inlineFormattingContext, HorizontalConstraints rootHorizontalConstraints, const InlineItemList& inlineItemList)
: AbstractLineBuilder(inlineFormattingContext, inlineFormattingContext.root(), rootHorizontalConstraints, inlineItemList)
, m_textOnlySimpleLineBuilder(inlineFormattingContext, downcast<ElementBox>(inlineItemList[0].layoutBox()), rootHorizontalConstraints, inlineItemList)
{
}

LineLayoutResult RangeBasedLineBuilder::layoutInlineContent(const LineInput& lineInput, const std::optional<PreviousLine>& previousLine)
{
// 1. Shrink the layout range that we can run text-only builder on (currently it's just the opening/closing inline box)
// 2. Run text-only line builder
// 3. Insert/append the missing inline box run
auto isFirstLine = !lineInput.needsLayoutRange.startIndex();

auto adjustedNeedsLayoutRange = [&] {
auto needsLayoutRange = lineInput.needsLayoutRange;
if (isFirstLine) {
ASSERT(m_inlineItemList[0].isInlineBoxStart());
ASSERT(!needsLayoutRange.start.offset);
// Skip leading InlineItemStart (e.g. <span>)
++needsLayoutRange.start.index;
}
// SKip trailing InlineItemEnd (e.g. </span>)
ASSERT(m_inlineItemList.last().isInlineBoxEnd());
ASSERT(!needsLayoutRange.end.offset);
--needsLayoutRange.end.index;
return needsLayoutRange;
};
auto needsLayoutRange = adjustedNeedsLayoutRange();
ASSERT(!needsLayoutRange.isEmpty());

auto lineLayoutResult = m_textOnlySimpleLineBuilder.layoutInlineContent({ needsLayoutRange, lineInput.initialLogicalRect }, previousLine);

auto insertLeadingInlineBoxRun = [&] {
auto& leadingInlineItem = m_inlineItemList.first();
ASSERT(leadingInlineItem.isInlineBoxStart());

if (isFirstLine) {
ASSERT(!previousLine);
lineLayoutResult.inlineContent.insert(0, { leadingInlineItem, leadingInlineItem.firstLineStyle(), { } });
lineLayoutResult.inlineItemRange.start = lineInput.needsLayoutRange.start;
return;
}
// Subsequent lines need leading spanning inline box run.
lineLayoutResult.inlineContent.insert(0, { leadingInlineItem, { }, { } });
};
insertLeadingInlineBoxRun();

auto appendTrailingInlineBoxRunIfNeeded = [&] {
if (lineLayoutResult.inlineItemRange.end != needsLayoutRange.end)
return;
auto& trailingInlineItem = m_inlineItemList.last();
lineLayoutResult.inlineContent.append({ trailingInlineItem, isFirstLine ? trailingInlineItem.firstLineStyle() : trailingInlineItem.style(), lineLayoutResult.contentGeometry.logicalWidth });
lineLayoutResult.inlineItemRange.end = lineInput.needsLayoutRange.end;
};
appendTrailingInlineBoxRunIfNeeded();

return lineLayoutResult;
}

bool RangeBasedLineBuilder::isEligibleForRangeInlineLayout(const InlineFormattingContext& inlineFormattingContext, const InlineContentCache::InlineItems& inlineItems, const PlacedFloats& placedFloats)
{
if (inlineItems.isEmpty())
return false;
// Range based line builder only supports the following content <inline box>eligible for text only layout</inline box>
auto& inlineItemList = inlineItems.content();
auto isFullyNestedContent = inlineItems.inlineBoxCount() == 1 && inlineItemList.first().isInlineBoxStart() && inlineItemList.last().isInlineBoxEnd() && inlineItemList.size() > 2;
if (!isFullyNestedContent)
return false;

auto& inlineBox = inlineItemList.first().layoutBox();
auto& inlineBoxGeometry = inlineFormattingContext.geometryForBox(inlineBox);
if (inlineBoxGeometry.horizontalMarginBorderAndPadding()) {
// FIXME: Add start decoration support is just a matter of shrinking the available space for the first line (or on subsequent lines when decoration break is present)
return false;
}
if (inlineBox.style().boxDecorationBreak() != RenderStyle::initialBoxDecorationBreak())
return false;

// Check the nested text content.
if (!inlineItems.hasTextAndLineBreakOnlyContent() || inlineItems.requiresVisualReordering() || !placedFloats.isEmpty())
return false;

if (!TextOnlySimpleLineBuilder::isEligibleForSimplifiedInlineLayoutByStyle(inlineFormattingContext.root().style()) || !TextOnlySimpleLineBuilder::isEligibleForSimplifiedInlineLayoutByStyle(inlineBox.style()))
return false;

return true;
}

}
}

Loading

0 comments on commit 639f7f3

Please sign in to comment.