Bug 1253840 - patch 2 - When justifying, the full advance of any trimmable end-of-line whitespace needs to be hung into the margin. r=emilio

Depends on D178210

Differential Revision: https://phabricator.services.mozilla.com/D178211
This commit is contained in:
Jonathan Kew
2023-05-19 16:44:10 +00:00
parent 882f96a421
commit 39322ae348
6 changed files with 165 additions and 47 deletions

View File

@@ -3046,7 +3046,8 @@ void nsLineLayout::ExpandInlineRubyBoxes(PerSpanData* aSpan) {
}
}
nscoord nsLineLayout::GetHangFrom(const PerSpanData* aSpan, bool aLineIsRTL) {
nscoord nsLineLayout::GetHangFrom(const PerSpanData* aSpan,
bool aLineIsRTL) const {
const PerFrameData* pfd = aSpan->mLastFrame;
nscoord result = 0;
while (pfd) {
@@ -3079,6 +3080,36 @@ nscoord nsLineLayout::GetHangFrom(const PerSpanData* aSpan, bool aLineIsRTL) {
return result;
}
gfxTextRun::TrimmableWS nsLineLayout::GetTrimFrom(const PerSpanData* aSpan,
bool aLineIsRTL) const {
const PerFrameData* pfd = aSpan->mLastFrame;
while (pfd) {
if (const PerSpanData* childSpan = pfd->mSpan) {
return GetTrimFrom(childSpan, aLineIsRTL);
}
if (pfd->mIsTextFrame) {
auto* lastText = static_cast<nsTextFrame*>(pfd->mFrame);
auto result = lastText->GetTrimmableWS();
if (result.mAdvance) {
lastText->EnsureTextRun(nsTextFrame::eInflated);
auto* textRun = lastText->GetTextRun(nsTextFrame::eInflated);
if (textRun && textRun->IsRightToLeft() != aLineIsRTL) {
result.mAdvance = -result.mAdvance;
}
}
return result;
}
if (!pfd->mSkipWhenTrimmingWhitespace) {
// If we hit a frame on the end that's not text and not a placeholder or
// <br>, then there is no trailing whitespace to trim. Stop the search.
return gfxTextRun::TrimmableWS{};
}
// Scan back for a preceding frame whose whitespace we can trim.
pfd = pfd->mPrev;
}
return gfxTextRun::TrimmableWS{};
}
// Align inline frames within the line according to the CSS text-align
// property.
void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
@@ -3106,8 +3137,15 @@ void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
// Check if there's trailing whitespace we need to "hang" at line-wrap.
nscoord hang = 0;
uint32_t trimCount = 0;
if (aLine->IsLineWrapped()) {
hang = GetHangFrom(mRootSpan, lineWM.IsBidiRTL());
if (textAlign == StyleTextAlign::Justify) {
auto trim = GetTrimFrom(mRootSpan, lineWM.IsBidiRTL());
hang = NSToCoordRound(trim.mAdvance);
trimCount = trim.mCount;
} else {
hang = GetHangFrom(mRootSpan, lineWM.IsBidiRTL());
}
}
bool isSVG = LineContainerFrame()->IsInSVGTextSubtree();
@@ -3144,9 +3182,11 @@ void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
switch (textAlign) {
case StyleTextAlign::Justify: {
int32_t opportunities =
psd->mFrame->mJustificationInfo.mInnerOpportunities;
psd->mFrame->mJustificationInfo.mInnerOpportunities -
(hang ? trimCount : 0);
if (opportunities > 0) {
int32_t gaps = opportunities * 2 + additionalGaps;
remainingISize += std::abs(hang);
JustificationApplicationState applyState(gaps, remainingISize);
// Apply the justification, and make sure to update our linebox
@@ -3154,6 +3194,15 @@ void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
aLine->ExpandBy(ApplyFrameJustification(psd, applyState),
ContainerSizeForSpan(psd));
// If the trimmable trailing whitespace that we want to hang had
// reverse-inline directionality, adjust line position to account for
// it being at the inline-start side.
// On top of the original "hang" amount, justification will have
// modified its width, so we include that adjustment here.
if (hang < 0) {
dx = hang - trimCount * remainingISize / opportunities;
}
MOZ_ASSERT(applyState.mGaps.mHandled == applyState.mGaps.mCount,
"Unprocessed justification gaps");
NS_ASSERTION(