Bug 1665657 - Whitespace that will hang should not contribute to the min inline-size of a textframe. r=emilio

This affects a few of the examples in the text/white-space-2 reftest, but the changes look sensible;
more significantly from an interop point of view, there are specific web-platform reftests that are
currently failing, but will pass after the patch.

Differential Revision: https://phabricator.services.mozilla.com/D95811
This commit is contained in:
Jonathan Kew 2020-11-04 13:31:30 +00:00
parent 810bc229cc
commit 0e3cf9687e
8 changed files with 34 additions and 28 deletions

View File

@ -801,12 +801,13 @@ static bool IsTrimmableSpace(char aCh) {
}
static bool IsTrimmableSpace(const nsTextFragment* aFrag, uint32_t aPos,
const nsStyleText* aStyleText) {
const nsStyleText* aStyleText,
bool aAllowHangingWS = false) {
NS_ASSERTION(aPos < aFrag->GetLength(), "No text for IsSpace!");
switch (aFrag->CharAt(aPos)) {
case ' ':
return !aStyleText->WhiteSpaceIsSignificant() &&
return (!aStyleText->WhiteSpaceIsSignificant() || aAllowHangingWS) &&
!IsSpaceCombiningSequenceTail(aFrag, aPos + 1);
case '\n':
return !aStyleText->NewlineIsSignificantStyle() &&
@ -814,7 +815,7 @@ static bool IsTrimmableSpace(const nsTextFragment* aFrag, uint32_t aPos,
case '\t':
case '\r':
case '\f':
return !aStyleText->WhiteSpaceIsSignificant();
return !aStyleText->WhiteSpaceIsSignificant() || aAllowHangingWS;
default:
return false;
}
@ -3049,11 +3050,13 @@ gfxSkipCharsIterator nsTextFrame::EnsureTextRun(
static uint32_t GetEndOfTrimmedText(const nsTextFragment* aFrag,
const nsStyleText* aStyleText,
uint32_t aStart, uint32_t aEnd,
gfxSkipCharsIterator* aIterator) {
gfxSkipCharsIterator* aIterator,
bool aAllowHangingWS = false) {
aIterator->SetSkippedOffset(aEnd);
while (aIterator->GetSkippedOffset() > aStart) {
aIterator->AdvanceSkipped(-1);
if (!IsTrimmableSpace(aFrag, aIterator->GetOriginalOffset(), aStyleText))
if (!IsTrimmableSpace(aFrag, aIterator->GetOriginalOffset(), aStyleText,
aAllowHangingWS))
return aIterator->GetSkippedOffset() + 1;
}
return aStart;
@ -8348,6 +8351,7 @@ void nsTextFrame::AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
bool collapseWhitespace = !textStyle->WhiteSpaceIsSignificant();
bool preformatNewlines = textStyle->NewlineIsSignificant(this);
bool preformatTabs = textStyle->WhiteSpaceIsSignificant();
bool whitespaceCanHang = textStyle->WhiteSpaceCanHangOrVisuallyCollapse();
gfxFloat tabWidth = -1;
uint32_t start = FindStartAfterSkippingWhitespace(&provider, aData, textStyle,
&iter, flowEndInTextRun);
@ -8408,9 +8412,9 @@ void nsTextFrame::AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
aData->mCurrentLine = NSCoordSaturatingAdd(aData->mCurrentLine, width);
aData->mAtStartOfLine = false;
if (collapseWhitespace) {
if (collapseWhitespace || whitespaceCanHang) {
uint32_t trimStart =
GetEndOfTrimmedText(frag, textStyle, wordStart, i, &iter);
GetEndOfTrimmedText(frag, textStyle, wordStart, i, &iter, whitespaceCanHang);
if (trimStart == start) {
// This is *all* trimmable whitespace, so whatever trailingWhitespace
// we saw previously is still trailing...
@ -9275,9 +9279,7 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
bool isBreakSpaces = textStyle->mWhiteSpace == StyleWhiteSpace::BreakSpaces;
// allow whitespace to overflow the container
bool whitespaceCanHang = !isBreakSpaces &&
textStyle->WhiteSpaceCanWrapStyle() &&
textStyle->WhiteSpaceIsSignificant();
bool whitespaceCanHang = textStyle->WhiteSpaceCanHangOrVisuallyCollapse();
gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority();
gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak;
bool shouldSuppressLineBreak = ShouldSuppressLineBreak();

View File

@ -3,11 +3,14 @@
<head>
<!-- Reference -->
<style>
div { border:1px solid black; }
div { font:16px sans-serif; border:1px solid black; }
.container { float:left; width:20%; border-color:cyan; }
p { width:0; }
b { font-weight:normal; background-color:yellow; white-space:pre; }
.cell { display:table-cell; border:1px solid green; }
.hang { display:inline-block; width:0; overflow:visible; }
.hang span { display:inline; background-color:yellow; }
.clip { overflow: hidden; }
</style>
</head>
<body>
@ -17,7 +20,7 @@ b { font-weight:normal; background-color:yellow; white-space:pre; }
Kitty</b></span>
<p><span class="cell"><b>Hello Kitty</b></span>
<p><span class="cell"><b>Hello Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello
Kitty</b></span>
</div>
@ -28,7 +31,7 @@ Kitty</b></span>
Kitty</b></span>
<p><span class="cell"><b>Hello
Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello
Kitty</b></span>
</div>
@ -37,7 +40,7 @@ Kitty</b></span>
Kitty</b></span>
<p><span class="cell"><b>Hello Kitty</b></span>
<p><span class="cell"><b>Hello Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell clip"><b>Hello<span class="hang"><span> </span></span>
Kitty</b></span>
</div>
@ -46,18 +49,18 @@ Kitty</b></span>
Kitty</b></span>
<p><span class="cell"><b>Hello Kitty</b></span>
<p><span class="cell"><b>Hello Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello
Kitty</b></span>
</div>
<div class="container">
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello<span class="hang"><span> </span></span>
Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello
Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello<span class="hang"><span> </span></span>
Kitty</b></span>
<p><span class="cell"><b>Hello
<p><span class="cell"><b>Hello
Kitty</b></span>
</div>

View File

@ -3,7 +3,7 @@
<head>
<!-- Wrapping tests in table-cell to test min-width computation -->
<style>
div { border:1px solid black; }
div { font:16px sans-serif; border:1px solid black; }
.container { float:left; width:20%; border-color:cyan; }
p { width:0; }
b { font-weight:normal; background-color:yellow; }

View File

@ -963,6 +963,15 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace;
}
bool WhiteSpaceCanHangOrVisuallyCollapse() const {
// This was originally expressed in nsTextFrame in terms of:
// mWhiteSpace != StyleWhiteSpace::BreakSpaces &&
// WhiteSpaceCanWrapStyle() &&
// WhiteSpaceIsSignificant()
// which simplifies to:
return mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap;
}
bool NewlineIsSignificantStyle() const {
return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||

View File

@ -1,2 +0,0 @@
[white-space-intrinsic-size-003.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[white-space-intrinsic-size-013.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[white-space-intrinsic-size-014.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[white-space-pre-wrap-trailing-spaces-003.html]
expected: FAIL