REGRESSION (r281306): Non-breaking space incorrectly collapsed when webkit-nbsp-mode is set to "space"
https://bugs.webkit.org/show_bug.cgi?id=235627
<rdar://88004831>
Reviewed by Antti Koivisto.
Source/WebCore:
"-webkit-nbsp-mode: space" has a peculiar collapsing behavior. It only collapses as leading content
preceded by forced line break.
<div style="-webkit-nbsp-mode: space; width: 0px;">
first_line second_line
</div>
The non-breaking space is collapsed. It does not show on the second line as leading content.
<div style="-webkit-nbsp-mode: space; width: 0px;">
first_line<br>
second_line
</div>
The non-breaking space is NOT collapsed. It shows up as leading content on the second line, indenting the "second_line" text content.
To mimic this legacy behavior, it's easier just to switch back to handling nbsp; as a non-whitespace inline item and
collapse it as leading content (depending on the breaking context).
(as opposed to customize regular whitespace content collapsing behavior just to support this quirk)
Test: fast/text/collapsible-non-breaking-space.html
* layout/formattingContexts/inline/InlineItemsBuilder.cpp:
(WebCore::Layout::moveToNextNonWhitespacePosition): remove special nbsp; handling
(WebCore::Layout::InlineItemsBuilder::handleTextContent): create an inline text item for the special mon-breaking space content.
* layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::initialize):
(WebCore::Layout::Line::appendTextContent):
* layout/formattingContexts/inline/InlineLine.h:
* layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::inlineItemWidth const):
(WebCore::Layout::LineBuilder::initialize):
(WebCore::Layout::LineBuilder::candidateContentForLine):
(WebCore::Layout::LineBuilder::handleInlineContent):
(WebCore::Layout::LineBuilder::rebuildLine):
* layout/formattingContexts/inline/InlineLineBuilder.h:
(WebCore::Layout::LineBuilder::isFirstLine const):
* layout/formattingContexts/inline/InlineTextItem.cpp:
(WebCore::Layout::InlineTextItem::isCollapsibleNonBreakingSpace const):
* layout/formattingContexts/inline/InlineTextItem.h:
LayoutTests:
* fast/text/collapsible-non-breaking-space-expected.html: Added.
* fast/text/collapsible-non-breaking-space.html: Added.
* platform/ios/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt: A slight behavior change with trailing content trimming, but
not generally noticeable and very specific to this non-standard property.
* platform/mac/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@288650 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 4dcb2c5..5e42ccb 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,17 @@
+2022-01-26 Alan Bujtas <zalan@apple.com>
+
+ REGRESSION (r281306): Non-breaking space incorrectly collapsed when webkit-nbsp-mode is set to "space"
+ https://bugs.webkit.org/show_bug.cgi?id=235627
+ <rdar://88004831>
+
+ Reviewed by Antti Koivisto.
+
+ * fast/text/collapsible-non-breaking-space-expected.html: Added.
+ * fast/text/collapsible-non-breaking-space.html: Added.
+ * platform/ios/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt: A slight behavior change with trailing content trimming, but
+ not generally noticeable and very specific to this non-standard property.
+ * platform/mac/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt:
+
2022-01-26 Alexey Shvayka <ashvayka@apple.com>
globalThis.queueMicrotask() should report thrown exceptions
diff --git a/LayoutTests/fast/text/collapsible-non-breaking-space-expected.html b/LayoutTests/fast/text/collapsible-non-breaking-space-expected.html
new file mode 100644
index 0000000..b6095d1
--- /dev/null
+++ b/LayoutTests/fast/text/collapsible-non-breaking-space-expected.html
@@ -0,0 +1,8 @@
+<style>
+div {
+ background-color: green;
+ width: 80px;
+ height: 220px;
+}
+</style>
+<div></div>
diff --git a/LayoutTests/fast/text/collapsible-non-breaking-space.html b/LayoutTests/fast/text/collapsible-non-breaking-space.html
new file mode 100644
index 0000000..a261a41
--- /dev/null
+++ b/LayoutTests/fast/text/collapsible-non-breaking-space.html
@@ -0,0 +1,22 @@
+<style>
+body {
+ font-size: 20px;
+ font-family: Ahem;
+ color: green;
+}
+div {
+ -webkit-nbsp-mode: space;
+ background-color: green;
+ float: left;
+ clear: both;
+}
+</style>
+<div> </div>
+<div>XX </div>
+<div>X X</div>
+<div style="width: 0px;">XXXX XXXX</div>
+<div style="white-space: pre">XX
+XXX</div>
+<div style="white-space: pre">XX
+ XX</div>
+<div>XXX <br> XXX</div>
diff --git a/LayoutTests/platform/ios/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt b/LayoutTests/platform/ios/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt
index 7ab5f63..0f64007 100644
--- a/LayoutTests/platform/ios/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt
+++ b/LayoutTests/platform/ios/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt
@@ -5,10 +5,10 @@
RenderBody {BODY} at (8,8) size 784x584
layer at (100,8) size 700x208
RenderBlock (positioned) {DIV} at (100,8) size 700x208 [border: (2px solid #FF0000)]
- RenderText {#text} at (14,15) size 659x178
- text run at (14,15) width 659: "This div is absolutely positioned to the left. All the spaces in this div"
- text run at (14,45) width 638: "are replaced with non-breaking spaces, and the nbsp-mode for this"
- text run at (14,75) width 610: "div is 'space', so when calculating line breaks, the non-breaking"
- text run at (14,105) width 651: "spaces should be treated as normal spaces. If this isn't the case, then"
- text run at (14,135) width 622: "all the text for this paragraph will be rendered in two lines, and a"
+ RenderText {#text} at (14,15) size 665x178
+ text run at (14,15) width 665: "This div is absolutely positioned to the left. All the spaces in this div "
+ text run at (14,45) width 644: "are replaced with non-breaking spaces, and the nbsp-mode for this "
+ text run at (14,75) width 616: "div is 'space', so when calculating line breaks, the non-breaking "
+ text run at (14,105) width 657: "spaces should be treated as normal spaces. If this isn't the case, then "
+ text run at (14,135) width 628: "all the text for this paragraph will be rendered in two lines, and a "
text run at (14,165) width 482: "horizontal scroll bar will appear along the bottom."
diff --git a/LayoutTests/platform/mac/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt b/LayoutTests/platform/mac/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt
index c699d9e..8e2fcd0 100644
--- a/LayoutTests/platform/mac/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt
+++ b/LayoutTests/platform/mac/fast/text/whitespace/nbsp-mode-and-linewraps-expected.txt
@@ -5,10 +5,10 @@
RenderBody {BODY} at (8,8) size 784x584
layer at (100,8) size 700x196
RenderBlock (positioned) {DIV} at (100,8) size 700x196 [border: (2px solid #FF0000)]
- RenderText {#text} at (14,14) size 659x168
- text run at (14,14) width 659: "This div is absolutely positioned to the left. All the spaces in this div"
- text run at (14,42) width 638: "are replaced with non-breaking spaces, and the nbsp-mode for this"
- text run at (14,70) width 610: "div is 'space', so when calculating line breaks, the non-breaking"
- text run at (14,98) width 651: "spaces should be treated as normal spaces. If this isn't the case, then"
- text run at (14,126) width 622: "all the text for this paragraph will be rendered in two lines, and a"
+ RenderText {#text} at (14,14) size 665x168
+ text run at (14,14) width 665: "This div is absolutely positioned to the left. All the spaces in this div "
+ text run at (14,42) width 644: "are replaced with non-breaking spaces, and the nbsp-mode for this "
+ text run at (14,70) width 616: "div is 'space', so when calculating line breaks, the non-breaking "
+ text run at (14,98) width 657: "spaces should be treated as normal spaces. If this isn't the case, then "
+ text run at (14,126) width 628: "all the text for this paragraph will be rendered in two lines, and a "
text run at (14,154) width 482: "horizontal scroll bar will appear along the bottom."
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index ae32a71..b8e8bd4 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,50 @@
+2022-01-26 Alan Bujtas <zalan@apple.com>
+
+ REGRESSION (r281306): Non-breaking space incorrectly collapsed when webkit-nbsp-mode is set to "space"
+ https://bugs.webkit.org/show_bug.cgi?id=235627
+ <rdar://88004831>
+
+ Reviewed by Antti Koivisto.
+
+ "-webkit-nbsp-mode: space" has a peculiar collapsing behavior. It only collapses as leading content
+ preceded by forced line break.
+
+ <div style="-webkit-nbsp-mode: space; width: 0px;">
+ first_line second_line
+ </div>
+ The non-breaking space is collapsed. It does not show on the second line as leading content.
+
+ <div style="-webkit-nbsp-mode: space; width: 0px;">
+ first_line<br>
+ second_line
+ </div>
+ The non-breaking space is NOT collapsed. It shows up as leading content on the second line, indenting the "second_line" text content.
+
+ To mimic this legacy behavior, it's easier just to switch back to handling nbsp; as a non-whitespace inline item and
+ collapse it as leading content (depending on the breaking context).
+ (as opposed to customize regular whitespace content collapsing behavior just to support this quirk)
+
+ Test: fast/text/collapsible-non-breaking-space.html
+
+ * layout/formattingContexts/inline/InlineItemsBuilder.cpp:
+ (WebCore::Layout::moveToNextNonWhitespacePosition): remove special nbsp; handling
+ (WebCore::Layout::InlineItemsBuilder::handleTextContent): create an inline text item for the special mon-breaking space content.
+ * layout/formattingContexts/inline/InlineLine.cpp:
+ (WebCore::Layout::Line::initialize):
+ (WebCore::Layout::Line::appendTextContent):
+ * layout/formattingContexts/inline/InlineLine.h:
+ * layout/formattingContexts/inline/InlineLineBuilder.cpp:
+ (WebCore::Layout::LineBuilder::inlineItemWidth const):
+ (WebCore::Layout::LineBuilder::initialize):
+ (WebCore::Layout::LineBuilder::candidateContentForLine):
+ (WebCore::Layout::LineBuilder::handleInlineContent):
+ (WebCore::Layout::LineBuilder::rebuildLine):
+ * layout/formattingContexts/inline/InlineLineBuilder.h:
+ (WebCore::Layout::LineBuilder::isFirstLine const):
+ * layout/formattingContexts/inline/InlineTextItem.cpp:
+ (WebCore::Layout::InlineTextItem::isCollapsibleNonBreakingSpace const):
+ * layout/formattingContexts/inline/InlineTextItem.h:
+
2022-01-26 Alexey Shvayka <ashvayka@apple.com>
JSEventListener::replaceJSFunctionForAttributeListener() should not replace m_wrapper unconditionally
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp
index 5307220..7d92785 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp
@@ -42,13 +42,13 @@
size_t length { 0 };
bool isWordSeparator { true };
};
-static std::optional<WhitespaceContent> moveToNextNonWhitespacePosition(StringView textContent, size_t startPosition, bool preserveNewline, bool preserveTab, bool treatNonBreakingSpaceAsRegularSpace, bool stopAtWordSeparatorBoundary)
+static std::optional<WhitespaceContent> moveToNextNonWhitespacePosition(StringView textContent, size_t startPosition, bool preserveNewline, bool preserveTab, bool stopAtWordSeparatorBoundary)
{
auto hasWordSeparatorCharacter = false;
auto isWordSeparatorCharacter = false;
auto isWhitespaceCharacter = [&](auto character) {
// white space processing in CSS affects only the document white space characters: spaces (U+0020), tabs (U+0009), and segment breaks.
- auto isTreatedAsSpaceCharacter = character == space || (character == newlineCharacter && !preserveNewline) || (character == tabCharacter && !preserveTab) || (character == noBreakSpace && treatNonBreakingSpaceAsRegularSpace);
+ auto isTreatedAsSpaceCharacter = character == space || (character == newlineCharacter && !preserveNewline) || (character == tabCharacter && !preserveTab);
isWordSeparatorCharacter = isTreatedAsSpaceCharacter;
hasWordSeparatorCharacter = hasWordSeparatorCharacter || isWordSeparatorCharacter;
return isTreatedAsSpaceCharacter || character == tabCharacter;
@@ -490,7 +490,6 @@
auto& style = inlineTextBox.style();
auto shouldPreserveSpacesAndTabs = TextUtil::shouldPreserveSpacesAndTabs(inlineTextBox);
auto shouldPreserveNewline = TextUtil::shouldPreserveNewline(inlineTextBox);
- auto shouldTreatNonBreakingSpaceAsRegularSpace = style.nbspMode() == NBSPMode::Space;
auto lineBreakIterator = LazyLineBreakIterator { text, style.computedLocale(), TextUtil::lineBreakIteratorMode(style.lineBreak()) };
unsigned currentPosition = 0;
@@ -508,7 +507,7 @@
auto handleWhitespace = [&] {
auto stopAtWordSeparatorBoundary = shouldPreserveSpacesAndTabs && style.fontCascade().wordSpacing();
- auto whitespaceContent = moveToNextNonWhitespacePosition(text, currentPosition, shouldPreserveNewline, shouldPreserveSpacesAndTabs, shouldTreatNonBreakingSpaceAsRegularSpace, stopAtWordSeparatorBoundary);
+ auto whitespaceContent = moveToNextNonWhitespacePosition(text, currentPosition, shouldPreserveNewline, shouldPreserveSpacesAndTabs, stopAtWordSeparatorBoundary);
if (!whitespaceContent)
return false;
@@ -527,6 +526,26 @@
if (handleWhitespace())
continue;
+ auto handleNonBreakingSpace = [&] {
+ if (style.nbspMode() != NBSPMode::Space) {
+ // Let's just defer to regular non-whitespace inline items when non breaking space needs no special handling.
+ return false;
+ }
+ auto startPosition = currentPosition;
+ auto endPosition = startPosition;
+ for (; endPosition < contentLength; ++endPosition) {
+ if (text[endPosition] != noBreakSpace)
+ break;
+ }
+ if (startPosition == endPosition)
+ return false;
+ inlineItems.append(InlineTextItem::createNonWhitespaceItem(inlineTextBox, startPosition, endPosition - startPosition, UBIDI_DEFAULT_LTR, { }, { }));
+ currentPosition = endPosition;
+ return true;
+ };
+ if (handleNonBreakingSpace())
+ continue;
+
auto handleNonWhitespace = [&] {
auto startPosition = currentPosition;
auto endPosition = startPosition;
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
index 8702c41..24a2b4a 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
@@ -49,8 +49,9 @@
{
}
-void Line::initialize(const Vector<InlineItem>& lineSpanningInlineBoxes)
+void Line::initialize(const Vector<InlineItem>& lineSpanningInlineBoxes, bool collapseLeadingNonBreakingSpace)
{
+ m_collapseLeadingNonBreakingSpace = collapseLeadingNonBreakingSpace;
m_inlineBoxListWithClonedDecorationEnd.clear();
m_clonedEndDecorationWidthForInlineBoxRuns = { };
m_nonSpanningInlineLevelBoxCount = 0;
@@ -261,8 +262,19 @@
void Line::appendTextContent(const InlineTextItem& inlineTextItem, const RenderStyle& style, InlineLayoutUnit logicalWidth)
{
auto willCollapseCompletely = [&] {
- if (!inlineTextItem.isWhitespace())
- return false;
+ if (!inlineTextItem.isWhitespace()) {
+ auto isLeadingCollapsibleNonBreakingSpace = [&] {
+ // Let's check for leading non-breaking space collapsing to match legacy line layout quirk.
+ if (!inlineTextItem.isCollapsibleNonBreakingSpace() || !m_collapseLeadingNonBreakingSpace)
+ return false;
+ for (auto& run : makeReversedRange(m_runs)) {
+ if (run.isBox() || run.isText())
+ return false;
+ }
+ return true;
+ };
+ return isLeadingCollapsibleNonBreakingSpace();
+ }
if (InlineTextItem::shouldPreserveSpacesAndTabs(inlineTextItem))
return false;
// This content is collapsible. Let's check if the last item is collapsed.
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLine.h b/Source/WebCore/layout/formattingContexts/inline/InlineLine.h
index a1f9d43..fa9dfbe 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLine.h
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLine.h
@@ -43,7 +43,7 @@
Line(const InlineFormattingContext&);
~Line();
- void initialize(const Vector<InlineItem>& lineSpanningInlineBoxes);
+ void initialize(const Vector<InlineItem>& lineSpanningInlineBoxes, bool collapseLeadingNonBreakingSpace);
void append(const InlineItem&, const RenderStyle&, InlineLayoutUnit logicalWidth);
@@ -229,6 +229,8 @@
InlineBoxListWithClonedDecorationEnd m_inlineBoxListWithClonedDecorationEnd;
InlineLayoutUnit m_clonedEndDecorationWidthForInlineBoxRuns { 0 };
bool m_hasNonDefaultBidiLevelRun { false };
+ // Note that this is only needed for the special (and ancient and not supported by other browsers) "-webkit-nbsp-mode: space".
+ bool m_collapseLeadingNonBreakingSpace { false };
};
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp
index e677d0d..6556ef6 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp
@@ -259,7 +259,7 @@
auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
if (auto contentWidth = inlineTextItem.width())
return *contentWidth;
- auto& fontCascade = m_isFirstLine ? inlineTextItem.firstLineStyle().fontCascade() : inlineTextItem.style().fontCascade();
+ auto& fontCascade = isFirstLine() ? inlineTextItem.firstLineStyle().fontCascade() : inlineTextItem.style().fontCascade();
if (!inlineTextItem.isWhitespace() || InlineTextItem::shouldPreserveSpacesAndTabs(inlineTextItem))
return TextUtil::width(inlineTextItem, fontCascade, contentLogicalLeft);
return TextUtil::width(inlineTextItem, fontCascade, inlineTextItem.start(), inlineTextItem.start() + 1, contentLogicalLeft);
@@ -280,7 +280,7 @@
if (inlineItem.isInlineBoxStart()) {
auto logicalWidth = boxGeometry.marginStart() + boxGeometry.borderStart() + boxGeometry.paddingStart().value_or(0);
#if ENABLE(CSS_BOX_DECORATION_BREAK)
- auto& style = m_isFirstLine ? inlineItem.firstLineStyle() : inlineItem.style();
+ auto& style = isFirstLine() ? inlineItem.firstLineStyle() : inlineItem.style();
if (style.boxDecorationBreak() == BoxDecorationBreak::Clone)
logicalWidth += boxGeometry.borderEnd() + boxGeometry.paddingEnd().value_or(0_lu);
#endif
@@ -401,7 +401,7 @@
void LineBuilder::initialize(const UsedConstraints& lineConstraints, size_t leadingInlineItemIndex, const std::optional<PreviousLine>& previousLine)
{
- m_isFirstLine = !previousLine;
+ m_previousLine = previousLine;
m_floats.clear();
m_lineSpanningInlineBoxes.clear();
m_wrapOpportunityList.clear();
@@ -439,7 +439,7 @@
m_lineSpanningInlineBoxes.append({ *spanningInlineBox, InlineItem::Type::InlineBoxStart, bidiLevelForOpaqueInlineItem });
};
createLineSpanningInlineBoxes();
- m_line.initialize(m_lineSpanningInlineBoxes);
+ m_line.initialize(m_lineSpanningInlineBoxes, m_previousLine && !m_previousLine->endsWithLineBreak);
m_lineMarginStart = lineConstraints.marginStart;
m_lineLogicalRect = lineConstraints.logicalRect;
@@ -686,7 +686,7 @@
for (auto index = currentInlineItemIndex; index < softWrapOpportunityIndex; ++index) {
auto& inlineItem = m_inlineItems[index];
auto& style = [&] () -> const RenderStyle& {
- return m_isFirstLine ? inlineItem.firstLineStyle() : inlineItem.style();
+ return isFirstLine() ? inlineItem.firstLineStyle() : inlineItem.style();
}();
if (inlineItem.isFloat()) {
lineCandidate.floatItem = &inlineItem;
@@ -959,7 +959,7 @@
if (inlineTextItem.isWhitespace())
return { };
auto& overflowingRun = candidateRuns.first();
- if (m_isFirstLine) {
+ if (isFirstLine()) {
auto& usedStyle = overflowingRun.style;
auto& style = overflowingRun.inlineItem.style();
if (&usedStyle != &style && usedStyle.fontCascade() != style.fontCascade()) {
@@ -1060,7 +1060,7 @@
ASSERT(!m_wrapOpportunityList.isEmpty());
// We might already have added floats. They shrink the available horizontal space for the line.
// Let's just reuse what the line has at this point.
- m_line.initialize(m_lineSpanningInlineBoxes);
+ m_line.initialize(m_lineSpanningInlineBoxes, m_previousLine && !m_previousLine->endsWithLineBreak);
auto currentItemIndex = layoutRange.start;
if (m_partialLeadingTextItem) {
m_line.append(*m_partialLeadingTextItem, m_partialLeadingTextItem->style(), inlineItemWidth(*m_partialLeadingTextItem, { }));
@@ -1070,7 +1070,7 @@
}
for (; currentItemIndex < layoutRange.end; ++currentItemIndex) {
auto& inlineItem = m_inlineItems[currentItemIndex];
- auto& style = m_isFirstLine ? inlineItem.firstLineStyle() : inlineItem.style();
+ auto& style = isFirstLine() ? inlineItem.firstLineStyle() : inlineItem.style();
m_line.append(inlineItem, style, inlineItemWidth(inlineItem, m_line.contentLogicalRight()));
if (&inlineItem == &lastInlineItemToAdd)
return currentItemIndex - layoutRange.start + 1;
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h
index 7646acd..99d940c 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h
@@ -125,6 +125,8 @@
std::optional<IntrinsicWidthMode> intrinsicWidthMode() const { return m_intrinsicWidthMode; }
bool isInIntrinsicWidthMode() const { return !!intrinsicWidthMode(); }
+ bool isFirstLine() const { return !m_previousLine.has_value(); }
+
const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
InlineFormattingState* formattingState() { return m_inlineFormattingState; }
FloatingState* floatingState() { return m_floatingState; }
@@ -133,7 +135,7 @@
const LayoutState& layoutState() const;
private:
- bool m_isFirstLine { false };
+ std::optional<PreviousLine> m_previousLine { };
std::optional<IntrinsicWidthMode> m_intrinsicWidthMode;
const InlineFormattingContext& m_inlineFormattingContext;
InlineFormattingState* m_inlineFormattingState { nullptr };
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp
index de15dd0..858e8f7 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp
@@ -88,6 +88,14 @@
return !m_length || (m_length == 1 && inlineTextBox().content()[start()] == zeroWidthSpace);
}
+bool InlineTextItem::isCollapsibleNonBreakingSpace() const
+{
+ if (style().nbspMode() != NBSPMode::Space)
+ return false;
+ // Note that this text item may be longer than just one character.
+ return m_length && inlineTextBox().content()[start()] == noBreakSpace;
+}
+
bool InlineTextItem::shouldPreserveSpacesAndTabs(const InlineTextItem& inlineTextItem)
{
ASSERT(inlineTextItem.isWhitespace());
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h b/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h
index 6918457..5c9382f 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h
@@ -50,6 +50,7 @@
bool isWhitespace() const { return m_textItemType == TextItemType::Whitespace; }
bool isWordSeparator() const { return m_isWordSeparator; }
bool isZeroWidthSpaceSeparator() const;
+ bool isCollapsibleNonBreakingSpace() const;
bool hasTrailingSoftHyphen() const { return m_hasTrailingSoftHyphen; }
std::optional<InlineLayoutUnit> width() const { return m_hasWidth ? std::make_optional(m_width) : std::optional<InlineLayoutUnit> { }; }