Blame layout/base/ServoRestyleManager.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "mozilla/ServoRestyleManager.h"
Packit f0b94e
Packit f0b94e
#include "mozilla/AutoRestyleTimelineMarker.h"
Packit f0b94e
#include "mozilla/AutoTimelineMarker.h"
Packit f0b94e
#include "mozilla/DocumentStyleRootIterator.h"
Packit f0b94e
#include "mozilla/ServoBindings.h"
Packit f0b94e
#include "mozilla/ServoStyleSet.h"
Packit f0b94e
#include "mozilla/ServoStyleContext.h"
Packit f0b94e
#include "mozilla/ServoStyleContextInlines.h"
Packit f0b94e
#include "mozilla/Unused.h"
Packit f0b94e
#include "mozilla/ViewportFrame.h"
Packit f0b94e
#include "mozilla/dom/ChildIterator.h"
Packit f0b94e
#include "mozilla/dom/ElementInlines.h"
Packit f0b94e
#include "nsBlockFrame.h"
Packit f0b94e
#include "nsBulletFrame.h"
Packit f0b94e
#include "nsIFrameInlines.h"
Packit f0b94e
#include "nsImageFrame.h"
Packit f0b94e
#include "nsPlaceholderFrame.h"
Packit f0b94e
#include "nsContentUtils.h"
Packit f0b94e
#include "nsCSSFrameConstructor.h"
Packit f0b94e
#include "nsPrintfCString.h"
Packit f0b94e
#include "nsRefreshDriver.h"
Packit f0b94e
#include "nsStyleChangeList.h"
Packit f0b94e
Packit f0b94e
#ifdef ACCESSIBILITY
Packit f0b94e
#include "nsAccessibilityService.h"
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
using namespace mozilla::dom;
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
static bool IsAnonBox(const nsIFrame& aFrame) {
Packit f0b94e
  return aFrame.StyleContext()->IsAnonBox();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static const nsIFrame* FirstContinuationOrPartOfIBSplit(
Packit f0b94e
    const nsIFrame* aFrame) {
Packit f0b94e
  if (!aFrame) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static const nsIFrame* ExpectedOwnerForChild(const nsIFrame& aFrame) {
Packit f0b94e
  const nsIFrame* parent = aFrame.GetParent();
Packit f0b94e
  if (aFrame.IsTableFrame()) {
Packit f0b94e
    MOZ_ASSERT(parent->IsTableWrapperFrame());
Packit f0b94e
    parent = parent->GetParent();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (IsAnonBox(aFrame) && !aFrame.IsTextFrame()) {
Packit f0b94e
    if (parent->IsLineFrame()) {
Packit f0b94e
      parent = parent->GetParent();
Packit f0b94e
    }
Packit f0b94e
    return parent->IsViewportFrame() ? nullptr
Packit f0b94e
                                     : FirstContinuationOrPartOfIBSplit(parent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aFrame.IsBulletFrame()) {
Packit f0b94e
    return FirstContinuationOrPartOfIBSplit(parent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aFrame.IsLineFrame()) {
Packit f0b94e
    // A ::first-line always ends up here via its block, which is therefore the
Packit f0b94e
    // right expected owner.  That block can be an
Packit f0b94e
    // anonymous box.  For example, we could have a ::first-line on a columnated
Packit f0b94e
    // block; the blockframe is the column-content anonymous box in that case.
Packit f0b94e
    // So we don't want to end up in the code below, which steps out of anon
Packit f0b94e
    // boxes.  Just return the parent of the line frame, which is the block.
Packit f0b94e
    return parent;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aFrame.IsLetterFrame()) {
Packit f0b94e
    // Ditto for ::first-letter. A first-letter always arrives here via its
Packit f0b94e
    // direct parent, except when it's parented to a ::first-line.
Packit f0b94e
    if (parent->IsLineFrame()) {
Packit f0b94e
      parent = parent->GetParent();
Packit f0b94e
    }
Packit f0b94e
    return FirstContinuationOrPartOfIBSplit(parent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (parent->IsLetterFrame()) {
Packit f0b94e
    // Things never have ::first-letter as their expected parent.  Go
Packit f0b94e
    // on up to the ::first-letter's parent.
Packit f0b94e
    parent = parent->GetParent();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  parent = FirstContinuationOrPartOfIBSplit(parent);
Packit f0b94e
Packit f0b94e
  // We've handled already anon boxes and bullet frames, so now we're looking at
Packit f0b94e
  // a frame of a DOM element or pseudo. Hop through anon and line-boxes
Packit f0b94e
  // generated by our DOM parent, and go find the owner frame for it.
Packit f0b94e
  while (parent && (IsAnonBox(*parent) || parent->IsLineFrame())) {
Packit f0b94e
    auto* pseudo = parent->StyleContext()->GetPseudo();
Packit f0b94e
    if (pseudo == nsCSSAnonBoxes::tableWrapper) {
Packit f0b94e
      const nsIFrame* tableFrame = parent->PrincipalChildList().FirstChild();
Packit f0b94e
      MOZ_ASSERT(tableFrame->IsTableFrame());
Packit f0b94e
      // Handle :-moz-table and :-moz-inline-table.
Packit f0b94e
      parent = IsAnonBox(*tableFrame) ? parent->GetParent() : tableFrame;
Packit f0b94e
    } else {
Packit f0b94e
      // We get the in-flow parent here so that we can handle the OOF anonymous
Packit f0b94e
      // boxed to get the correct parent.
Packit f0b94e
      parent = parent->GetInFlowParent();
Packit f0b94e
    }
Packit f0b94e
    parent = FirstContinuationOrPartOfIBSplit(parent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return parent;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleState::AssertOwner(const ServoRestyleState& aParent) const {
Packit f0b94e
  MOZ_ASSERT(mOwner);
Packit f0b94e
  MOZ_ASSERT(!mOwner->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
Packit f0b94e
  // We allow aParent.mOwner to be null, for cases when we're not starting at
Packit f0b94e
  // the root of the tree.  We also allow aParent.mOwner to be somewhere up our
Packit f0b94e
  // expected owner chain not our immediate owner, which allows us creating long
Packit f0b94e
  // chains of ServoRestyleStates in some cases where it's just not worth it.
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
  if (aParent.mOwner) {
Packit f0b94e
    const nsIFrame* owner = ExpectedOwnerForChild(*mOwner);
Packit f0b94e
    if (owner != aParent.mOwner) {
Packit f0b94e
      MOZ_ASSERT(IsAnonBox(*owner),
Packit f0b94e
                 "Should only have expected owner weirdness when anon boxes "
Packit f0b94e
                 "are involved");
Packit f0b94e
      bool found = false;
Packit f0b94e
      for (; owner; owner = ExpectedOwnerForChild(*owner)) {
Packit f0b94e
        if (owner == aParent.mOwner) {
Packit f0b94e
          found = true;
Packit f0b94e
          break;
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
      MOZ_ASSERT(found, "Must have aParent.mOwner on our expected owner chain");
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
#endif
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsChangeHint ServoRestyleState::ChangesHandledFor(
Packit f0b94e
    const nsIFrame& aFrame) const {
Packit f0b94e
  if (!mOwner) {
Packit f0b94e
    MOZ_ASSERT(!mChangesHandled);
Packit f0b94e
    return mChangesHandled;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mOwner == ExpectedOwnerForChild(aFrame),
Packit f0b94e
             "Missed some frame in the hierarchy?");
Packit f0b94e
  return mChangesHandled;
Packit f0b94e
}
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
void ServoRestyleState::AddPendingWrapperRestyle(nsIFrame* aWrapperFrame) {
Packit f0b94e
  MOZ_ASSERT(aWrapperFrame->StyleContext()->IsWrapperAnonBox(),
Packit f0b94e
             "All our wrappers are anon boxes, and why would we restyle "
Packit f0b94e
             "non-inheriting ones?");
Packit f0b94e
  MOZ_ASSERT(aWrapperFrame->StyleContext()->IsInheritingAnonBox(),
Packit f0b94e
             "All our wrappers are anon boxes, and why would we restyle "
Packit f0b94e
             "non-inheriting ones?");
Packit f0b94e
  MOZ_ASSERT(
Packit f0b94e
      aWrapperFrame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::cellContent,
Packit f0b94e
      "Someone should be using TableAwareParentFor");
Packit f0b94e
  MOZ_ASSERT(aWrapperFrame->StyleContext()->GetPseudo() !=
Packit f0b94e
                 nsCSSAnonBoxes::tableWrapper,
Packit f0b94e
             "Someone should be using TableAwareParentFor");
Packit f0b94e
  // Make sure we only add first continuations.
Packit f0b94e
  aWrapperFrame = aWrapperFrame->FirstContinuation();
Packit f0b94e
  nsIFrame* last = mPendingWrapperRestyles.SafeLastElement(nullptr);
Packit f0b94e
  if (last == aWrapperFrame) {
Packit f0b94e
    // Already queued up, nothing to do.
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Make sure to queue up parents before children.  But don't queue up
Packit f0b94e
  // ancestors of non-anonymous boxes here; those are handled when we traverse
Packit f0b94e
  // their non-anonymous kids.
Packit f0b94e
  if (aWrapperFrame->ParentIsWrapperAnonBox()) {
Packit f0b94e
    AddPendingWrapperRestyle(TableAwareParentFor(aWrapperFrame));
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If the append fails, we'll fail to restyle properly, but that's probably
Packit f0b94e
  // better than crashing.
Packit f0b94e
  if (mPendingWrapperRestyles.AppendElement(aWrapperFrame, fallible)) {
Packit f0b94e
    aWrapperFrame->SetIsWrapperAnonBoxNeedingRestyle(true);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleState::ProcessWrapperRestyles(nsIFrame* aParentFrame) {
Packit f0b94e
  size_t i = mPendingWrapperRestyleOffset;
Packit f0b94e
  while (i < mPendingWrapperRestyles.Length()) {
Packit f0b94e
    i += ProcessMaybeNestedWrapperRestyle(aParentFrame, i);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  mPendingWrapperRestyles.TruncateLength(mPendingWrapperRestyleOffset);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
size_t ServoRestyleState::ProcessMaybeNestedWrapperRestyle(nsIFrame* aParent,
Packit f0b94e
                                                           size_t aIndex) {
Packit f0b94e
  // The frame at index aIndex is something we should restyle ourselves, but
Packit f0b94e
  // following frames may need separate ServoRestyleStates to restyle.
Packit f0b94e
  MOZ_ASSERT(aIndex < mPendingWrapperRestyles.Length());
Packit f0b94e
Packit f0b94e
  nsIFrame* cur = mPendingWrapperRestyles[aIndex];
Packit f0b94e
  MOZ_ASSERT(cur->StyleContext()->IsWrapperAnonBox());
Packit f0b94e
Packit f0b94e
  // Where is cur supposed to inherit from?  From its parent frame, except in
Packit f0b94e
  // the case when cur is a table, in which case it should be its grandparent.
Packit f0b94e
  // Also, not in the case when the resulting frame would be a first-line; in
Packit f0b94e
  // that case we should be inheriting from the block, and the first-line will
Packit f0b94e
  // do its fixup later if needed.
Packit f0b94e
  //
Packit f0b94e
  // Note that after we do all that fixup the parent we get might still not be
Packit f0b94e
  // aParent; for example aParent could be a scrollframe, in which case we
Packit f0b94e
  // should inherit from the scrollcontent frame.  Or the parent might be some
Packit f0b94e
  // continuation of aParent.
Packit f0b94e
  //
Packit f0b94e
  // Try to assert as much as we can about the parent we actually end up using
Packit f0b94e
  // without triggering bogus asserts in all those various edge cases.
Packit f0b94e
  nsIFrame* parent = cur->GetParent();
Packit f0b94e
  if (cur->IsTableFrame()) {
Packit f0b94e
    MOZ_ASSERT(parent->IsTableWrapperFrame());
Packit f0b94e
    parent = parent->GetParent();
Packit f0b94e
  }
Packit f0b94e
  if (parent->IsLineFrame()) {
Packit f0b94e
    parent = parent->GetParent();
Packit f0b94e
  }
Packit f0b94e
  MOZ_ASSERT(FirstContinuationOrPartOfIBSplit(parent) == aParent ||
Packit f0b94e
             (parent->StyleContext()->IsInheritingAnonBox() &&
Packit f0b94e
              parent->GetContent() == aParent->GetContent()));
Packit f0b94e
Packit f0b94e
  // Now "this" is a ServoRestyleState for aParent, so if parent is not a next
Packit f0b94e
  // continuation (possibly across ib splits) of aParent we need a new
Packit f0b94e
  // ServoRestyleState for the kid.
Packit f0b94e
  Maybe<ServoRestyleState> parentRestyleState;
Packit f0b94e
  nsIFrame* parentForRestyle =
Packit f0b94e
      nsLayoutUtils::FirstContinuationOrIBSplitSibling(parent);
Packit f0b94e
  if (parentForRestyle != aParent) {
Packit f0b94e
    parentRestyleState.emplace(*parentForRestyle, *this, nsChangeHint_Empty,
Packit f0b94e
                               Type::InFlow);
Packit f0b94e
  }
Packit f0b94e
  ServoRestyleState& curRestyleState =
Packit f0b94e
      parentRestyleState ? *parentRestyleState : *this;
Packit f0b94e
Packit f0b94e
  // This frame may already have been restyled.  Even if it has, we can't just
Packit f0b94e
  // return, because the next frame may be a kid of it that does need restyling.
Packit f0b94e
  if (cur->IsWrapperAnonBoxNeedingRestyle()) {
Packit f0b94e
    parentForRestyle->UpdateStyleOfChildAnonBox(cur, curRestyleState);
Packit f0b94e
    cur->SetIsWrapperAnonBoxNeedingRestyle(false);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  size_t numProcessed = 1;
Packit f0b94e
Packit f0b94e
  // Note: no overflow possible here, since aIndex < length.
Packit f0b94e
  if (aIndex + 1 < mPendingWrapperRestyles.Length()) {
Packit f0b94e
    nsIFrame* next = mPendingWrapperRestyles[aIndex + 1];
Packit f0b94e
    if (TableAwareParentFor(next) == cur &&
Packit f0b94e
        next->IsWrapperAnonBoxNeedingRestyle()) {
Packit f0b94e
      // It might be nice if we could do better than nsChangeHint_Empty.  On
Packit f0b94e
      // the other hand, presumably our mChangesHandled already has the bits
Packit f0b94e
      // we really want here so in practice it doesn't matter.
Packit f0b94e
      ServoRestyleState childState(*cur, curRestyleState, nsChangeHint_Empty,
Packit f0b94e
                                   Type::InFlow,
Packit f0b94e
                                   /* aAssertWrapperRestyleLength = */ false);
Packit f0b94e
      numProcessed +=
Packit f0b94e
          childState.ProcessMaybeNestedWrapperRestyle(cur, aIndex + 1);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return numProcessed;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsIFrame* ServoRestyleState::TableAwareParentFor(const nsIFrame* aChild) {
Packit f0b94e
  // We want to get the anon box parent for aChild. where aChild has
Packit f0b94e
  // ParentIsWrapperAnonBox().
Packit f0b94e
  //
Packit f0b94e
  // For the most part this is pretty straightforward, but there are two
Packit f0b94e
  // wrinkles.  First, if aChild is a table, then we really want the parent of
Packit f0b94e
  // its table wrapper.
Packit f0b94e
  if (aChild->IsTableFrame()) {
Packit f0b94e
    aChild = aChild->GetParent();
Packit f0b94e
    MOZ_ASSERT(aChild->IsTableWrapperFrame());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsIFrame* parent = aChild->GetParent();
Packit f0b94e
  // Now if parent is a cell-content frame, we actually want the cellframe.
Packit f0b94e
  if (parent->StyleContext()->GetPseudo() == nsCSSAnonBoxes::cellContent) {
Packit f0b94e
    parent = parent->GetParent();
Packit f0b94e
  } else if (parent->IsTableWrapperFrame()) {
Packit f0b94e
    // Must be a caption.  In that case we want the table here.
Packit f0b94e
    MOZ_ASSERT(aChild->StyleDisplay()->mDisplay == StyleDisplay::TableCaption);
Packit f0b94e
    parent = parent->PrincipalChildList().FirstChild();
Packit f0b94e
  }
Packit f0b94e
  return parent;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
Packit f0b94e
    : RestyleManager(StyleBackendType::Servo, aPresContext),
Packit f0b94e
      mReentrantChanges(nullptr) {}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::PostRestyleEvent(Element* aElement,
Packit f0b94e
                                           nsRestyleHint aRestyleHint,
Packit f0b94e
                                           nsChangeHint aMinChangeHint) {
Packit f0b94e
  MOZ_ASSERT(!(aMinChangeHint & nsChangeHint_NeutralChange),
Packit f0b94e
             "Didn't expect explicit change hints to be neutral!");
Packit f0b94e
  if (MOZ_UNLIKELY(IsDisconnected()) ||
Packit f0b94e
      MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We allow posting restyles from within change hint handling, but not from
Packit f0b94e
  // within the restyle algorithm itself.
Packit f0b94e
  MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
Packit f0b94e
Packit f0b94e
  if (aRestyleHint == 0 && !aMinChangeHint) {
Packit f0b94e
    return;  // Nothing to do.
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Assuming the restyle hints will invalidate cached style for
Packit f0b94e
  // getComputedStyle, since we don't know if any of the restyling that we do
Packit f0b94e
  // would affect undisplayed elements.
Packit f0b94e
  if (aRestyleHint) {
Packit f0b94e
    IncrementUndisplayedRestyleGeneration();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Processing change hints sometimes causes new change hints to be generated,
Packit f0b94e
  // and very occasionally, additional restyle hints. We collect the change
Packit f0b94e
  // hints manually to avoid re-traversing the DOM to find them.
Packit f0b94e
  if (mReentrantChanges && !aRestyleHint) {
Packit f0b94e
    mReentrantChanges->AppendElement(ReentrantChange{aElement, aMinChangeHint});
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aRestyleHint & ~eRestyle_AllHintsWithAnimations) {
Packit f0b94e
    mHaveNonAnimationRestyles = true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aRestyleHint & eRestyle_LaterSiblings) {
Packit f0b94e
    aRestyleHint &= ~eRestyle_LaterSiblings;
Packit f0b94e
Packit f0b94e
    nsRestyleHint siblingHint = eRestyle_Subtree;
Packit f0b94e
    Element* current = aElement->GetNextElementSibling();
Packit f0b94e
    while (current) {
Packit f0b94e
      Servo_NoteExplicitHints(current, siblingHint, nsChangeHint(0));
Packit f0b94e
      current = current->GetNextElementSibling();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aRestyleHint || aMinChangeHint) {
Packit f0b94e
    Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::PostRestyleEventForCSSRuleChanges() {
Packit f0b94e
  mRestyleForCSSRuleChanges = true;
Packit f0b94e
  mPresContext->PresShell()->EnsureStyleFlush();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::PostRestyleEventForAnimations(
Packit f0b94e
    Element* aElement, CSSPseudoElementType aPseudoType,
Packit f0b94e
    nsRestyleHint aRestyleHint) {
Packit f0b94e
  Element* elementToRestyle =
Packit f0b94e
      EffectCompositor::GetElementToRestyle(aElement, aPseudoType);
Packit f0b94e
Packit f0b94e
  if (!elementToRestyle) {
Packit f0b94e
    // FIXME: Bug 1371107: When reframing happens,
Packit f0b94e
    // EffectCompositor::mElementsToRestyle still has unbinded old pseudo
Packit f0b94e
    // element. We should drop it.
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  AutoRestyleTimelineMarker marker(mPresContext->GetDocShell(),
Packit f0b94e
                                   true /* animation-only */);
Packit f0b94e
  Servo_NoteExplicitHints(elementToRestyle, aRestyleHint, nsChangeHint(0));
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
Packit f0b94e
                                              nsRestyleHint aRestyleHint) {
Packit f0b94e
  // NOTE(emilio): GeckoRestlyeManager does a sync style flush, which seems not
Packit f0b94e
  // to be needed in my testing.
Packit f0b94e
  PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::PostRebuildAllStyleDataEvent(
Packit f0b94e
    nsChangeHint aExtraHint, nsRestyleHint aRestyleHint) {
Packit f0b94e
  // NOTE(emilio): The semantics of these methods are quite funny, in the sense
Packit f0b94e
  // that we're not supposed to need to rebuild the actual stylist data.
Packit f0b94e
  //
Packit f0b94e
  // That's handled as part of the MediumFeaturesChanged stuff, if needed.
Packit f0b94e
  StyleSet()->ClearCachedStyleData();
Packit f0b94e
Packit f0b94e
  DocumentStyleRootIterator iter(mPresContext->Document());
Packit f0b94e
  while (Element* root = iter.GetNextStyleRoot()) {
Packit f0b94e
    PostRestyleEvent(root, aRestyleHint, aExtraHint);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // TODO(emilio, bz): Extensions can add/remove stylesheets that can affect
Packit f0b94e
  // non-inheriting anon boxes. It's not clear if we want to support that, but
Packit f0b94e
  // if we do, we need to re-selector-match them here.
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void ServoRestyleManager::ClearServoDataFromSubtree(
Packit f0b94e
    Element* aElement, IncludeRoot aIncludeRoot) {
Packit f0b94e
  if (aElement->HasServoData()) {
Packit f0b94e
    StyleChildrenIterator it(aElement);
Packit f0b94e
    for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
Packit f0b94e
      if (n->IsElement()) {
Packit f0b94e
        ClearServoDataFromSubtree(n->AsElement(), IncludeRoot::Yes);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (MOZ_LIKELY(aIncludeRoot == IncludeRoot::Yes)) {
Packit f0b94e
    aElement->ClearServoData();
Packit f0b94e
    MOZ_ASSERT(!aElement->HasAnyOfFlags(Element::kAllServoDescendantBits |
Packit f0b94e
                                        NODE_NEEDS_FRAME));
Packit f0b94e
    MOZ_ASSERT(aElement != aElement->OwnerDoc()->GetServoRestyleRoot());
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void ServoRestyleManager::ClearRestyleStateFromSubtree(
Packit f0b94e
    Element* aElement) {
Packit f0b94e
  if (aElement->HasAnyOfFlags(Element::kAllServoDescendantBits)) {
Packit f0b94e
    StyleChildrenIterator it(aElement);
Packit f0b94e
    for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
Packit f0b94e
      if (n->IsElement()) {
Packit f0b94e
        ClearRestyleStateFromSubtree(n->AsElement());
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool wasRestyled;
Packit f0b94e
  Unused << Servo_TakeChangeHint(aElement, &wasRestyled);
Packit f0b94e
  aElement->UnsetFlags(Element::kAllServoDescendantBits);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * This struct takes care of encapsulating some common state that text nodes may
Packit f0b94e
 * need to track during the post-traversal.
Packit f0b94e
 *
Packit f0b94e
 * This is currently used to properly compute change hints when the parent
Packit f0b94e
 * element of this node is a display: contents node, and also to avoid computing
Packit f0b94e
 * the style for text children more than once per element.
Packit f0b94e
 */
Packit f0b94e
struct ServoRestyleManager::TextPostTraversalState {
Packit f0b94e
 public:
Packit f0b94e
  TextPostTraversalState(Element& aParentElement,
Packit f0b94e
                         ServoStyleContext* aParentContext,
Packit f0b94e
                         bool aDisplayContentsParentStyleChanged,
Packit f0b94e
                         ServoRestyleState& aParentRestyleState)
Packit f0b94e
      : mParentElement(aParentElement),
Packit f0b94e
        mParentContext(aParentContext),
Packit f0b94e
        mParentRestyleState(aParentRestyleState),
Packit f0b94e
        mStyle(nullptr),
Packit f0b94e
        mShouldPostHints(aDisplayContentsParentStyleChanged),
Packit f0b94e
        mShouldComputeHints(aDisplayContentsParentStyleChanged),
Packit f0b94e
        mComputedHint(nsChangeHint_Empty) {}
Packit f0b94e
Packit f0b94e
  nsStyleChangeList& ChangeList() { return mParentRestyleState.ChangeList(); }
Packit f0b94e
Packit f0b94e
  nsStyleContext& ComputeStyle(nsIContent* aTextNode) {
Packit f0b94e
    if (!mStyle) {
Packit f0b94e
      mStyle = mParentRestyleState.StyleSet().ResolveStyleForText(
Packit f0b94e
          aTextNode, &ParentStyle());
Packit f0b94e
    }
Packit f0b94e
    MOZ_ASSERT(mStyle);
Packit f0b94e
    return *mStyle;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void ComputeHintIfNeeded(nsIContent* aContent, nsIFrame* aTextFrame,
Packit f0b94e
                           nsStyleContext& aNewContext) {
Packit f0b94e
    MOZ_ASSERT(aTextFrame);
Packit f0b94e
    MOZ_ASSERT(aNewContext.GetPseudo() == nsCSSAnonBoxes::mozText);
Packit f0b94e
Packit f0b94e
    if (MOZ_LIKELY(!mShouldPostHints)) {
Packit f0b94e
      return;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    ServoStyleContext* oldContext = aTextFrame->StyleContext()->AsServo();
Packit f0b94e
    MOZ_ASSERT(oldContext->GetPseudo() == nsCSSAnonBoxes::mozText);
Packit f0b94e
Packit f0b94e
    // We rely on the fact that all the text children for the same element share
Packit f0b94e
    // style to avoid recomputing style differences for all of them.
Packit f0b94e
    //
Packit f0b94e
    // TODO(emilio): The above may not be true for ::first-{line,letter}, but
Packit f0b94e
    // we'll cross that bridge when we support those in stylo.
Packit f0b94e
    if (mShouldComputeHints) {
Packit f0b94e
      mShouldComputeHints = false;
Packit f0b94e
      uint32_t equalStructs, samePointerStructs;
Packit f0b94e
      mComputedHint = oldContext->CalcStyleDifference(
Packit f0b94e
          &aNewContext, &equalStructs, &samePointerStructs);
Packit f0b94e
      mComputedHint = NS_RemoveSubsumedHints(
Packit f0b94e
          mComputedHint, mParentRestyleState.ChangesHandledFor(*aTextFrame));
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (mComputedHint) {
Packit f0b94e
      mParentRestyleState.ChangeList().AppendChange(aTextFrame, aContent,
Packit f0b94e
                                                    mComputedHint);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  ServoStyleContext& ParentStyle() {
Packit f0b94e
    if (!mParentContext) {
Packit f0b94e
      mLazilyResolvedParentContext =
Packit f0b94e
          mParentRestyleState.StyleSet().ResolveServoStyle(&mParentElement);
Packit f0b94e
      mParentContext = mLazilyResolvedParentContext;
Packit f0b94e
    }
Packit f0b94e
    return *mParentContext;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Element& mParentElement;
Packit f0b94e
  ServoStyleContext* mParentContext;
Packit f0b94e
  RefPtr<ServoStyleContext> mLazilyResolvedParentContext;
Packit f0b94e
  ServoRestyleState& mParentRestyleState;
Packit f0b94e
  RefPtr<nsStyleContext> mStyle;
Packit f0b94e
  bool mShouldPostHints;
Packit f0b94e
  bool mShouldComputeHints;
Packit f0b94e
  nsChangeHint mComputedHint;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
static void UpdateBackdropIfNeeded(nsIFrame* aFrame, ServoStyleSet& aStyleSet,
Packit f0b94e
                                   nsStyleChangeList& aChangeList) {
Packit f0b94e
  const nsStyleDisplay* display = aFrame->StyleContext()->StyleDisplay();
Packit f0b94e
  if (display->mTopLayer != NS_STYLE_TOP_LAYER_TOP) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Elements in the top layer are guaranteed to have absolute or fixed
Packit f0b94e
  // position per https://fullscreen.spec.whatwg.org/#new-stacking-layer.
Packit f0b94e
  MOZ_ASSERT(display->IsAbsolutelyPositionedStyle());
Packit f0b94e
Packit f0b94e
  nsIFrame* backdropPlaceholder =
Packit f0b94e
      aFrame->GetChildList(nsIFrame::kBackdropList).FirstChild();
Packit f0b94e
  if (!backdropPlaceholder) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(backdropPlaceholder->IsPlaceholderFrame());
Packit f0b94e
  nsIFrame* backdropFrame =
Packit f0b94e
      nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPlaceholder);
Packit f0b94e
  MOZ_ASSERT(backdropFrame->IsBackdropFrame());
Packit f0b94e
  MOZ_ASSERT(backdropFrame->StyleContext()->GetPseudoType() ==
Packit f0b94e
             CSSPseudoElementType::backdrop);
Packit f0b94e
Packit f0b94e
  RefPtr<nsStyleContext> newContext = aStyleSet.ResolvePseudoElementStyle(
Packit f0b94e
      aFrame->GetContent()->AsElement(), CSSPseudoElementType::backdrop,
Packit f0b94e
      aFrame->StyleContext()->AsServo(),
Packit f0b94e
      /* aPseudoElement = */ nullptr);
Packit f0b94e
Packit f0b94e
  // NOTE(emilio): We can't use the changes handled for the owner of the
Packit f0b94e
  // backdrop frame, since it's out of flow, and parented to the viewport or
Packit f0b94e
  // canvas frame (depending on the `position` value).
Packit f0b94e
  MOZ_ASSERT(backdropFrame->GetParent()->IsViewportFrame() ||
Packit f0b94e
             backdropFrame->GetParent()->IsCanvasFrame());
Packit f0b94e
  nsTArray<nsIFrame*> wrappersToRestyle;
Packit f0b94e
  ServoRestyleState state(aStyleSet, aChangeList, wrappersToRestyle);
Packit f0b94e
  aFrame->UpdateStyleOfOwnedChildFrame(backdropFrame, newContext, state);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void UpdateFirstLetterIfNeeded(nsIFrame* aFrame,
Packit f0b94e
                                      ServoRestyleState& aRestyleState) {
Packit f0b94e
  MOZ_ASSERT(
Packit f0b94e
      !aFrame->IsFrameOfType(nsIFrame::eBlockFrame),
Packit f0b94e
      "You're probably duplicating work with UpdatePseudoElementStyles!");
Packit f0b94e
  if (!aFrame->HasFirstLetterChild()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We need to find the block the first-letter is associated with so we can
Packit f0b94e
  // find the right element for the first-letter's style resolution.  Might as
Packit f0b94e
  // well just delegate the whole thing to that block.
Packit f0b94e
  nsIFrame* block = aFrame->GetParent();
Packit f0b94e
  while (!block->IsFrameOfType(nsIFrame::eBlockFrame)) {
Packit f0b94e
    block = block->GetParent();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  static_cast<nsBlockFrame*>(block->FirstContinuation())
Packit f0b94e
      ->UpdateFirstLetterStyle(aRestyleState);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void UpdateOneAdditionalStyleContext(nsIFrame* aFrame, uint32_t aIndex,
Packit f0b94e
                                            ServoStyleContext& aOldContext,
Packit f0b94e
                                            ServoRestyleState& aRestyleState) {
Packit f0b94e
  auto pseudoType = aOldContext.GetPseudoType();
Packit f0b94e
  MOZ_ASSERT(pseudoType != CSSPseudoElementType::NotPseudo);
Packit f0b94e
  MOZ_ASSERT(
Packit f0b94e
      !nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudoType));
Packit f0b94e
Packit f0b94e
  RefPtr<ServoStyleContext> newContext =
Packit f0b94e
      aRestyleState.StyleSet().ResolvePseudoElementStyle(
Packit f0b94e
          aFrame->GetContent()->AsElement(), pseudoType,
Packit f0b94e
          aFrame->StyleContext()->AsServo(),
Packit f0b94e
          /* aPseudoElement = */ nullptr);
Packit f0b94e
Packit f0b94e
  uint32_t equalStructs, samePointerStructs;  // Not used, actually.
Packit f0b94e
  nsChangeHint childHint = aOldContext.CalcStyleDifference(
Packit f0b94e
      newContext, &equalStructs, &samePointerStructs);
Packit f0b94e
  if (!aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
Packit f0b94e
    childHint = NS_RemoveSubsumedHints(
Packit f0b94e
        childHint, aRestyleState.ChangesHandledFor(*aFrame));
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (childHint) {
Packit f0b94e
    if (childHint & nsChangeHint_ReconstructFrame) {
Packit f0b94e
      // If we generate a reconstruct here, remove any non-reconstruct hints we
Packit f0b94e
      // may have already generated for this content.
Packit f0b94e
      aRestyleState.ChangeList().PopChangesForContent(aFrame->GetContent());
Packit f0b94e
    }
Packit f0b94e
    aRestyleState.ChangeList().AppendChange(aFrame, aFrame->GetContent(),
Packit f0b94e
                                            childHint);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  aFrame->SetAdditionalStyleContext(aIndex, newContext);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void UpdateAdditionalStyleContexts(nsIFrame* aFrame,
Packit f0b94e
                                          ServoRestyleState& aRestyleState) {
Packit f0b94e
  MOZ_ASSERT(aFrame);
Packit f0b94e
  MOZ_ASSERT(aFrame->GetContent() && aFrame->GetContent()->IsElement());
Packit f0b94e
Packit f0b94e
  // FIXME(emilio): Consider adding a bit or something to avoid the initial
Packit f0b94e
  // virtual call?
Packit f0b94e
  uint32_t index = 0;
Packit f0b94e
  while (auto* oldContext = aFrame->GetAdditionalStyleContext(index)) {
Packit f0b94e
    UpdateOneAdditionalStyleContext(aFrame, index++, *oldContext->AsServo(),
Packit f0b94e
                                    aRestyleState);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void UpdateFramePseudoElementStyles(nsIFrame* aFrame,
Packit f0b94e
                                           ServoRestyleState& aRestyleState) {
Packit f0b94e
  if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
Packit f0b94e
    static_cast<nsBlockFrame*>(aFrame)->UpdatePseudoElementStyles(
Packit f0b94e
        aRestyleState);
Packit f0b94e
  } else {
Packit f0b94e
    UpdateFirstLetterIfNeeded(aFrame, aRestyleState);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  UpdateBackdropIfNeeded(aFrame, aRestyleState.StyleSet(),
Packit f0b94e
                         aRestyleState.ChangeList());
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
enum class ServoPostTraversalFlags : uint32_t {
Packit f0b94e
  Empty = 0,
Packit f0b94e
  // Whether parent was restyled.
Packit f0b94e
  ParentWasRestyled = 1 << 0,
Packit f0b94e
  // Skip sending accessibility notifications for all descendants.
Packit f0b94e
  SkipA11yNotifications = 1 << 1,
Packit f0b94e
  // Always send accessibility notifications if the element is shown.
Packit f0b94e
  // The SkipA11yNotifications flag above overrides this flag.
Packit f0b94e
  SendA11yNotificationsIfShown = 1 << 2,
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoPostTraversalFlags)
Packit f0b94e
Packit f0b94e
// Send proper accessibility notifications and return post traversal
Packit f0b94e
// flags for kids.
Packit f0b94e
static ServoPostTraversalFlags SendA11yNotifications(
Packit f0b94e
    nsPresContext* aPresContext, Element* aElement,
Packit f0b94e
    nsStyleContext* aOldStyleContext, nsStyleContext* aNewStyleContext,
Packit f0b94e
    ServoPostTraversalFlags aFlags) {
Packit f0b94e
  using Flags = ServoPostTraversalFlags;
Packit f0b94e
  MOZ_ASSERT(!(aFlags & Flags::SkipA11yNotifications) ||
Packit f0b94e
                 !(aFlags & Flags::SendA11yNotificationsIfShown),
Packit f0b94e
             "The two a11y flags should never be set together");
Packit f0b94e
Packit f0b94e
#ifdef ACCESSIBILITY
Packit f0b94e
  nsAccessibilityService* accService = GetAccService();
Packit f0b94e
  if (!accService) {
Packit f0b94e
    // If we don't have accessibility service, accessibility is not
Packit f0b94e
    // enabled. Just skip everything.
Packit f0b94e
    return Flags::Empty;
Packit f0b94e
  }
Packit f0b94e
  if (aFlags & Flags::SkipA11yNotifications) {
Packit f0b94e
    // Propogate the skipping flag to descendants.
Packit f0b94e
    return Flags::SkipA11yNotifications;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool needsNotify = false;
Packit f0b94e
  bool isVisible = aNewStyleContext->StyleVisibility()->IsVisible();
Packit f0b94e
  if (aFlags & Flags::SendA11yNotificationsIfShown) {
Packit f0b94e
    if (!isVisible) {
Packit f0b94e
      // Propagate the sending-if-shown flag to descendants.
Packit f0b94e
      return Flags::SendA11yNotificationsIfShown;
Packit f0b94e
    }
Packit f0b94e
    // We have asked accessibility service to remove the whole subtree
Packit f0b94e
    // of element which becomes invisible from the accessible tree, but
Packit f0b94e
    // this element is visible, so we need to add it back.
Packit f0b94e
    needsNotify = true;
Packit f0b94e
  } else {
Packit f0b94e
    // If we shouldn't skip in any case, we need to check whether our
Packit f0b94e
    // own visibility has changed.
Packit f0b94e
    bool wasVisible = aOldStyleContext->StyleVisibility()->IsVisible();
Packit f0b94e
    needsNotify = wasVisible != isVisible;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (needsNotify) {
Packit f0b94e
    nsIPresShell* presShell = aPresContext->PresShell();
Packit f0b94e
    if (isVisible) {
Packit f0b94e
      accService->ContentRangeInserted(presShell, aElement->GetParent(),
Packit f0b94e
                                       aElement, aElement->GetNextSibling());
Packit f0b94e
      // We are adding the subtree. Accessibility service would handle
Packit f0b94e
      // descendants, so we should just skip them from notifying.
Packit f0b94e
      return Flags::SkipA11yNotifications;
Packit f0b94e
    }
Packit f0b94e
    // Remove the subtree of this invisible element, and ask any shown
Packit f0b94e
    // descendant to add themselves back.
Packit f0b94e
    accService->ContentRemoved(presShell, aElement);
Packit f0b94e
    return Flags::SendA11yNotificationsIfShown;
Packit f0b94e
  }
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
  return Flags::Empty;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool ServoRestyleManager::ProcessPostTraversal(
Packit f0b94e
    Element* aElement, ServoStyleContext* aParentContext,
Packit f0b94e
    ServoRestyleState& aRestyleState, ServoPostTraversalFlags aFlags) {
Packit f0b94e
  nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
Packit f0b94e
  nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
Packit f0b94e
Packit f0b94e
  // NOTE(emilio): This is needed because for table frames the bit is set on the
Packit f0b94e
  // table wrapper (which is the primary frame), not on the table itself.
Packit f0b94e
  const bool isOutOfFlow =
Packit f0b94e
      primaryFrame && primaryFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
Packit f0b94e
Packit f0b94e
  // Grab the change hint from Servo.
Packit f0b94e
  bool wasRestyled;
Packit f0b94e
  nsChangeHint changeHint =
Packit f0b94e
      static_cast<nsChangeHint>(Servo_TakeChangeHint(aElement, &wasRestyled));
Packit f0b94e
Packit f0b94e
  // We should really fix the weird primary frame mapping for image maps
Packit f0b94e
  // (bug 135040)...
Packit f0b94e
  if (styleFrame && styleFrame->GetContent() != aElement) {
Packit f0b94e
    MOZ_ASSERT(static_cast<nsImageFrame*>(do_QueryFrame(styleFrame)));
Packit f0b94e
    styleFrame = nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Handle lazy frame construction by posting a reconstruct for any lazily-
Packit f0b94e
  // constructed roots.
Packit f0b94e
  if (aElement->HasFlag(NODE_NEEDS_FRAME)) {
Packit f0b94e
    changeHint |= nsChangeHint_ReconstructFrame;
Packit f0b94e
    MOZ_ASSERT(!styleFrame);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (styleFrame) {
Packit f0b94e
    MOZ_ASSERT(primaryFrame);
Packit f0b94e
Packit f0b94e
    nsIFrame* maybeAnonBoxChild;
Packit f0b94e
    if (isOutOfFlow) {
Packit f0b94e
      maybeAnonBoxChild = primaryFrame->GetPlaceholderFrame();
Packit f0b94e
    } else {
Packit f0b94e
      maybeAnonBoxChild = primaryFrame;
Packit f0b94e
      changeHint = NS_RemoveSubsumedHints(
Packit f0b94e
          changeHint, aRestyleState.ChangesHandledFor(*styleFrame));
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // If the parent wasn't restyled, the styles of our anon box parents won't
Packit f0b94e
    // change either.
Packit f0b94e
    if ((aFlags & ServoPostTraversalFlags::ParentWasRestyled) &&
Packit f0b94e
        maybeAnonBoxChild->ParentIsWrapperAnonBox()) {
Packit f0b94e
      aRestyleState.AddPendingWrapperRestyle(
Packit f0b94e
          ServoRestyleState::TableAwareParentFor(maybeAnonBoxChild));
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Although we shouldn't generate non-ReconstructFrame hints for elements with
Packit f0b94e
  // no frames, we can still get them here if they were explicitly posted by
Packit f0b94e
  // PostRestyleEvent, such as a RepaintFrame hint when a :link changes to be
Packit f0b94e
  // :visited.  Skip processing these hints if there is no frame.
Packit f0b94e
  if ((styleFrame || (changeHint & nsChangeHint_ReconstructFrame)) &&
Packit f0b94e
      changeHint) {
Packit f0b94e
    aRestyleState.ChangeList().AppendChange(styleFrame, aElement, changeHint);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If our change hint is reconstruct, we delegate to the frame constructor,
Packit f0b94e
  // which consumes the new style and expects the old style to be on the frame.
Packit f0b94e
  //
Packit f0b94e
  // XXXbholley: We should teach the frame constructor how to clear the dirty
Packit f0b94e
  // descendants bit to avoid the traversal here.
Packit f0b94e
  if (changeHint & nsChangeHint_ReconstructFrame) {
Packit f0b94e
    ClearRestyleStateFromSubtree(aElement);
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // TODO(emilio): We could avoid some refcount traffic here, specially in the
Packit f0b94e
  // ServoStyleContext case, which uses atomic refcounting.
Packit f0b94e
  //
Packit f0b94e
  // Hold the old style context alive, because it could become a dangling
Packit f0b94e
  // pointer during the replacement. In practice it's not a huge deal, but
Packit f0b94e
  // better not playing with dangling pointers if not needed.
Packit f0b94e
  RefPtr<ServoStyleContext> oldStyleContext =
Packit f0b94e
      styleFrame ? styleFrame->StyleContext()->AsServo() : nullptr;
Packit f0b94e
Packit f0b94e
  nsStyleContext* displayContentsStyle = nullptr;
Packit f0b94e
  // FIXME(emilio, bug 1303605): This can be simpler for Servo.
Packit f0b94e
  // Note that we intentionally don't check for display: none content.
Packit f0b94e
  if (!oldStyleContext) {
Packit f0b94e
    displayContentsStyle =
Packit f0b94e
        PresContext()->FrameConstructor()->GetDisplayContentsStyleFor(aElement);
Packit f0b94e
    if (displayContentsStyle) {
Packit f0b94e
      oldStyleContext = displayContentsStyle->AsServo();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Maybe<ServoRestyleState> thisFrameRestyleState;
Packit f0b94e
  if (styleFrame) {
Packit f0b94e
    auto type = isOutOfFlow ? ServoRestyleState::Type::OutOfFlow
Packit f0b94e
                            : ServoRestyleState::Type::InFlow;
Packit f0b94e
Packit f0b94e
    thisFrameRestyleState.emplace(*styleFrame, aRestyleState, changeHint, type);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We can't really assume as used changes from display: contents elements (or
Packit f0b94e
  // other elements without frames).
Packit f0b94e
  ServoRestyleState& childrenRestyleState =
Packit f0b94e
      thisFrameRestyleState ? *thisFrameRestyleState : aRestyleState;
Packit f0b94e
Packit f0b94e
  RefPtr<ServoStyleContext> upToDateContext =
Packit f0b94e
      wasRestyled ? aRestyleState.StyleSet().ResolveServoStyle(aElement)
Packit f0b94e
                  : oldStyleContext;
Packit f0b94e
Packit f0b94e
  ServoPostTraversalFlags childrenFlags =
Packit f0b94e
      wasRestyled ? ServoPostTraversalFlags::ParentWasRestyled
Packit f0b94e
                  : ServoPostTraversalFlags::Empty;
Packit f0b94e
Packit f0b94e
  if (wasRestyled && oldStyleContext) {
Packit f0b94e
    MOZ_ASSERT(styleFrame || displayContentsStyle);
Packit f0b94e
    MOZ_ASSERT(oldStyleContext->ComputedData() !=
Packit f0b94e
               upToDateContext->ComputedData());
Packit f0b94e
Packit f0b94e
    upToDateContext->ResolveSameStructsAs(oldStyleContext);
Packit f0b94e
Packit f0b94e
    // We want to walk all the continuations here, even the ones with different
Packit f0b94e
    // styles.  In practice, the only reason we get continuations with different
Packit f0b94e
    // styles here is ::first-line (::first-letter never affects element
Packit f0b94e
    // styles).  But in that case, newContext is the right context for the
Packit f0b94e
    // _later_ continuations anyway (the ones not affected by ::first-line), not
Packit f0b94e
    // the earlier ones, so there is no point stopping right at the point when
Packit f0b94e
    // we'd actually be setting the right style context.
Packit f0b94e
    //
Packit f0b94e
    // This does mean that we may be setting the wrong style context on our
Packit f0b94e
    // initial continuations; ::first-line fixes that up after the fact.
Packit f0b94e
    for (nsIFrame* f = styleFrame; f; f = f->GetNextContinuation()) {
Packit f0b94e
      MOZ_ASSERT_IF(f != styleFrame, !f->GetAdditionalStyleContext(0));
Packit f0b94e
      f->SetStyleContext(upToDateContext);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (MOZ_UNLIKELY(displayContentsStyle)) {
Packit f0b94e
      MOZ_ASSERT(!styleFrame);
Packit f0b94e
      PresContext()
Packit f0b94e
          ->FrameConstructor()
Packit f0b94e
          ->ChangeRegisteredDisplayContentsStyleFor(aElement, upToDateContext);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (styleFrame) {
Packit f0b94e
      UpdateAdditionalStyleContexts(styleFrame, aRestyleState);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (!aElement->GetParent()) {
Packit f0b94e
      // This is the root.  Update styles on the viewport as needed.
Packit f0b94e
      ViewportFrame* viewport =
Packit f0b94e
          do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
Packit f0b94e
      if (viewport) {
Packit f0b94e
        // NB: The root restyle state, not the one for our children!
Packit f0b94e
        viewport->UpdateStyle(aRestyleState);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // Some changes to animations don't affect the computed style and yet still
Packit f0b94e
    // require the layer to be updated. For example, pausing an animation via
Packit f0b94e
    // the Web Animations API won't affect an element's style but still
Packit f0b94e
    // requires to update the animation on the layer.
Packit f0b94e
    //
Packit f0b94e
    // We can sometimes reach this when the animated style is being removed.
Packit f0b94e
    // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
Packit f0b94e
    // style or not, we need to call it *after* setting |newContext| to
Packit f0b94e
    // |styleFrame| to ensure the animated transform has been removed first.
Packit f0b94e
    AddLayerChangesForAnimation(styleFrame, aElement,
Packit f0b94e
                                aRestyleState.ChangeList());
Packit f0b94e
Packit f0b94e
    childrenFlags |= SendA11yNotifications(
Packit f0b94e
        mPresContext, aElement, oldStyleContext, upToDateContext, aFlags);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  const bool traverseElementChildren =
Packit f0b94e
      aElement->HasAnyOfFlags(Element::kAllServoDescendantBits);
Packit f0b94e
  const bool traverseTextChildren =
Packit f0b94e
      wasRestyled || aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
Packit f0b94e
  bool recreatedAnyContext = wasRestyled;
Packit f0b94e
  if (traverseElementChildren || traverseTextChildren) {
Packit f0b94e
    StyleChildrenIterator it(aElement);
Packit f0b94e
    TextPostTraversalState textState(*aElement, upToDateContext,
Packit f0b94e
                                     displayContentsStyle && wasRestyled,
Packit f0b94e
                                     childrenRestyleState);
Packit f0b94e
    for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
Packit f0b94e
      if (traverseElementChildren && n->IsElement()) {
Packit f0b94e
        recreatedAnyContext |=
Packit f0b94e
            ProcessPostTraversal(n->AsElement(), upToDateContext,
Packit f0b94e
                                 childrenRestyleState, childrenFlags);
Packit f0b94e
      } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
Packit f0b94e
        recreatedAnyContext |= ProcessPostTraversalForText(
Packit f0b94e
            n, textState, childrenRestyleState, childrenFlags);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We want to update frame pseudo-element styles after we've traversed our
Packit f0b94e
  // kids, because some of those updates (::first-line/::first-letter) need to
Packit f0b94e
  // modify the styles of the kids, and the child traversal above would just
Packit f0b94e
  // clobber those modifications.
Packit f0b94e
  if (styleFrame) {
Packit f0b94e
    if (wasRestyled) {
Packit f0b94e
      // Make sure to update anon boxes and pseudo bits after updating text,
Packit f0b94e
      // otherwise ProcessPostTraversalForText could clobber first-letter
Packit f0b94e
      // styles, for example.
Packit f0b94e
      styleFrame->UpdateStyleOfOwnedAnonBoxes(childrenRestyleState);
Packit f0b94e
    }
Packit f0b94e
    // Process anon box wrapper frames before ::first-line bits, but _after_
Packit f0b94e
    // owned anon boxes, since the children wrapper anon boxes could be
Packit f0b94e
    // inheriting from our own owned anon boxes.
Packit f0b94e
    childrenRestyleState.ProcessWrapperRestyles(styleFrame);
Packit f0b94e
    if (wasRestyled) {
Packit f0b94e
      UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
Packit f0b94e
    } else if (traverseElementChildren &&
Packit f0b94e
               styleFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
Packit f0b94e
      // Even if we were not restyled, if we're a block with a first-line and
Packit f0b94e
      // one of our descendant elements which is on the first line was restyled,
Packit f0b94e
      // we need to update the styles of things on the first line, because
Packit f0b94e
      // they're wrong now.
Packit f0b94e
      //
Packit f0b94e
      // FIXME(bz) Could we do better here?  For example, could we keep track of
Packit f0b94e
      // frames that are "block with a ::first-line so we could avoid
Packit f0b94e
      // IsFrameOfType() and digging about for the first-line frame if not?
Packit f0b94e
      // Could we keep track of whether the element children we actually restyle
Packit f0b94e
      // are affected by first-line?  Something else?  Bug 1385443 tracks making
Packit f0b94e
      // this better.
Packit f0b94e
      nsIFrame* firstLineFrame =
Packit f0b94e
          static_cast<nsBlockFrame*>(styleFrame)->GetFirstLineFrame();
Packit f0b94e
      if (firstLineFrame) {
Packit f0b94e
        for (nsIFrame* kid : firstLineFrame->PrincipalChildList()) {
Packit f0b94e
          ReparentStyleContext(kid);
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  aElement->UnsetFlags(Element::kAllServoDescendantBits);
Packit f0b94e
  return recreatedAnyContext;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool ServoRestyleManager::ProcessPostTraversalForText(
Packit f0b94e
    nsIContent* aTextNode, TextPostTraversalState& aPostTraversalState,
Packit f0b94e
    ServoRestyleState& aRestyleState, ServoPostTraversalFlags aFlags) {
Packit f0b94e
  // Handle lazy frame construction.
Packit f0b94e
  if (aTextNode->HasFlag(NODE_NEEDS_FRAME)) {
Packit f0b94e
    aPostTraversalState.ChangeList().AppendChange(
Packit f0b94e
        nullptr, aTextNode, nsChangeHint_ReconstructFrame);
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Handle restyle.
Packit f0b94e
  nsIFrame* primaryFrame = aTextNode->GetPrimaryFrame();
Packit f0b94e
  if (!primaryFrame) {
Packit f0b94e
    return false;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If the parent wasn't restyled, the styles of our anon box parents won't
Packit f0b94e
  // change either.
Packit f0b94e
  if ((aFlags & ServoPostTraversalFlags::ParentWasRestyled) &&
Packit f0b94e
      primaryFrame->ParentIsWrapperAnonBox()) {
Packit f0b94e
    aRestyleState.AddPendingWrapperRestyle(
Packit f0b94e
        ServoRestyleState::TableAwareParentFor(primaryFrame));
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsStyleContext& newContext = aPostTraversalState.ComputeStyle(aTextNode);
Packit f0b94e
  aPostTraversalState.ComputeHintIfNeeded(aTextNode, primaryFrame, newContext);
Packit f0b94e
Packit f0b94e
  // We want to walk all the continuations here, even the ones with different
Packit f0b94e
  // styles.  In practice, the only reasons we get continuations with different
Packit f0b94e
  // styles are ::first-line and ::first-letter.  But in those cases,
Packit f0b94e
  // newContext is the right context for the _later_ continuations anyway (the
Packit f0b94e
  // ones not affected by ::first-line/::first-letter), not the earlier ones,
Packit f0b94e
  // so there is no point stopping right at the point when we'd actually be
Packit f0b94e
  // setting the right style context.
Packit f0b94e
  //
Packit f0b94e
  // This does mean that we may be setting the wrong style context on our
Packit f0b94e
  // initial continuations; ::first-line/::first-letter fix that up after the
Packit f0b94e
  // fact.
Packit f0b94e
  for (nsIFrame* f = primaryFrame; f; f = f->GetNextContinuation()) {
Packit f0b94e
    f->SetStyleContext(&newContext);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return true;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::ClearSnapshots() {
Packit f0b94e
  for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
Packit f0b94e
    iter.Key()->UnsetFlags(ELEMENT_HAS_SNAPSHOT | ELEMENT_HANDLED_SNAPSHOT);
Packit f0b94e
    iter.Remove();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
ServoElementSnapshot& ServoRestyleManager::SnapshotFor(Element* aElement) {
Packit f0b94e
  MOZ_ASSERT(!mInStyleRefresh);
Packit f0b94e
Packit f0b94e
  // NOTE(emilio): We can handle snapshots from a one-off restyle of those that
Packit f0b94e
  // we do to restyle stuff for reconstruction, for example.
Packit f0b94e
  //
Packit f0b94e
  // It seems to be the case that we always flush in between that happens and
Packit f0b94e
  // the next attribute change, so we can assert that we haven't handled the
Packit f0b94e
  // snapshot here yet. If this assertion didn't hold, we'd need to unset that
Packit f0b94e
  // flag from here too.
Packit f0b94e
  //
Packit f0b94e
  // Can't wait to make ProcessPendingRestyles the only entry-point for styling,
Packit f0b94e
  // so this becomes much easier to reason about. Today is not that day though.
Packit f0b94e
  MOZ_ASSERT(aElement->HasServoData());
Packit f0b94e
  MOZ_ASSERT(!aElement->HasFlag(ELEMENT_HANDLED_SNAPSHOT));
Packit f0b94e
Packit f0b94e
  ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(aElement, aElement);
Packit f0b94e
  aElement->SetFlags(ELEMENT_HAS_SNAPSHOT);
Packit f0b94e
Packit f0b94e
  // Now that we have a snapshot, make sure a restyle is triggered.
Packit f0b94e
  aElement->NoteDirtyForServo();
Packit f0b94e
  return *snapshot;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags) {
Packit f0b94e
  nsPresContext* presContext = PresContext();
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(presContext->Document(), "No document?  Pshaw!");
Packit f0b94e
  // FIXME(emilio): In the "flush animations" case, ideally, we should only
Packit f0b94e
  // recascade animation styles running on the compositor, so we shouldn't care
Packit f0b94e
  // about other styles, or new rules that apply to the page...
Packit f0b94e
  //
Packit f0b94e
  // However, that's not true as of right now, see bug 1388031 and bug 1388692.
Packit f0b94e
  MOZ_ASSERT((aFlags & ServoTraversalFlags::FlushThrottledAnimations) ||
Packit f0b94e
                 !presContext->HasPendingMediaQueryUpdates(),
Packit f0b94e
             "Someone forgot to update media queries?");
Packit f0b94e
  MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
Packit f0b94e
  MOZ_ASSERT(!mInStyleRefresh, "Reentrant call?");
Packit f0b94e
Packit f0b94e
  if (MOZ_UNLIKELY(!presContext->PresShell()->DidInitialize())) {
Packit f0b94e
    // PresShell::FlushPendingNotifications doesn't early-return in the case
Packit f0b94e
    // where the PresShell hasn't yet been initialized (and therefore we haven't
Packit f0b94e
    // yet done the initial style traversal of the DOM tree). We should arguably
Packit f0b94e
    // fix up the callers and assert against this case, but we just detect and
Packit f0b94e
    // handle it for now.
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Create a AnimationsWithDestroyedFrame during restyling process to
Packit f0b94e
  // stop animations and transitions on elements that have no frame at the end
Packit f0b94e
  // of the restyling process.
Packit f0b94e
  AnimationsWithDestroyedFrame animationsWithDestroyedFrame(this);
Packit f0b94e
Packit f0b94e
  ServoStyleSet* styleSet = StyleSet();
Packit f0b94e
  nsIDocument* doc = presContext->Document();
Packit f0b94e
Packit f0b94e
  // Ensure the refresh driver is active during traversal to avoid mutating
Packit f0b94e
  // mActiveTimer and mMostRecentRefresh time.
Packit f0b94e
  presContext->RefreshDriver()->MostRecentRefresh();
Packit f0b94e
Packit f0b94e
  // Perform the Servo traversal, and the post-traversal if required. We do this
Packit f0b94e
  // in a loop because certain rare paths in the frame constructor (like
Packit f0b94e
  // uninstalling XBL bindings) can trigger additional style validations.
Packit f0b94e
  mInStyleRefresh = true;
Packit f0b94e
  if (mHaveNonAnimationRestyles) {
Packit f0b94e
    ++mAnimationGeneration;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (mRestyleForCSSRuleChanges) {
Packit f0b94e
    aFlags |= ServoTraversalFlags::ForCSSRuleChanges;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  while (styleSet->StyleDocument(aFlags)) {
Packit f0b94e
    ClearSnapshots();
Packit f0b94e
Packit f0b94e
    nsStyleChangeList currentChanges(StyleBackendType::Servo);
Packit f0b94e
    bool anyStyleChanged = false;
Packit f0b94e
Packit f0b94e
    // Recreate style contexts, and queue up change hints (which also handle
Packit f0b94e
    // lazy frame construction).
Packit f0b94e
    {
Packit f0b94e
      AutoRestyleTimelineMarker marker(presContext->GetDocShell(), false);
Packit f0b94e
      DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
Packit f0b94e
      while (Element* root = iter.GetNextStyleRoot()) {
Packit f0b94e
        nsTArray<nsIFrame*> wrappersToRestyle;
Packit f0b94e
        ServoRestyleState state(*styleSet, currentChanges, wrappersToRestyle);
Packit f0b94e
        ServoPostTraversalFlags flags = ServoPostTraversalFlags::Empty;
Packit f0b94e
        anyStyleChanged |= ProcessPostTraversal(root, nullptr, state, flags);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    doc->ClearServoRestyleRoot();
Packit f0b94e
Packit f0b94e
    // Process the change hints.
Packit f0b94e
    //
Packit f0b94e
    // Unfortunately, the frame constructor can generate new change hints while
Packit f0b94e
    // processing existing ones. We redirect those into a secondary queue and
Packit f0b94e
    // iterate until there's nothing left.
Packit f0b94e
    {
Packit f0b94e
      AutoTimelineMarker marker(presContext->GetDocShell(),
Packit f0b94e
                                "StylesApplyChanges");
Packit f0b94e
      ReentrantChangeList newChanges;
Packit f0b94e
      mReentrantChanges = &newChanges;
Packit f0b94e
      while (!currentChanges.IsEmpty()) {
Packit f0b94e
        ProcessRestyledFrames(currentChanges);
Packit f0b94e
        MOZ_ASSERT(currentChanges.IsEmpty());
Packit f0b94e
        for (ReentrantChange& change : newChanges) {
Packit f0b94e
          if (!(change.mHint & nsChangeHint_ReconstructFrame) &&
Packit f0b94e
              !change.mContent->GetPrimaryFrame()) {
Packit f0b94e
            // SVG Elements post change hints without ensuring that the primary
Packit f0b94e
            // frame will be there after that (see bug 1366142).
Packit f0b94e
            //
Packit f0b94e
            // Just ignore those, since we can't really process them.
Packit f0b94e
            continue;
Packit f0b94e
          }
Packit f0b94e
          currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
Packit f0b94e
                                      change.mContent, change.mHint);
Packit f0b94e
        }
Packit f0b94e
        newChanges.Clear();
Packit f0b94e
      }
Packit f0b94e
      mReentrantChanges = nullptr;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (anyStyleChanged) {
Packit f0b94e
      // Maybe no styles changed when:
Packit f0b94e
      //
Packit f0b94e
      //  * Only explicit change hints were posted in the first place.
Packit f0b94e
      //  * When an attribute or state change in the content happens not to need
Packit f0b94e
      //    a restyle after all.
Packit f0b94e
      //
Packit f0b94e
      // In any case, we don't need to increment the restyle generation in that
Packit f0b94e
      // case.
Packit f0b94e
      IncrementRestyleGeneration();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  doc->ClearServoRestyleRoot();
Packit f0b94e
Packit f0b94e
  FlushOverflowChangedTracker();
Packit f0b94e
Packit f0b94e
  ClearSnapshots();
Packit f0b94e
  styleSet->AssertTreeIsClean();
Packit f0b94e
  mHaveNonAnimationRestyles = false;
Packit f0b94e
  mRestyleForCSSRuleChanges = false;
Packit f0b94e
  mInStyleRefresh = false;
Packit f0b94e
Packit f0b94e
  // Now that everything has settled, see if we have enough free rule nodes in
Packit f0b94e
  // the tree to warrant sweeping them.
Packit f0b94e
  styleSet->MaybeGCRuleTree();
Packit f0b94e
Packit f0b94e
  // Note: We are in the scope of |animationsWithDestroyedFrame|, so
Packit f0b94e
  //       |mAnimationsWithDestroyedFrame| is still valid.
Packit f0b94e
  MOZ_ASSERT(mAnimationsWithDestroyedFrame);
Packit f0b94e
  mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
static void VerifyFlatTree(const nsIContent& aContent) {
Packit f0b94e
  StyleChildrenIterator iter(&aContent);
Packit f0b94e
Packit f0b94e
  for (auto* content = iter.GetNextChild(); content;
Packit f0b94e
       content = iter.GetNextChild()) {
Packit f0b94e
    MOZ_ASSERT(content->GetFlattenedTreeParentNodeForStyle() == &aContent);
Packit f0b94e
    VerifyFlatTree(*content);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::ProcessPendingRestyles() {
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
  if (auto* root = mPresContext->Document()->GetRootElement()) {
Packit f0b94e
    VerifyFlatTree(*root);
Packit f0b94e
  }
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
  DoProcessPendingRestyles(ServoTraversalFlags::Empty);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::ProcessAllPendingAttributeAndStateInvalidations() {
Packit f0b94e
  if (mSnapshots.IsEmpty()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
  for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
Packit f0b94e
    // Servo data for the element might have been dropped. (e.g. by removing
Packit f0b94e
    // from its document)
Packit f0b94e
    if (iter.Key()->HasFlag(ELEMENT_HAS_SNAPSHOT)) {
Packit f0b94e
      Servo_ProcessInvalidations(StyleSet()->RawSet(), iter.Key(), &mSnapshots);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  ClearSnapshots();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool ServoRestyleManager::HasPendingRestyleAncestor(Element* aElement) const {
Packit f0b94e
  return Servo_HasPendingRestyleAncestor(aElement);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::UpdateOnlyAnimationStyles() {
Packit f0b94e
  bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
Packit f0b94e
  if (!doCSS) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  DoProcessPendingRestyles(ServoTraversalFlags::FlushThrottledAnimations);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
Packit f0b94e
                                              EventStates aChangedBits) {
Packit f0b94e
  MOZ_ASSERT(!mInStyleRefresh);
Packit f0b94e
Packit f0b94e
  if (!aContent->IsElement()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Element* aElement = aContent->AsElement();
Packit f0b94e
  if (!aElement->HasServoData()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  const EventStates kVisitedAndUnvisited =
Packit f0b94e
      NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED;
Packit f0b94e
  if (aChangedBits.HasAllStates(kVisitedAndUnvisited) &&
Packit f0b94e
      !Gecko_VisitedStylesEnabled(aElement->OwnerDoc())) {
Packit f0b94e
    aChangedBits &= ~kVisitedAndUnvisited;
Packit f0b94e
    if (aChangedBits.IsEmpty()) {
Packit f0b94e
      return;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsChangeHint changeHint;
Packit f0b94e
  ContentStateChangedInternal(aElement, aChangedBits, &changeHint);
Packit f0b94e
Packit f0b94e
  // Don't bother taking a snapshot if no rules depend on these state bits.
Packit f0b94e
  //
Packit f0b94e
  // We always take a snapshot for the LTR/RTL event states, since Servo doesn't
Packit f0b94e
  // track those bits in the same way, and we know that :dir() rules are always
Packit f0b94e
  // present in UA style sheets.
Packit f0b94e
  if (!aChangedBits.HasAtLeastOneOfStates(DIRECTION_STATES) &&
Packit f0b94e
      !StyleSet()->HasStateDependency(*aElement, aChangedBits)) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  ServoElementSnapshot& snapshot = SnapshotFor(aElement);
Packit f0b94e
  EventStates previousState = aElement->StyleState() ^ aChangedBits;
Packit f0b94e
  snapshot.AddState(previousState);
Packit f0b94e
Packit f0b94e
  if (changeHint) {
Packit f0b94e
    Servo_NoteExplicitHints(aElement, nsRestyleHint(0), changeHint);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Assuming we need to invalidate cached style in getComputedStyle for
Packit f0b94e
  // undisplayed elements, since we don't know if it is needed.
Packit f0b94e
  IncrementUndisplayedRestyleGeneration();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static inline bool AttributeInfluencesOtherPseudoClassState(
Packit f0b94e
    const Element& aElement, const nsAtom* aAttribute) {
Packit f0b94e
  // We must record some state for :-moz-browser-frame and
Packit f0b94e
  // :-moz-table-border-nonzero.
Packit f0b94e
  if (aAttribute == nsGkAtoms::mozbrowser) {
Packit f0b94e
    return aElement.IsAnyOfHTMLElements(nsGkAtoms::iframe, nsGkAtoms::frame);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aAttribute == nsGkAtoms::border) {
Packit f0b94e
    return aElement.IsHTMLElement(nsGkAtoms::table);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return false;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static inline bool NeedToRecordAttrChange(
Packit f0b94e
    const ServoStyleSet& aStyleSet, const Element& aElement,
Packit f0b94e
    int32_t aNameSpaceID, nsAtom* aAttribute,
Packit f0b94e
    bool* aInfluencesOtherPseudoClassState) {
Packit f0b94e
  *aInfluencesOtherPseudoClassState =
Packit f0b94e
      AttributeInfluencesOtherPseudoClassState(aElement, aAttribute);
Packit f0b94e
Packit f0b94e
  // If the attribute influences one of the pseudo-classes that are backed by
Packit f0b94e
  // attributes, we just record it.
Packit f0b94e
  if (*aInfluencesOtherPseudoClassState) {
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We assume that id and class attributes are used in class/id selectors, and
Packit f0b94e
  // thus record them.
Packit f0b94e
  //
Packit f0b94e
  // TODO(emilio): We keep a filter of the ids in use somewhere in the StyleSet,
Packit f0b94e
  // presumably we could try to filter the old and new id, but it's not clear
Packit f0b94e
  // it's worth it.
Packit f0b94e
  if (aNameSpaceID == kNameSpaceID_None &&
Packit f0b94e
      (aAttribute == nsGkAtoms::id || aAttribute == nsGkAtoms::_class)) {
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We always record lang="", even though we force a subtree restyle when it
Packit f0b94e
  // changes, since it can change how its siblings match :lang(..) due to
Packit f0b94e
  // selectors like :lang(..) + div.
Packit f0b94e
  if (aAttribute == nsGkAtoms::lang) {
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Otherwise, just record the attribute change if a selector in the page may
Packit f0b94e
  // reference it from an attribute selector.
Packit f0b94e
  return aStyleSet.MightHaveAttributeDependency(aElement, aAttribute);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::AttributeWillChange(Element* aElement,
Packit f0b94e
                                              int32_t aNameSpaceID,
Packit f0b94e
                                              nsAtom* aAttribute,
Packit f0b94e
                                              int32_t aModType,
Packit f0b94e
                                              const nsAttrValue* aNewValue) {
Packit f0b94e
  TakeSnapshotForAttributeChange(aElement, aNameSpaceID, aAttribute);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::ClassAttributeWillBeChangedBySMIL(Element* aElement) {
Packit f0b94e
  TakeSnapshotForAttributeChange(aElement, kNameSpaceID_None,
Packit f0b94e
                                 nsGkAtoms::_class);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::TakeSnapshotForAttributeChange(Element* aElement,
Packit f0b94e
                                                         int32_t aNameSpaceID,
Packit f0b94e
                                                         nsAtom* aAttribute) {
Packit f0b94e
  MOZ_ASSERT(!mInStyleRefresh);
Packit f0b94e
Packit f0b94e
  if (!aElement->HasServoData()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool influencesOtherPseudoClassState;
Packit f0b94e
  if (!NeedToRecordAttrChange(*StyleSet(), *aElement, aNameSpaceID, aAttribute,
Packit f0b94e
                              &influencesOtherPseudoClassState)) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We cannot tell if the attribute change will affect the styles of
Packit f0b94e
  // undisplayed elements, because we don't actually restyle those elements
Packit f0b94e
  // during the restyle traversal. So just assume that the attribute change can
Packit f0b94e
  // cause the style to change.
Packit f0b94e
  IncrementUndisplayedRestyleGeneration();
Packit f0b94e
Packit f0b94e
  // Some other random attribute changes may also affect the transitions,
Packit f0b94e
  // so we also set this true here.
Packit f0b94e
  mHaveNonAnimationRestyles = true;
Packit f0b94e
Packit f0b94e
  ServoElementSnapshot& snapshot = SnapshotFor(aElement);
Packit f0b94e
  snapshot.AddAttrs(aElement, aNameSpaceID, aAttribute);
Packit f0b94e
Packit f0b94e
  if (influencesOtherPseudoClassState) {
Packit f0b94e
    snapshot.AddOtherPseudoClassState(aElement);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// For some attribute changes we must restyle the whole subtree:
Packit f0b94e
//
Packit f0b94e
// *  is affected by the cellpadding on its ancestor table
Packit f0b94e
// * lwtheme and lwthemetextcolor on root element of XUL document
Packit f0b94e
//   affects all descendants due to :-moz-lwtheme* pseudo-classes
Packit f0b94e
// * lang="" and xml:lang="" can affect all descendants due to :lang()
Packit f0b94e
//
Packit f0b94e
static inline bool AttributeChangeRequiresSubtreeRestyle(
Packit f0b94e
    const Element& aElement, nsAtom* aAttr) {
Packit f0b94e
  if (aAttr == nsGkAtoms::cellpadding) {
Packit f0b94e
    return aElement.IsHTMLElement(nsGkAtoms::table);
Packit f0b94e
  }
Packit f0b94e
  if (aAttr == nsGkAtoms::lwtheme || aAttr == nsGkAtoms::lwthemetextcolor) {
Packit f0b94e
    return aElement.GetNameSpaceID() == kNameSpaceID_XUL &&
Packit f0b94e
           &aElement == aElement.OwnerDoc()->GetRootElement();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return aAttr == nsGkAtoms::lang;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::AttributeChanged(Element* aElement,
Packit f0b94e
                                           int32_t aNameSpaceID,
Packit f0b94e
                                           nsAtom* aAttribute, int32_t aModType,
Packit f0b94e
                                           const nsAttrValue* aOldValue) {
Packit f0b94e
  MOZ_ASSERT(!mInStyleRefresh);
Packit f0b94e
Packit f0b94e
  auto changeHint = nsChangeHint(0);
Packit f0b94e
  auto restyleHint = nsRestyleHint(0);
Packit f0b94e
Packit f0b94e
  changeHint |= aElement->GetAttributeChangeHint(aAttribute, aModType);
Packit f0b94e
Packit f0b94e
  if (aAttribute == nsGkAtoms::style) {
Packit f0b94e
    restyleHint |= eRestyle_StyleAttribute;
Packit f0b94e
  } else if (AttributeChangeRequiresSubtreeRestyle(*aElement, aAttribute)) {
Packit f0b94e
    restyleHint |= eRestyle_Subtree;
Packit f0b94e
  } else if (aElement->IsAttributeMapped(aAttribute)) {
Packit f0b94e
    restyleHint |= eRestyle_Self;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (nsIFrame* primaryFrame = aElement->GetPrimaryFrame()) {
Packit f0b94e
    // See if we have appearance information for a theme.
Packit f0b94e
    const nsStyleDisplay* disp = primaryFrame->StyleDisplay();
Packit f0b94e
    if (disp->mAppearance) {
Packit f0b94e
      nsITheme* theme = PresContext()->GetTheme();
Packit f0b94e
      if (theme && theme->ThemeSupportsWidget(PresContext(), primaryFrame,
Packit f0b94e
                                              disp->mAppearance)) {
Packit f0b94e
        bool repaint = false;
Packit f0b94e
        theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute,
Packit f0b94e
                                  &repaint, aOldValue);
Packit f0b94e
        if (repaint) {
Packit f0b94e
          changeHint |= nsChangeHint_RepaintFrame;
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (restyleHint || changeHint) {
Packit f0b94e
    Servo_NoteExplicitHints(aElement, restyleHint, changeHint);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (restyleHint) {
Packit f0b94e
    // Assuming we need to invalidate cached style in getComputedStyle for
Packit f0b94e
    // undisplayed elements, since we don't know if it is needed.
Packit f0b94e
    IncrementUndisplayedRestyleGeneration();
Packit f0b94e
Packit f0b94e
    // If we change attributes, we have to mark this to be true, so we will
Packit f0b94e
    // increase the animation generation for the new created transition if any.
Packit f0b94e
    mHaveNonAnimationRestyles = true;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame) {
Packit f0b94e
// This is only called when moving frames in or out of the first-line
Packit f0b94e
// pseudo-element (or one of its descendants).  We can't say much about
Packit f0b94e
// aFrame's ancestors, unfortunately (e.g. during a dynamic insert into
Packit f0b94e
// something inside an inline-block on the first line the ancestors could be
Packit f0b94e
// totally arbitrary), but we will definitely find a line frame on the
Packit f0b94e
// ancestor chain.  Note that the lineframe may not actually be the one that
Packit f0b94e
// corresponds to ::first-line; when we're moving _out_ of the ::first-line it
Packit f0b94e
// will be one of the continuations instead.
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
  {
Packit f0b94e
    nsIFrame* f = aFrame->GetParent();
Packit f0b94e
    while (f && !f->IsLineFrame()) {
Packit f0b94e
      f = f->GetParent();
Packit f0b94e
    }
Packit f0b94e
    MOZ_ASSERT(f, "Must have found a first-line frame");
Packit f0b94e
  }
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
  DoReparentStyleContext(aFrame, *StyleSet());
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::DoReparentStyleContext(nsIFrame* aFrame,
Packit f0b94e
                                                 ServoStyleSet& aStyleSet) {
Packit f0b94e
  if (aFrame->IsBackdropFrame()) {
Packit f0b94e
    // Style context of backdrop frame has no parent style context, and
Packit f0b94e
    // thus we do not need to reparent it.
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aFrame->IsPlaceholderFrame()) {
Packit f0b94e
    // Also reparent the out-of-flow and all its continuations.  We're doing
Packit f0b94e
    // this to match Gecko for now, but it's not clear that this behavior is
Packit f0b94e
    // correct per spec.  It's certainly pretty odd for out-of-flows whose
Packit f0b94e
    // containing block is not within the first line.
Packit f0b94e
    //
Packit f0b94e
    // Right now we're somewhat inconsistent in this testcase:
Packit f0b94e
    //
Packit f0b94e
    //  <style>
Packit f0b94e
    //    div { color: orange; clear: left; }
Packit f0b94e
    //    div::first-line { color: blue; }
Packit f0b94e
    //  </style>
Packit f0b94e
    //  
Packit f0b94e
    //    What color is this text?
Packit f0b94e
    //  
Packit f0b94e
    //  
Packit f0b94e
    //    What color is this text?
Packit f0b94e
    //  
Packit f0b94e
    //
Packit f0b94e
    // We make the first float orange and the second float blue.  On the other
Packit f0b94e
    // hand, if the float were within an inline-block that was on the first
Packit f0b94e
    // line, arguably it _should_ inherit from the ::first-line...
Packit f0b94e
    nsIFrame* outOfFlow =
Packit f0b94e
        nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
Packit f0b94e
    MOZ_ASSERT(outOfFlow, "no out-of-flow frame");
Packit f0b94e
    for (; outOfFlow; outOfFlow = outOfFlow->GetNextContinuation()) {
Packit f0b94e
      DoReparentStyleContext(outOfFlow, aStyleSet);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsIFrame* providerFrame;
Packit f0b94e
  nsStyleContext* newParentContext =
Packit f0b94e
      aFrame->GetParentStyleContext(&providerFrame);
Packit f0b94e
  // If our provider is our child, we want to reparent it first, because we
Packit f0b94e
  // inherit style from it.
Packit f0b94e
  bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
Packit f0b94e
  nsIFrame* providerChild = nullptr;
Packit f0b94e
  if (isChild) {
Packit f0b94e
    DoReparentStyleContext(providerFrame, aStyleSet);
Packit f0b94e
    // Get the style context again after ReparentStyleContext() which might have
Packit f0b94e
    // changed it.
Packit f0b94e
    newParentContext = providerFrame->StyleContext();
Packit f0b94e
    providerChild = providerFrame;
Packit f0b94e
    MOZ_ASSERT(!providerFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
Packit f0b94e
               "Out of flow provider?");
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!newParentContext) {
Packit f0b94e
    // No need to do anything here for this frame, but we should still reparent
Packit f0b94e
    // its descendants, because those may have styles that inherit from the
Packit f0b94e
    // parent of this frame (e.g. non-anonymous columns in an anonymous
Packit f0b94e
    // colgroup).
Packit f0b94e
    MOZ_ASSERT(aFrame->StyleContext()->IsNonInheritingAnonBox(),
Packit f0b94e
               "Why did this frame not end up with a parent context?");
Packit f0b94e
    ReparentFrameDescendants(aFrame, providerChild, aStyleSet);
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool isElement = aFrame->GetContent()->IsElement();
Packit f0b94e
Packit f0b94e
  // We probably don't want to initiate transitions from
Packit f0b94e
  // ReparentStyleContext, since we call it during frame
Packit f0b94e
  // construction rather than in response to dynamic changes.
Packit f0b94e
  // Also see the comment at the start of
Packit f0b94e
  // nsTransitionManager::ConsiderInitiatingTransition.
Packit f0b94e
  //
Packit f0b94e
  // We don't try to do the fancy copying from previous continuations that
Packit f0b94e
  // GeckoRestyleManager does here, because that relies on knowing the parents
Packit f0b94e
  // of style contexts, and we don't know those.
Packit f0b94e
  ServoStyleContext* oldContext = aFrame->StyleContext()->AsServo();
Packit f0b94e
  Element* ourElement =
Packit f0b94e
      oldContext->GetPseudoType() == CSSPseudoElementType::NotPseudo &&
Packit f0b94e
              isElement
Packit f0b94e
          ? aFrame->GetContent()->AsElement()
Packit f0b94e
          : nullptr;
Packit f0b94e
  ServoStyleContext* newParent = newParentContext->AsServo();
Packit f0b94e
Packit f0b94e
  ServoStyleContext* newParentIgnoringFirstLine;
Packit f0b94e
  if (newParent->GetPseudoType() == CSSPseudoElementType::firstLine) {
Packit f0b94e
    MOZ_ASSERT(providerFrame && providerFrame->GetParent()->IsFrameOfType(
Packit f0b94e
                                    nsIFrame::eBlockFrame),
Packit f0b94e
               "How could we get a ::first-line parent style without having "
Packit f0b94e
               "a ::first-line provider frame?");
Packit f0b94e
    // If newParent is a ::first-line style, get the parent blockframe, and then
Packit f0b94e
    // correct it for our pseudo as needed (e.g. stepping out of anon boxes).
Packit f0b94e
    // Use the resulting style for the "parent style ignoring ::first-line".
Packit f0b94e
    nsIFrame* blockFrame = providerFrame->GetParent();
Packit f0b94e
    nsIFrame* correctedFrame =
Packit f0b94e
        nsFrame::CorrectStyleParentFrame(blockFrame, oldContext->GetPseudo());
Packit f0b94e
    newParentIgnoringFirstLine = correctedFrame->StyleContext()->AsServo();
Packit f0b94e
  } else {
Packit f0b94e
    newParentIgnoringFirstLine = newParent;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!providerFrame) {
Packit f0b94e
    // No providerFrame means we inherited from a display:contents thing.  Our
Packit f0b94e
    // layout parent style is the style of our nearest ancestor frame.  But we
Packit f0b94e
    // have to be careful to do that with our placeholder, not with us, if we're
Packit f0b94e
    // out of flow.
Packit f0b94e
    if (aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
Packit f0b94e
      aFrame->GetPlaceholderFrame()->GetLayoutParentStyleForOutOfFlow(
Packit f0b94e
          &providerFrame);
Packit f0b94e
    } else {
Packit f0b94e
      providerFrame = nsFrame::CorrectStyleParentFrame(aFrame->GetParent(),
Packit f0b94e
                                                       oldContext->GetPseudo());
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  ServoStyleContext* layoutParent = providerFrame->StyleContext()->AsServo();
Packit f0b94e
Packit f0b94e
  RefPtr<ServoStyleContext> newContext = aStyleSet.ReparentStyleContext(
Packit f0b94e
      oldContext, newParent, newParentIgnoringFirstLine, layoutParent,
Packit f0b94e
      ourElement);
Packit f0b94e
  aFrame->SetStyleContext(newContext);
Packit f0b94e
Packit f0b94e
  // This logic somewhat mirrors the logic in
Packit f0b94e
  // ServoRestyleManager::ProcessPostTraversal.
Packit f0b94e
  if (isElement) {
Packit f0b94e
    // We can't use UpdateAdditionalStyleContexts as-is because it needs a
Packit f0b94e
    // ServoRestyleState and maintaining one of those during a _frametree_
Packit f0b94e
    // traversal is basically impossible.
Packit f0b94e
    uint32_t index = 0;
Packit f0b94e
    while (nsStyleContext* oldAdditionalContext =
Packit f0b94e
               aFrame->GetAdditionalStyleContext(index)) {
Packit f0b94e
      RefPtr<ServoStyleContext> newAdditionalContext =
Packit f0b94e
          aStyleSet.ReparentStyleContext(oldAdditionalContext->AsServo(),
Packit f0b94e
                                         newContext, newContext, newContext,
Packit f0b94e
                                         nullptr);
Packit f0b94e
      aFrame->SetAdditionalStyleContext(index, newAdditionalContext);
Packit f0b94e
      ++index;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Generally, owned anon boxes are our descendants.  The only exceptions are
Packit f0b94e
  // tables (for the table wrapper) and inline frames (for the block part of the
Packit f0b94e
  // block-in-inline split).  We're going to update our descendants when looping
Packit f0b94e
  // over kids, and we don't want to update the block part of a block-in-inline
Packit f0b94e
  // split if the inline is on the first line but the block is not (and if the
Packit f0b94e
  // block is, it's the child of something else on the first line and will get
Packit f0b94e
  // updated as a child).  And given how this method ends up getting called, if
Packit f0b94e
  // we reach here for a table frame, we are already in the middle of
Packit f0b94e
  // reparenting the table wrapper frame.  So no need to
Packit f0b94e
  // UpdateStyleOfOwnedAnonBoxes() here.
Packit f0b94e
Packit f0b94e
  ReparentFrameDescendants(aFrame, providerChild, aStyleSet);
Packit f0b94e
Packit f0b94e
  // We do not need to do the equivalent of UpdateFramePseudoElementStyles,
Packit f0b94e
  // because those are hadled by our descendant walk.
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ServoRestyleManager::ReparentFrameDescendants(nsIFrame* aFrame,
Packit f0b94e
                                                   nsIFrame* aProviderChild,
Packit f0b94e
                                                   ServoStyleSet& aStyleSet) {
Packit f0b94e
  nsIFrame::ChildListIterator lists(aFrame);
Packit f0b94e
  for (; !lists.IsDone(); lists.Next()) {
Packit f0b94e
    for (nsIFrame* child : lists.CurrentList()) {
Packit f0b94e
      // only do frames that are in flow
Packit f0b94e
      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
Packit f0b94e
          child != aProviderChild) {
Packit f0b94e
        DoReparentStyleContext(child, aStyleSet);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace mozilla