Bug 1931466: Ensure inline elements in an empty linebox as having zero BSize and no baseline. r=layout-reviewers,dholbert,jfkthame

Differential Revision: https://phabricator.services.mozilla.com/D229191
This commit is contained in:
David Shin 2024-11-19 19:39:21 +00:00
parent 8f4f441cae
commit 429486d08f
17 changed files with 169 additions and 33 deletions

View File

@ -4990,7 +4990,10 @@ void nsBlockFrame::DoReflowInlineFrames(
aLineLayout.BeginLineReflow(
iStart, aState.mBCoord, availISize, availBSize,
aFloatAvailableSpace.HasFloats(), false, /*XXX isTopOfPage*/
aFloatAvailableSpace.HasFloats(), false /*XXX isTopOfPage*/,
HasOutsideMarker() || Style()->IsAnonBox()
? CollapseEmptyInlineFramesInLine::Preserve
: CollapseEmptyInlineFramesInLine::Collapse,
lineWM, aState.mContainerSize, aState.mInsetForBalance);
aState.mFlags.mIsLineLayoutEmpty = false;

View File

@ -222,9 +222,11 @@ void nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
ReflowInput rs(aPresContext, aReflowInput, kid, kidAvailSize);
nsLineLayout ll(aPresContext, nullptr, aReflowInput, nullptr, nullptr);
// This frame does not get constructed for an empty inline frame, so
// `CollapseEmptyInlineFramesInLine` should not matter.
ll.BeginLineReflow(
bp.IStart(wm), bp.BStart(wm), availSize.ISize(wm), NS_UNCONSTRAINEDSIZE,
false, true, kidWritingMode,
false, true, CollapseEmptyInlineFramesInLine::Collapse, kidWritingMode,
nsSize(aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
rs.mLineLayout = ≪
ll.SetInFirstLetter(true);

View File

@ -850,6 +850,8 @@ Maybe<nscoord> nsInlineFrame::GetNaturalBaselineBOffset(
if (aBaselineGroup == BaselineSharingGroup::Last) {
return Nothing{};
}
// TODO(dshin): Some functions seem to rely on this returning
// NS_INTRINSIC_ISIZE_UNKNOWN. e.g. /css/css-pseudo/target-text-008.html
return Some(mBaseline);
}

View File

@ -91,12 +91,11 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
}
}
void nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
nscoord aISize, nscoord aBSize,
bool aImpactedByFloats, bool aIsTopOfPage,
WritingMode aWritingMode,
const nsSize& aContainerSize,
nscoord aInset) {
void nsLineLayout::BeginLineReflow(
nscoord aICoord, nscoord aBCoord, nscoord aISize, nscoord aBSize,
bool aImpactedByFloats, bool aIsTopOfPage,
CollapseEmptyInlineFramesInLine aCollapseEmptyInlineFramesInLine,
WritingMode aWritingMode, const nsSize& aContainerSize, nscoord aInset) {
MOZ_ASSERT(nullptr == mRootSpan, "bad linelayout user");
LAYOUT_WARN_IF_FALSE(aISize != NS_UNCONSTRAINEDSIZE,
"have unconstrained width; this should only result from "
@ -149,6 +148,9 @@ void nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
psd->mIStart = aICoord;
psd->mICoord = aICoord;
psd->mIEnd = aICoord + aISize;
psd->mDoCollapseEmptyInlineFramesInLine =
aCollapseEmptyInlineFramesInLine ==
CollapseEmptyInlineFramesInLine::Collapse;
// Set up inset to be used for text-wrap:balance implementation, but only if
// the available size is greater than inset.
psd->mInset = aISize > aInset ? aInset : 0;
@ -354,6 +356,7 @@ nsLineLayout::PerSpanData* nsLineLayout::NewPerSpanData() {
psd->mContainsFloat = false;
psd->mHasNonemptyContent = false;
psd->mBaseline = nullptr;
psd->mDoCollapseEmptyInlineFramesInLine = false;
#ifdef DEBUG
outerLineLayout->mSpansAllocated++;
@ -1490,6 +1493,34 @@ void nsLineLayout::VerticalAlignLine() {
// this operation is set to zero so that the y coordinates for all
// of the placed children will be relative to there.
PerSpanData* psd = mRootSpan;
if (mLineIsEmpty && psd->mDoCollapseEmptyInlineFramesInLine) {
// This line is empty, and should be consisting of only inline elements.
// (inline-block elements would make the line non-empty).
WritingMode lineWM = psd->mWritingMode;
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
// Ideally, if the frame would collapse itself - but it depends on
// knowing that the line is empty.
if (!pfd->mFrame->IsInlineFrame() && !pfd->mFrame->IsRubyFrame()) {
continue;
}
// Collapse the physical size to 0.
pfd->mBounds.BStart(lineWM) = mBStartEdge;
pfd->mBounds.BSize(lineWM) = 0;
// Initialize mBlockDirAlign (though it doesn't make much difference
// because we don't align empty boxes).
pfd->mBlockDirAlign = VALIGN_OTHER;
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerSize());
}
mFinalLineBSize = 0;
if (mGotLineBox) {
mLineBox->SetBounds(psd->mWritingMode, psd->mIStart, mBStartEdge,
psd->mICoord - psd->mIStart, 0, ContainerSize());
mLineBox->SetLogicalAscent(0);
}
return;
}
VerticalAlignFrames(psd);
// *** Note that comments here still use the anachronistic term

View File

@ -20,6 +20,18 @@
class nsFloatManager;
struct nsStyleText;
/**
* Flag indicating if inline frames within a line should be collapsed
* to zero block-size if all frames within it are empty.
* Declared as typed enum for clearer semantics in function calls, though
* it is reflected as a boolean in
* PerSpanData::mDoCollapseEmptyInlineFramesInLine.
*/
enum class CollapseEmptyInlineFramesInLine {
Preserve,
Collapse,
};
class nsLineLayout {
using BlockReflowState = mozilla::BlockReflowState;
using ReflowInput = mozilla::ReflowInput;
@ -49,13 +61,14 @@ class nsLineLayout {
int32_t GetLineNumber() const { return mLineNumber; }
void BeginLineReflow(nscoord aICoord, nscoord aBCoord, nscoord aISize,
nscoord aBSize, bool aImpactedByFloats,
bool aIsTopOfPage, mozilla::WritingMode aWritingMode,
const nsSize& aContainerSize,
// aInset is used during text-wrap:balance to reduce
// the effective available space on the line.
nscoord aInset = 0);
void BeginLineReflow(
nscoord aICoord, nscoord aBCoord, nscoord aISize, nscoord aBSize,
bool aImpactedByFloats, bool aIsTopOfPage,
CollapseEmptyInlineFramesInLine aCollapseEmptyInlineFramesInLine,
mozilla::WritingMode aWritingMode, const nsSize& aContainerSize,
// aInset is used during text-wrap:balance to reduce
// the effective available space on the line.
nscoord aInset = 0);
/**
* Returns true if the line had to use an overflow-wrap break position.
@ -497,6 +510,7 @@ class nsLineLayout {
mozilla::WritingMode mWritingMode;
bool mContainsFloat;
bool mHasNonemptyContent;
bool mDoCollapseEmptyInlineFramesInLine;
nscoord mIStart;
nscoord mICoord;

View File

@ -341,9 +341,9 @@ void nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
// If the writing mode is vertical-rl, the horizontal position of
// rt frames will be updated when reflowing this text container,
// hence leave container size 0 here for now.
lineLayout->BeginLineReflow(0, 0, reflowInput->ComputedISize(),
NS_UNCONSTRAINEDSIZE, false, false, reflowWM,
nsSize(0, 0));
lineLayout->BeginLineReflow(
0, 0, reflowInput->ComputedISize(), NS_UNCONSTRAINEDSIZE, false, false,
CollapseEmptyInlineFramesInLine::Collapse, reflowWM, nsSize(0, 0));
lineLayout->AttachRootFrameToBaseLineLayout();
}

View File

@ -10,7 +10,7 @@ div {
background: green;
}
</style>
<div><span></span></div>
<div><span>&nbsp;</span></div>
<script>
let $div = document.querySelector('div');
let $span = document.querySelector('span');

View File

@ -10,7 +10,7 @@ div {
background: green;
}
</style>
<div><span></span></div>
<div><span>&nbsp;</span></div>
<script>
let $div = document.querySelector('div');
let $span = document.querySelector('span');

View File

@ -2,5 +2,3 @@
max-asserts: 3
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Blob URL fragment is implemented.]
expected: FAIL

View File

@ -1,2 +0,0 @@
[abspos-inline-008.xht]
expected: FAIL

View File

@ -1,2 +0,0 @@
[toogle-abspos-on-relpos-inline-child.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[out-of-flow-in-multicolumn-116.html]
expected: FAIL

View File

@ -1,5 +0,0 @@
[position-absolute-in-inline-001.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[absolute inside inline container location should be correct.]
expected: FAIL

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<link rel="help" href="https://drafts.csswg.org/css-inline-3/#invisible-line-boxes">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1931466">
<style>
.container {
border: 1px solid;
}
ul {
margin: 0;
}
.button {
box-sizing: border-box;
border-left: 1px solid;
width: 1px;
height: 11px;
display: inline-block;
vertical-align: top;
}
</style>
<div class="container"></div><br>
<div class="container"><span style="border: 1px solid; border-right: 2px solid;"></span></div><br>
<div class="container"><ul><li>&nbsp;</li><li>&nbsp;</li></ul></div><br>
<div class="container"><div class="button"></div><span>&nbsp;</span></div><br>

View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<link rel="help" href="https://drafts.csswg.org/css-inline-3/#invisible-line-boxes">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1931466">
<link rel="match" href="empty-span-size-001-ref.html">
<style>
.container, .has-height {
border: 1px solid;
}
.inline {
outline: 1px solid;
}
input {
outline: 1px solid;
background: transparent;
padding: 0;
border: 0;
line-height: 10px;
vertical-align: top;
}
ul {
margin: 0;
}
li {
width: 0;
}
</style>
<!-- Empty inline element in empty line has a height of zero. -->
<div class="container"><span class="inline"></span></div><br>
<!-- ... But not if the line has a meaningful height. -->
<div class="container"><span class="inline"></span><span class="has-height"></span><span class="inline"></span></div><br>
<!-- ... Or if the line is present in some kind of context that gives a meaningful height. -->
<div class="container"><ul><li></li><li></li></ul></div><br>
<div class="container"><input type="button" value=""></div><br>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<link rel="help" href="https://drafts.csswg.org/css-inline-3/#invisible-line-boxes">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1931466">
<style>
.container {
border: 1px solid;
}
ul {
margin: 0;
}
</style>
<div class="container"></div><br>
<div class="container"><span style="border: 1px solid; border-right: 2px solid;"></span></div><br>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<link rel="help" href="https://drafts.csswg.org/css-inline-3/#invisible-line-boxes">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1931466">
<link rel="match" href="empty-span-size-002-ref.html">
<style>
.container, .has-height {
border: 1px solid;
}
.inline {
outline: 1px solid;
}
</style>
<!-- Empty inline element in empty line has a height of zero. -->
<div class="container"><ruby class="inline"></ruby></div><br>
<!-- ... But not if the line has a meaningful height. -->
<div class="container"><ruby class="inline"></ruby><ruby class="has-height"></ruby><ruby class="inline"></ruby></div><br>