@@ -134,19 +134,7 @@ void RestyleManager::ContentAppended(nsIContent* aFirstNewContent) {
134
134
}
135
135
136
136
if (selectorFlags & NodeSelectorFlags::HasSlowSelector) {
137
- if (container->IsElement ()) {
138
- auto * containerElement = container->AsElement ();
139
- PostRestyleEvent (containerElement, RestyleHint::RestyleSubtree (),
140
- nsChangeHint (0 ));
141
- if (selectorFlags & NodeSelectorFlags::HasSlowSelectorNthAll) {
142
- StyleSet ()->MaybeInvalidateRelativeSelectorForNthDependencyFromSibling (
143
- containerElement->GetFirstElementChild (),
144
- /* aForceRestyleSiblings = */ false );
145
- }
146
- } else {
147
- RestylePreviousSiblings (aFirstNewContent);
148
- RestyleSiblingsStartingWith (aFirstNewContent);
149
- }
137
+ RestyleWholeContainer (container, selectorFlags);
150
138
// Restyling the container is the most we can do here, so we're done.
151
139
return ;
152
140
}
@@ -185,6 +173,24 @@ void RestyleManager::RestyleSiblingsStartingWith(nsIContent* aStartingSibling) {
185
173
}
186
174
}
187
175
176
+ void RestyleManager::RestyleWholeContainer (nsINode* aContainer,
177
+ NodeSelectorFlags aSelectorFlags) {
178
+ if (!mRestyledAsWholeContainer .EnsureInserted (aContainer)) {
179
+ return ;
180
+ }
181
+ if (auto * containerElement = Element::FromNode (aContainer)) {
182
+ PostRestyleEvent (containerElement, RestyleHint::RestyleSubtree (),
183
+ nsChangeHint (0 ));
184
+ if (aSelectorFlags & NodeSelectorFlags::HasSlowSelectorNthAll) {
185
+ StyleSet ()->MaybeInvalidateRelativeSelectorForNthDependencyFromSibling (
186
+ containerElement->GetFirstElementChild (),
187
+ /* aForceRestyleSiblings = */ false );
188
+ }
189
+ } else {
190
+ RestyleSiblingsStartingWith (aContainer->GetFirstChild ());
191
+ }
192
+ }
193
+
188
194
void RestyleManager::RestyleForEmptyChange (Element* aContainer) {
189
195
PostRestyleEvent (aContainer, RestyleHint::RestyleSubtree (), nsChangeHint (0 ));
190
196
StyleSet ()->MaybeInvalidateRelativeSelectorForEmptyDependency (*aContainer);
@@ -399,19 +405,7 @@ void RestyleManager::RestyleForInsertOrChange(nsIContent* aChild) {
399
405
}
400
406
401
407
if (selectorFlags & NodeSelectorFlags::HasSlowSelector) {
402
- if (container->IsElement ()) {
403
- auto * containerElement = container->AsElement ();
404
- PostRestyleEvent (containerElement, RestyleHint::RestyleSubtree (),
405
- nsChangeHint (0 ));
406
- if (selectorFlags & NodeSelectorFlags::HasSlowSelectorNthAll) {
407
- StyleSet ()->MaybeInvalidateRelativeSelectorForNthDependencyFromSibling (
408
- containerElement->GetFirstElementChild (),
409
- /* aForceRestyleSiblings = */ false );
410
- }
411
- } else {
412
- RestylePreviousSiblings (aChild);
413
- RestyleSiblingsStartingWith (aChild);
414
- }
408
+ RestyleWholeContainer (container, selectorFlags);
415
409
// Restyling the container is the most we can do here, so we're done.
416
410
return ;
417
411
}
@@ -468,10 +462,11 @@ void RestyleManager::ContentWillBeRemoved(nsIContent* aOldChild) {
468
462
}
469
463
470
464
// The container cannot be a document.
471
- MOZ_ASSERT (container->IsElement () || container->IsShadowRoot ());
465
+ const bool containerIsElement = container->IsElement ();
466
+ MOZ_ASSERT (containerIsElement || container->IsShadowRoot ());
472
467
473
468
if (selectorFlags & NodeSelectorFlags::HasEmptySelector &&
474
- container-> IsElement () ) {
469
+ containerIsElement ) {
475
470
// see whether we need to restyle the container
476
471
bool isEmpty = true ; // :empty or :-moz-only-whitespace
477
472
for (nsIContent* child = container->GetFirstChild (); child;
@@ -485,26 +480,25 @@ void RestyleManager::ContentWillBeRemoved(nsIContent* aOldChild) {
485
480
break ;
486
481
}
487
482
}
488
- if (isEmpty && container-> IsElement () ) {
483
+ if (isEmpty && containerIsElement ) {
489
484
RestyleForEmptyChange (container->AsElement ());
490
485
return ;
491
486
}
492
487
}
493
488
494
- if (selectorFlags & NodeSelectorFlags::HasSlowSelector) {
495
- if (container->IsElement ()) {
496
- auto * containerElement = container->AsElement ();
497
- PostRestyleEvent (containerElement, RestyleHint::RestyleSubtree (),
498
- nsChangeHint (0 ));
499
- if (selectorFlags & NodeSelectorFlags::HasSlowSelectorNthAll) {
500
- StyleSet ()->MaybeInvalidateRelativeSelectorForNthDependencyFromSibling (
501
- containerElement->GetFirstElementChild (),
502
- /* aForceRestyleSiblings = */ false );
503
- }
504
- } else {
505
- RestylePreviousSiblings (aOldChild);
506
- RestyleSiblingsStartingWith (aOldChild);
507
- }
489
+ // It is somewhat common to remove all nodes in a container from the
490
+ // beginning. If we're doing that, going through the
491
+ // HasSlowSelectorLaterSiblings code-path would be quadratic, so that's not
492
+ // amazing. Instead, we take the slower path (which also restyles the
493
+ // container) in that case. It restyles one more element, but it avoids the
494
+ // quadratic behavior.
495
+ const bool restyleWholeContainer =
496
+ (selectorFlags & NodeSelectorFlags::HasSlowSelector) ||
497
+ (selectorFlags & NodeSelectorFlags::HasSlowSelectorLaterSiblings &&
498
+ !aOldChild->GetPreviousSibling ());
499
+
500
+ if (restyleWholeContainer) {
501
+ RestyleWholeContainer (container, selectorFlags);
508
502
// Restyling the container is the most we can do here, so we're done.
509
503
return ;
510
504
}
@@ -3267,6 +3261,7 @@ void RestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags) {
3267
3261
3268
3262
while (styleSet->StyleDocument (aFlags)) {
3269
3263
ClearSnapshots ();
3264
+ mRestyledAsWholeContainer .Clear ();
3270
3265
3271
3266
// Select scroll anchors for frames that have been scrolled. Do this
3272
3267
// before processing restyled frames so that anchor nodes are correctly
@@ -3362,6 +3357,7 @@ void RestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags) {
3362
3357
presContext->FinishedContainerQueryUpdate ();
3363
3358
presContext->UpdateHiddenByContentVisibilityForAnimationsIfNeeded ();
3364
3359
ClearSnapshots ();
3360
+ mRestyledAsWholeContainer .Clear ();
3365
3361
styleSet->AssertTreeIsClean ();
3366
3362
3367
3363
mHaveNonAnimationRestyles = false ;
0 commit comments