Bug 1872929 - Don't allow text-wrap:balance adjustment to cause an overflow-wrap line break to be used. r=layout-reviewers,emilio

Differential Revision: https://phabricator.services.mozilla.com/D199974
This commit is contained in:
Jonathan Kew 2024-01-30 18:58:16 +00:00
Родитель 5130fe99a7
Коммит 860d32f808
6 изменённых файлов: 58 добавлений и 24 удалений

Просмотреть файл

@ -1558,8 +1558,9 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
// Do we need to start a `text-wrap: balance` iteration?
if (tryBalance) {
tryBalance = false;
// Don't try to balance an incomplete block.
if (!reflowStatus.IsFullyComplete()) {
// Don't try to balance an incomplete block, or if we had to use an
// overflow-wrap break position in the initial reflow.
if (!reflowStatus.IsFullyComplete() || trialState.mUsedOverflowWrap) {
break;
}
balanceTarget.mOffset =
@ -1596,7 +1597,7 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
// Helper to determine whether the current trial succeeded (i.e. was able
// to fit the content into the expected number of lines).
auto trialSucceeded = [&]() -> bool {
if (!reflowStatus.IsFullyComplete()) {
if (!reflowStatus.IsFullyComplete() || trialState.mUsedOverflowWrap) {
return false;
}
if (balanceTarget.mContent) {
@ -1626,7 +1627,7 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
// If we were attempting to balance, check whether the final iteration was
// successful, and if not, back up by one step.
if (balanceTarget.mOffset >= 0) {
if (trialSucceeded()) {
if (!trialState.mInset || trialSucceeded()) {
break;
}
trialState.ResetForBalance(-1);
@ -1907,7 +1908,7 @@ nsReflowStatus nsBlockFrame::TrialReflow(nsPresContext* aPresContext,
}
// Now reflow...
ReflowDirtyLines(state);
aTrialState.mUsedOverflowWrap = ReflowDirtyLines(state);
// If we have a next-in-flow, and that next-in-flow has pushed floats from
// this frame from a previous iteration of reflow, then we should not return
@ -2832,11 +2833,12 @@ static bool LinesAreEmpty(const nsLineList& aList) {
return true;
}
void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
bool nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
bool keepGoing = true;
bool repositionViews = false; // should we really need this?
bool foundAnyClears = aState.mTrailingClearFromPIF != StyleClear::None;
bool willReflowAgain = false;
bool usedOverflowWrap = false;
#ifdef DEBUG
if (gNoisyReflow) {
@ -3157,7 +3159,7 @@ void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
} else {
// Reflow the dirty line. If it's an incremental reflow, then force
// it to invalidate the dirty area if necessary
ReflowLine(aState, line, &keepGoing);
usedOverflowWrap |= ReflowLine(aState, line, &keepGoing);
}
if (aState.mReflowInput.WillReflowAgainForClearance()) {
@ -3454,7 +3456,7 @@ void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
// line to be created; see SplitLine's callers for examples of
// when this happens).
while (line != LinesEnd()) {
ReflowLine(aState, line, &keepGoing);
usedOverflowWrap |= ReflowLine(aState, line, &keepGoing);
if (aState.mReflowInput.WillReflowAgainForClearance()) {
line->MarkDirty();
@ -3558,6 +3560,8 @@ void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
ToString(aState.mReflowStatus).c_str());
}
#endif
return usedOverflowWrap;
}
void nsBlockFrame::MarkLineDirtyForInterrupt(nsLineBox* aLine) {
@ -3618,8 +3622,9 @@ void nsBlockFrame::DeleteLine(BlockReflowState& aState,
* Reflow a line. The line will either contain a single block frame
* or contain 1 or more inline frames. aKeepReflowGoing indicates
* whether or not the caller should continue to reflow more lines.
* Returns true if the reflow used an overflow-wrap breakpoint.
*/
void nsBlockFrame::ReflowLine(BlockReflowState& aState, LineIterator aLine,
bool nsBlockFrame::ReflowLine(BlockReflowState& aState, LineIterator aLine,
bool* aKeepReflowGoing) {
MOZ_ASSERT(aLine->GetChildCount(), "reflowing empty line");
@ -3639,15 +3644,16 @@ void nsBlockFrame::ReflowLine(BlockReflowState& aState, LineIterator aLine,
nsIFrame* firstChild = aLine->mFirstChild;
if (firstChild->IsHiddenByContentVisibilityOfInFlowParentForLayout() &&
!HasAnyStateBits(NS_FRAME_OWNS_ANON_BOXES)) {
return;
return false;
}
// Now that we know what kind of line we have, reflow it
bool usedOverflowWrap = false;
if (aLine->IsBlock()) {
ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
} else {
aLine->SetLineWrapped(false);
ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
usedOverflowWrap = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// Store the line's float edges for overflow marker analysis if needed.
aLine->ClearFloatEdges();
@ -3670,6 +3676,8 @@ void nsBlockFrame::ReflowLine(BlockReflowState& aState, LineIterator aLine,
}
aLine->ClearMovedFragments();
return usedOverflowWrap;
}
nsIFrame* nsBlockFrame::PullFrame(BlockReflowState& aState,
@ -4635,10 +4643,12 @@ void nsBlockFrame::ReflowBlockFrame(BlockReflowState& aState,
#endif
}
void nsBlockFrame::ReflowInlineFrames(BlockReflowState& aState,
// Returns true if an overflow-wrap break was used.
bool nsBlockFrame::ReflowInlineFrames(BlockReflowState& aState,
LineIterator aLine,
bool* aKeepReflowGoing) {
*aKeepReflowGoing = true;
bool usedOverflowWrap = false;
aLine->SetLineIsImpactedByFloat(false);
@ -4678,7 +4688,7 @@ void nsBlockFrame::ReflowInlineFrames(BlockReflowState& aState,
DoReflowInlineFrames(aState, lineLayout, aLine, floatAvailableSpace,
availableSpaceBSize, &floatManagerState,
aKeepReflowGoing, &lineReflowStatus, allowPullUp);
lineLayout.EndLineReflow();
usedOverflowWrap = lineLayout.EndLineReflow();
if (LineReflowStatus::RedoNoPull == lineReflowStatus ||
LineReflowStatus::RedoMoreFloats == lineReflowStatus ||
@ -4707,6 +4717,8 @@ void nsBlockFrame::ReflowInlineFrames(BlockReflowState& aState,
} while (LineReflowStatus::RedoNoPull == lineReflowStatus);
} while (LineReflowStatus::RedoMoreFloats == lineReflowStatus);
} while (LineReflowStatus::RedoNextBand == lineReflowStatus);
return usedOverflowWrap;
}
void nsBlockFrame::SetBreakBeforeStatusBeforeLine(BlockReflowState& aState,

Просмотреть файл

@ -552,6 +552,8 @@ class nsBlockFrame : public nsContainerFrame {
const nscoord mConsumedBSize;
const nscoord mEffectiveContentBoxBSize;
bool mNeedFloatManager;
// [out] Whether reflowing resulted in use of an overflow-wrap break.
bool mUsedOverflowWrap = false;
// Settings for the current trial.
bool mBalancing = false;
nscoord mInset = 0;
@ -581,6 +583,7 @@ class nsBlockFrame : public nsContainerFrame {
mFcBounds.Clear();
mBlockEndEdgeOfChildren = 0;
mContainerWidth = 0;
mUsedOverflowWrap = false;
}
};
@ -736,8 +739,11 @@ class nsBlockFrame : public nsContainerFrame {
*/
void PrepareResizeReflow(BlockReflowState& aState);
/** reflow all lines that have been marked dirty */
void ReflowDirtyLines(BlockReflowState& aState);
/**
* Reflow all lines that have been marked dirty.
* Returns whether an overflow-wrap break was used anywhere.
*/
bool ReflowDirtyLines(BlockReflowState& aState);
/** Mark a given line dirty due to reflow being interrupted on or before it */
void MarkLineDirtyForInterrupt(nsLineBox* aLine);
@ -754,8 +760,10 @@ class nsBlockFrame : public nsContainerFrame {
* more inline frames.
* @param aKeepReflowGoing [OUT]
* indicates whether the caller should continue to reflow more lines
* @returns
* whether an overflow-wrap breakpoint was used
*/
void ReflowLine(BlockReflowState& aState, LineIterator aLine,
bool ReflowLine(BlockReflowState& aState, LineIterator aLine,
bool* aKeepReflowGoing);
// Return false if it needs another reflow because of reduced space
@ -798,7 +806,8 @@ class nsBlockFrame : public nsContainerFrame {
void ReflowBlockFrame(BlockReflowState& aState, LineIterator aLine,
bool* aKeepGoing);
void ReflowInlineFrames(BlockReflowState& aState, LineIterator aLine,
// Returns whether an overflow-wrap break was used.
bool ReflowInlineFrames(BlockReflowState& aState, LineIterator aLine,
bool* aKeepLineGoing);
void DoReflowInlineFrames(

Просмотреть файл

@ -78,7 +78,8 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
mDirtyNextLine(false),
mLineAtStart(false),
mHasRuby(false),
mSuppressLineWrap(LineContainerFrame()->IsInSVGTextSubtree())
mSuppressLineWrap(LineContainerFrame()->IsInSVGTextSubtree()),
mUsedOverflowWrap(false)
#ifdef DEBUG
,
mSpansAllocated(0),
@ -195,8 +196,8 @@ void nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
psd->mICoord = aICoord;
psd->mIEnd = aICoord + aISize;
// Set up inset to be used for text-wrap:balance implementation, but only if
// the available size is at least 2*inset.
psd->mInset = aISize < aInset * 2 ? 0 : aInset;
// the available size is greater than inset.
psd->mInset = aISize > aInset ? aInset : 0;
mContainerSize = aContainerSize;
mBStartEdge = aBCoord;
@ -251,7 +252,7 @@ void nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
}
}
void nsLineLayout::EndLineReflow() {
bool nsLineLayout::EndLineReflow() {
#ifdef NOISY_REFLOW
LineContainerFrame()->ListTag(stdout);
printf(": EndLineReflow: width=%d\n",
@ -282,6 +283,8 @@ void nsLineLayout::EndLineReflow() {
maxFramesAllocated = mFramesAllocated;
}
#endif
return mUsedOverflowWrap;
}
// XXX swtich to a single mAvailLineWidth that we adjust as each frame

Просмотреть файл

@ -53,7 +53,10 @@ class nsLineLayout {
// the effective available space on the line.
nscoord aInset = 0);
void EndLineReflow();
/**
* Returns true if the line had to use an overflow-wrap break position.
*/
bool EndLineReflow();
/**
* Called when a float has been placed. This method updates the
@ -330,6 +333,11 @@ class nsLineLayout {
void SetSuppressLineWrap(bool aEnabled) { mSuppressLineWrap = aEnabled; }
/**
* Record that the line had to resort to an overflow-wrap break.
*/
void SetUsedOverflowWrap() { mUsedOverflowWrap = true; }
protected:
// This state is constant for a given block frame doing line layout
@ -585,6 +593,7 @@ class nsLineLayout {
bool mLineAtStart : 1;
bool mHasRuby : 1;
bool mSuppressLineWrap : 1;
bool mUsedOverflowWrap : 1;
int32_t mSpanDepth;
#ifdef DEBUG

Просмотреть файл

@ -9842,6 +9842,9 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
aLineLayout.SetFirstLetterStyleOK(false);
aStatus.SetFirstLetterComplete();
}
if (breakPriority == gfxBreakPriority::eWordWrapBreak) {
aLineLayout.SetUsedOverflowWrap();
}
// Updated the cached NewlineProperty, or delete it.
if (contentLength < maxContentLength &&

Просмотреть файл

@ -1,2 +0,0 @@
[text-wrap-balance-overflow-001.html]
expected: FAIL