tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a5535c43d6a821e4ad20d53bc6077694a8a85f89
parent f2c2d7b9553a9311873aa8a9c476c2bdc870a0a8
Author: Emily McDonough <emcdonough@mozilla.com>
Date:   Fri, 24 Oct 2025 22:15:16 +0000

Bug 1993939 Part 2 - Fix text-decoration-trim on line breaks when the nsTextFrame is not inside inline frames. r=layout-reviewers,layout-jp-market-reviewers,jfkthame

There are two issues that occurred in this situation. First, because every
nsTextFrame had the same, single decorating frame (nsBlockFrame), the check
for continuations would not work before.
Second, because the geometric comparison worked on the decorating frame, which
might be a block frame with many lines, the check for being at the start of
the line would succeed for every line (which combined with the issue with
continuation checking, would apply trim to the start of every line).
This also caused the check for the end of the line to sporadically work or not
for every single line.

This fixes the continuation check to work for the case of a single block frame
containing continuing text frames, and geometrically tests against the lines
of block frames instead of the block frame itself.

Differential Revision: https://phabricator.services.mozilla.com/D268964

Diffstat:
Mlayout/generic/nsTextFrame.cpp | 43++++++++++++++++++++++++++++++++++---------
1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp @@ -5786,7 +5786,7 @@ static gfxFloat ComputeDecorationLineOffset( // Helper to determine decoration trim offset. // Returns false if the trim would cut off the decoration entirely. static bool ComputeDecorationTrim( - const nsTextFrame* aFrame, const nsPresContext* aPresCtx, + nsTextFrame* aFrame, const nsPresContext* aPresCtx, const nsIFrame* aDecFrame, const gfxFont::Metrics& aMetrics, nsCSSRendering::DecorationRectParams& aParams) { const gfxFloat app = aPresCtx->AppUnitsPerDevPixel(); @@ -5826,34 +5826,59 @@ static bool ComputeDecorationTrim( if (wm.IsInlineReversed()) { std::swap(trimLeft, trimRight); } - const nsPoint offset = aFrame->GetOffsetTo(aDecFrame); - const nsSize decSize = aDecFrame->GetSize(); + + nsPoint offset; + nsSize containingSize; const nsSize size = aFrame->GetSize(); + // If the decorating frame is an inline frame, we can use it as the + // reference frame for measurements. + // If the decorating frame is not inline, then we will need to consider + // text indentation and calculate geometry using line boxes. + if (aDecFrame->IsInlineFrame()) { + offset = aFrame->GetOffsetTo(aDecFrame); + containingSize = aDecFrame->GetSize(); + } else { + nsIFrame* const lineContainer = FindLineContainer(aFrame); + nsILineIterator* const iter = lineContainer->GetLineIterator(); + const nsILineIterator::LineInfo lineInfo = + iter->GetLine(GetFrameLineNum(aFrame, iter)).unwrap(); + + offset = aFrame->GetOffsetTo(lineContainer); + offset -= lineInfo.mLineBounds.TopLeft(); + containingSize = lineInfo.mLineBounds.Size(); + } + nscoord start, end, max; if (verticalDec) { start = offset.y; max = size.height; - end = decSize.height - (size.height + offset.y); + end = containingSize.height - (size.height + offset.y); } else { start = offset.x; max = size.width; - end = decSize.width - (size.width + offset.x); + end = containingSize.width - (size.width + offset.x); } const bool cloneDecBreak = aDecFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone; // TODO alaskanemily: This will not correctly account for the case that the // continuations are bidi continuations. - bool applyLeft = cloneDecBreak || !aDecFrame->GetPrevContinuation(); - bool applyRight = cloneDecBreak || !aDecFrame->GetNextContinuation(); + bool applyLeft = cloneDecBreak || (!aFrame->GetPrevContinuation() && + !aDecFrame->GetPrevContinuation()); + bool applyRight = cloneDecBreak || (!aFrame->GetNextContinuation() && + !aDecFrame->GetNextContinuation()); if (wm.IsInlineReversed()) { std::swap(applyLeft, applyRight); } if (applyLeft) { trimLeft -= NSAppUnitsToDoublePixels(start, app); + } else { + trimLeft = 0; } if (applyRight) { trimRight -= NSAppUnitsToDoublePixels(end, app); + } else { + trimRight = 0; } if (trimLeft >= NSAppUnitsToDoublePixels(max, app) - trimRight) { @@ -5871,10 +5896,10 @@ static bool ComputeDecorationTrim( // I am unsure if it's possible that the first/last frame might be inset // for some reason, as well, in which case we will not draw the outset // decorations. - if (applyLeft && (trimLeft > 0.0 || start == 0)) { + if (trimLeft > 0.0 || start == 0) { aParams.trimLeft = trimLeft; } - if (applyRight && (trimRight > 0.0 || end == 0)) { + if (trimRight > 0.0 || end == 0) { aParams.trimRight = trimRight; } return true;