tor-browser

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

commit ce0042d32d6fad3745d166930aee8df46caf736c
parent dc43a0df23837c073c0559d2d4dbda010549cfbc
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date:   Sat,  1 Nov 2025 10:53:02 +0000

Bug 1948933 - Skip white-space fix ups when removing from a flex/grid container or table pseudo. r=layout-reviewers,dshin

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

Diffstat:
Mlayout/base/nsCSSFrameConstructor.cpp | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp @@ -17,6 +17,7 @@ #include "RubyUtils.h" #include "StickyScrollContainer.h" #include "mozilla/AbsoluteContainingBlock.h" +#include "mozilla/Assertions.h" #include "mozilla/AutoRestore.h" #include "mozilla/ComputedStyleInlines.h" #include "mozilla/DebugOnly.h" @@ -1997,6 +1998,19 @@ static bool IsWrapperPseudo(nsIFrame* aFrame) { return PseudoStyle::IsWrapperAnonBox(pseudoType) || IsTablePseudo(aFrame); } +static bool IsInAnonymousTable(nsIFrame* aFrame) { + for (nsIFrame* f = aFrame; f; f = f->GetParent()) { + if (!IsWrapperPseudo(f)) { + return false; + } + if (f->IsTableWrapperFrame()) { + return true; + } + } + MOZ_ASSERT_UNREACHABLE("Expected to be called inside tables"); + return false; +} + /* static */ nsCSSFrameConstructor::ParentType nsCSSFrameConstructor::GetParentType( LayoutFrameType aFrameType) { @@ -7526,6 +7540,48 @@ bool nsCSSFrameConstructor::ContentWillBeRemoved(nsIContent* aChild, parentFrame = childFrame->GetParent(); } + const bool canSkipWhitespaceFixup = [&] { + if (aKind == RemovalKind::ForReconstruction) { + // If we're just reconstructing frames for the element, then the + // following ContentInserted notification on the element will + // take care of fixing up any adjacent white-space text nodes. + return true; + } + switch (parentFrame->Type()) { + case LayoutFrameType::Table: + case LayoutFrameType::TableRow: + case LayoutFrameType::TableRowGroup: + case LayoutFrameType::TableCol: + case LayoutFrameType::TableColGroup: + case LayoutFrameType::TableWrapper: { + // Tables ignore all whitespace within their wrappers, so we can avoid + // reconstructing adjacent whitespace if the table is not anonymous. + if (!IsInAnonymousTable(parentFrame)) { + return true; + } + // If the table is anonymous and the child is at the edges, we might + // need to create whitespace at the edges of the table that wasn't + // there before, so we can only skip the check if childFrame has frames + // around. Captions are extra-special here, because they're siblings + // with the main table frame, so we can't count that as a relevant + // sibling for our purposes. + auto* prevSibling = childFrame->GetPrevSibling(); + return prevSibling && !prevSibling->IsTableFrame() && + childFrame->GetNextSibling(); + } + case LayoutFrameType::GridContainer: + case LayoutFrameType::FlexContainer: + // Flex and grid containers similarly skip whitespace and wrap + // non-whitespace in anonymous flex items, so any change to + // white-space that could matter would have triggered the + // reconstruction of the container itself due to merging anonymous + // grid / flex items. + return true; + default: + break; + } + return false; + }(); DestroyContext context(mPresShell); RemoveFrame(context, nsLayoutUtils::GetChildListNameFor(childFrame), childFrame); @@ -7546,10 +7602,7 @@ bool nsCSSFrameConstructor::ContentWillBeRemoved(nsIContent* aChild, RecoverLetterFrames(containingBlock); } - // If we're just reconstructing frames for the element, then the - // following ContentInserted notification on the element will - // take care of fixing up any adjacent text nodes. - if (aKind != RemovalKind::ForReconstruction) { + if (!canSkipWhitespaceFixup) { MOZ_ASSERT(aChild->GetParentNode(), "How did we have a sibling without a parent?"); // Adjacent whitespace-only text nodes might have been suppressed if