Diff
Modified: trunk/Source/WebCore/ChangeLog (283046 => 283047)
--- trunk/Source/WebCore/ChangeLog 2021-09-24 17:31:26 UTC (rev 283046)
+++ trunk/Source/WebCore/ChangeLog 2021-09-24 17:44:14 UTC (rev 283047)
@@ -1,3 +1,28 @@
+2021-09-24 Alan Bujtas <za...@apple.com>
+
+ [LFC][IFC] Line breaking only uses a few style properties
+ https://bugs.webkit.org/show_bug.cgi?id=230757
+
+ Reviewed by Antti Koivisto.
+
+ The continuous runs, input to the line breaking, should only contain style properties that line breaking actually uses.
+ This is in preparation for supporting first-line.
+
+ * layout/formattingContexts/inline/InlineContentBreaker.cpp:
+ (WebCore::Layout::InlineContentBreaker::isWrappingAllowed):
+ (WebCore::Layout::InlineContentBreaker::shouldKeepEndOfLineWhitespace const):
+ (WebCore::Layout::InlineContentBreaker::processOverflowingContent const):
+ (WebCore::Layout::InlineContentBreaker::processOverflowingContentWithText const):
+ (WebCore::Layout::InlineContentBreaker::wordBreakBehavior const):
+ (WebCore::Layout::InlineContentBreaker::tryBreakingTextRun const):
+ (WebCore::Layout::InlineContentBreaker::ContinuousContent::append):
+ (WebCore::Layout::InlineContentBreaker::ContinuousContent::reset):
+ * layout/formattingContexts/inline/InlineContentBreaker.h:
+ (WebCore::Layout::InlineContentBreaker::ContinuousContent::Run::Run):
+ * layout/formattingContexts/inline/InlineLineBuilder.cpp:
+ (WebCore::Layout::LineCandidate::InlineContent::appendInlineItem):
+ (WebCore::Layout::LineBuilder::handleInlineContent):
+
2021-09-24 Youenn Fablet <you...@apple.com>
RTCDataChannelHandlerClient does not need to be ref counted
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp (283046 => 283047)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp 2021-09-24 17:31:26 UTC (rev 283046)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp 2021-09-24 17:44:14 UTC (rev 283047)
@@ -112,11 +112,10 @@
return { };
}
-bool InlineContentBreaker::isWrappingAllowed(const InlineItem& inlineItem)
+bool InlineContentBreaker::isWrappingAllowed(const ContinuousContent::Run& run)
{
- auto& styleToUse = inlineItem.isBox() ? inlineItem.layoutBox().parent().style() : inlineItem.layoutBox().style();
// Do not try to wrap overflown 'pre' and 'no-wrap' content to next line.
- return styleToUse.whiteSpace() != WhiteSpace::Pre && styleToUse.whiteSpace() != WhiteSpace::NoWrap;
+ return run.style.whiteSpace != WhiteSpace::Pre && run.style.whiteSpace != WhiteSpace::NoWrap;
}
bool InlineContentBreaker::shouldKeepEndOfLineWhitespace(const ContinuousContent& continuousContent) const
@@ -125,7 +124,7 @@
// Note that the "keep" in this context means we let the whitespace content sit on the current line.
// It might very well get collapsed when we close the line (normal/nowrap/pre-line).
// See https://www.w3.org/TR/css-text-3/#white-space-property
- auto whitespace = continuousContent.runs()[*firstTextRunIndex(continuousContent)].inlineItem.style().whiteSpace();
+ auto whitespace = continuousContent.runs()[*firstTextRunIndex(continuousContent)].style.whiteSpace;
return whitespace == WhiteSpace::Normal || whitespace == WhiteSpace::NoWrap || whitespace == WhiteSpace::PreWrap || whitespace == WhiteSpace::PreLine;
}
@@ -266,7 +265,7 @@
// Parent style drives the wrapping behavior here.
// e.g. <div style="white-space: nowrap">some text<div style="display: inline-block; white-space: pre-wrap"></div></div>.
// While the inline-block has pre-wrap which allows wrapping, the content lives in a nowrap context.
- return isWrappingAllowed(continuousContent.runs()[overflowingRunIndex].inlineItem);
+ return isWrappingAllowed(continuousContent.runs()[overflowingRunIndex]);
};
if (shouldWrapUnbreakableContentToNextLine())
return { Result::Action::Wrap, IsEndOfLine::Yes };
@@ -288,7 +287,7 @@
return false;
}
// Check if this text run needs to stay on the current line.
- return isWrappingAllowed(run.inlineItem);
+ return isWrappingAllowed(run);
};
auto findTrailingRunIndex = [&] (auto breakableRunIndex) -> std::optional<size_t> {
@@ -371,7 +370,7 @@
if (isBreakableRun(run)) {
ASSERT(run.inlineItem.isText());
// We know that this run does not fit the available space. If we can break it at any position, let's just use the start of the run.
- if (wordBreakBehavior(run.inlineItem.style(), lineStatus.hasWrapOpportunityAtPreviousPosition) == WordBreakRule::AtArbitraryPosition) {
+ if (wordBreakBehavior(run.style, lineStatus.hasWrapOpportunityAtPreviousPosition) == WordBreakRule::AtArbitraryPosition) {
// We must be on an inline box boundary. Let's go back to the run in front of the inline box start run.
// e.g. <span>unbreakable_and_overflow<span style="word-break: break-all">breakable</span>
// We are at "breakable", <span> is at index - 1 and the trailing run is at index - 2.
@@ -405,16 +404,16 @@
return { overflowingRunIndex };
}
-OptionSet<InlineContentBreaker::WordBreakRule> InlineContentBreaker::wordBreakBehavior(const RenderStyle& style, bool hasWrapOpportunityAtPreviousPosition) const
+OptionSet<InlineContentBreaker::WordBreakRule> InlineContentBreaker::wordBreakBehavior(const ContinuousContent::Run::Style& style, bool hasWrapOpportunityAtPreviousPosition) const
{
// Disregard any prohibition against line breaks mandated by the word-break property.
// The different wrapping opportunities must not be prioritized.
// Note hyphenation is not applied.
- if (style.lineBreak() == LineBreak::Anywhere)
+ if (style.lineBreak == LineBreak::Anywhere)
return { WordBreakRule::AtArbitraryPosition };
auto includeHyphenationIfAllowed = [&](std::optional<InlineContentBreaker::WordBreakRule> wordBreakRule) -> OptionSet<InlineContentBreaker::WordBreakRule> {
- auto hyphenationIsAllowed = !n_hyphenationIsDisabled && style.hyphens() == Hyphens::Auto && canHyphenate(style.computedLocale());
+ auto hyphenationIsAllowed = !n_hyphenationIsDisabled && style.hyphens == Hyphens::Auto && canHyphenate(style.locale);
if (hyphenationIsAllowed) {
if (wordBreakRule)
return { *wordBreakRule, WordBreakRule::AtHyphenationOpportunities };
@@ -425,18 +424,18 @@
return { };
};
// Breaking is allowed within “words”.
- if (style.wordBreak() == WordBreak::BreakAll)
+ if (style.wordBreak == WordBreak::BreakAll)
return includeHyphenationIfAllowed(WordBreakRule::AtArbitraryPosition);
// For compatibility with legacy content, the word-break property also supports a deprecated break-word keyword.
// When specified, this has the same effect as word-break: normal and overflow-wrap: anywhere, regardless of the actual value of the overflow-wrap property.
- if (style.wordBreak() == WordBreak::BreakWord && !hasWrapOpportunityAtPreviousPosition)
+ if (style.wordBreak == WordBreak::BreakWord && !hasWrapOpportunityAtPreviousPosition)
return includeHyphenationIfAllowed(WordBreakRule::AtArbitraryPosition);
// OverflowWrap::BreakWord/Anywhere An otherwise unbreakable sequence of characters may be broken at an arbitrary point if there are no otherwise-acceptable break points in the line.
// Note that this applies to content where CSS properties (e.g. WordBreak::KeepAll) make it unbreakable.
- if ((style.overflowWrap() == OverflowWrap::BreakWord || style.overflowWrap() == OverflowWrap::Anywhere) && !hasWrapOpportunityAtPreviousPosition)
+ if ((style.overflowWrap == OverflowWrap::BreakWord || style.overflowWrap == OverflowWrap::Anywhere) && !hasWrapOpportunityAtPreviousPosition)
return includeHyphenationIfAllowed(WordBreakRule::AtArbitraryPosition);
// Breaking is forbidden within “words”.
- if (style.wordBreak() == WordBreak::KeepAll)
+ if (style.wordBreak == WordBreak::KeepAll)
return { };
return includeHyphenationIfAllowed({ });
}
@@ -445,7 +444,7 @@
{
ASSERT(overflowingRun.inlineItem.isText());
auto& inlineTextItem = downcast<InlineTextItem>(overflowingRun.inlineItem);
- auto& style = inlineTextItem.style();
+ auto& style = overflowingRun.style;
auto availableSpaceIsInfinite = !availableWidth.has_value();
auto breakRules = wordBreakBehavior(style, hasWrapOpportunityAtPreviousPosition);
@@ -462,18 +461,17 @@
return { };
}
auto runLength = inlineTextItem.length();
- unsigned limitBefore = style.hyphenationLimitBefore() == RenderStyle::initialHyphenationLimitBefore() ? 0 : style.hyphenationLimitBefore();
- unsigned limitAfter = style.hyphenationLimitAfter() == RenderStyle::initialHyphenationLimitAfter() ? 0 : style.hyphenationLimitAfter();
+ auto limitBefore = style.hyphenationLimitBefore.value_or(0);
+ auto limitAfter = style.hyphenationLimitAfter.value_or(0);
// Check if this run can accommodate the before/after limits at all before start measuring text.
if (limitBefore >= runLength || limitAfter >= runLength || limitBefore + limitAfter > runLength)
return { };
unsigned leftSideLength = runLength;
- auto& fontCascade = style.fontCascade();
- auto hyphenWidth = InlineLayoutUnit { fontCascade.width(TextRun { StringView { style.hyphenString() } }) };
+ auto hyphenWidth = InlineLayoutUnit { style.fontCascade.width(TextRun { StringView { style.hyphenString } }) };
if (!availableSpaceIsInfinite) {
auto availableWidthExcludingHyphen = *availableWidth - hyphenWidth;
- if (availableWidthExcludingHyphen <= 0 || !enoughWidthForHyphenation(availableWidthExcludingHyphen, fontCascade.pixelSize()))
+ if (availableWidthExcludingHyphen <= 0 || !enoughWidthForHyphenation(availableWidthExcludingHyphen, style.fontCascade.pixelSize()))
return { };
leftSideLength = TextUtil::midWordBreak(inlineTextItem, overflowingRun.logicalWidth, availableWidthExcludingHyphen, logicalLeft).length;
}
@@ -481,7 +479,7 @@
return { };
// Adjust before index to accommodate the limit-after value (it's the last potential hyphen location in this run).
auto hyphenBefore = std::min(leftSideLength, runLength - limitAfter) + 1;
- unsigned hyphenLocation = lastHyphenLocation(StringView(inlineTextItem.inlineTextBox().content()).substring(inlineTextItem.start(), inlineTextItem.length()), hyphenBefore, style.computedLocale());
+ unsigned hyphenLocation = lastHyphenLocation(StringView(inlineTextItem.inlineTextBox().content()).substring(inlineTextItem.start(), inlineTextItem.length()), hyphenBefore, style.locale);
if (!hyphenLocation || hyphenLocation < limitBefore)
return { };
// hyphenLocation is relative to the start of this InlineItemText.
@@ -518,9 +516,9 @@
return { };
}
-void InlineContentBreaker::ContinuousContent::append(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth, std::optional<InlineLayoutUnit> collapsibleWidth)
+void InlineContentBreaker::ContinuousContent::append(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit logicalWidth, std::optional<InlineLayoutUnit> collapsibleWidth)
{
- m_runs.append({ inlineItem, logicalWidth });
+ m_runs.append({ inlineItem, style, logicalWidth });
m_logicalWidth = clampTo<InlineLayoutUnit>(m_logicalWidth + logicalWidth);
if (!collapsibleWidth) {
m_collapsibleLogicalWidth = { };
@@ -543,7 +541,6 @@
m_collapsibleLogicalWidth = { };
m_runs.clear();
}
-
}
}
#endif
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h (283046 => 283047)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h 2021-09-24 17:31:26 UTC (rev 283046)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.h 2021-09-24 17:44:14 UTC (rev 283047)
@@ -28,11 +28,9 @@
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "LayoutUnits.h"
+#include "RenderStyle.h"
namespace WebCore {
-
-class RenderStyle;
-
namespace Layout {
class InlineItem;
@@ -84,15 +82,28 @@
bool hasTrailingCollapsibleContent() const { return !!collapsibleLogicalWidth(); }
bool isFullyCollapsible() const { return logicalWidth() == collapsibleLogicalWidth(); }
- void append(const InlineItem&, InlineLayoutUnit logicalWidth, std::optional<InlineLayoutUnit> collapsibleWidth);
+ void append(const InlineItem&, const RenderStyle&, InlineLayoutUnit logicalWidth, std::optional<InlineLayoutUnit> collapsibleWidth);
void reset();
struct Run {
- Run(const InlineItem&, InlineLayoutUnit logicalWidth);
+ Run(const InlineItem&, const RenderStyle&, InlineLayoutUnit logicalWidth);
Run(const Run&);
Run& operator=(const Run&);
const InlineItem& inlineItem;
+ struct Style {
+ WhiteSpace whiteSpace { WhiteSpace::Normal };
+ LineBreak lineBreak { LineBreak::Auto };
+ WordBreak wordBreak { WordBreak::Normal };
+ OverflowWrap overflowWrap { OverflowWrap::Normal };
+ Hyphens hyphens { Hyphens::None };
+ std::optional<unsigned> hyphenationLimitBefore;
+ std::optional<unsigned> hyphenationLimitAfter;
+ const FontCascade& fontCascade;
+ const AtomString& hyphenString;
+ const AtomString& locale;
+ };
+ Style style;
InlineLayoutUnit logicalWidth { 0 };
};
using RunList = Vector<Run, 3>;
@@ -116,7 +127,7 @@
Result processInlineContent(const ContinuousContent&, const LineStatus&);
void setHyphenationDisabled() { n_hyphenationIsDisabled = true; }
- static bool isWrappingAllowed(const InlineItem&);
+ static bool isWrappingAllowed(const ContinuousContent::Run&);
private:
Result processOverflowingContent(const ContinuousContent&, const LineStatus&) const;
@@ -127,14 +138,24 @@
AtArbitraryPosition = 1 << 0,
AtHyphenationOpportunities = 1 << 1
};
- OptionSet<WordBreakRule> wordBreakBehavior(const RenderStyle&, bool hasWrapOpportunityAtPreviousPosition) const;
+ OptionSet<WordBreakRule> wordBreakBehavior(const ContinuousContent::Run::Style&, bool hasWrapOpportunityAtPreviousPosition) const;
bool shouldKeepEndOfLineWhitespace(const ContinuousContent&) const;
bool n_hyphenationIsDisabled { false };
};
-inline InlineContentBreaker::ContinuousContent::Run::Run(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth)
+inline InlineContentBreaker::ContinuousContent::Run::Run(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit logicalWidth)
: inlineItem(inlineItem)
+ , style({ style.whiteSpace()
+ , style.lineBreak()
+ , style.wordBreak()
+ , style.overflowWrap()
+ , style.hyphens()
+ , style.hyphenationLimitBefore() != style.initialHyphenationLimitBefore() ? std::make_optional(style.hyphenationLimitBefore()) : std::nullopt
+ , style.hyphenationLimitAfter() != style.initialHyphenationLimitAfter() ? std::make_optional(style.hyphenationLimitAfter()) : std::nullopt
+ , style.fontCascade()
+ , style.hyphenString()
+ , style.fontDescription().computedLocale() })
, logicalWidth(logicalWidth)
{
}
@@ -141,6 +162,7 @@
inline InlineContentBreaker::ContinuousContent::Run::Run(const Run& other)
: inlineItem(other.inlineItem)
+ , style(other.style)
, logicalWidth(other.logicalWidth)
{
}
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp (283046 => 283047)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp 2021-09-24 17:31:26 UTC (rev 283046)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp 2021-09-24 17:44:14 UTC (rev 283047)
@@ -195,7 +195,8 @@
ASSERT(logicalWidth > letterSpacing);
return letterSpacing;
};
- m_continuousContent.append(inlineItem, logicalWidth, collapsibleWidth());
+ // FIXME: While the line breaking related properties for atomic level boxes do not depend on the line index (first line style) it'd be great to figure out the correct style to pass in.
+ m_continuousContent.append(inlineItem, !inlineItem.isBox() ? inlineItem.style() : inlineItem.layoutBox().parent().style(), logicalWidth, collapsibleWidth());
m_hasInlineLevelBox = m_hasInlineLevelBox || inlineItem.isBox() || inlineItem.isInlineBoxStart();
}
@@ -692,11 +693,11 @@
m_line.append(run.inlineItem, run.logicalWidth);
if (lineCandidate.inlineContent.hasTrailingSoftWrapOpportunity()) {
// Check if we are allowed to wrap at this position.
- auto& trailingItem = candidateRuns.last().inlineItem;
+ auto& trailingRun = candidateRuns.last();
// FIXME: There must be a way to decide if the trailing run actually ended up on the line.
// Let's just deal with collapsed leading whitespace for now.
- if (!m_line.runs().isEmpty() && InlineContentBreaker::isWrappingAllowed(trailingItem))
- m_wrapOpportunityList.append(&trailingItem);
+ if (!m_line.runs().isEmpty() && InlineContentBreaker::isWrappingAllowed(trailingRun))
+ m_wrapOpportunityList.append(&trailingRun.inlineItem);
}
return { result.isEndOfLine, { candidateRuns.size(), false } };
}