forked from mirrors/gecko-dev
		
	The main renaming was generated with the following python script:
```
import sys
import re
CAMEL_CASE_REGEX = re.compile(r"(^|_|-)([A-Z])([A-Z]+)")
DISPLAY_REGEX = re.compile(r"\bNS_STYLE_DISPLAY_([^M][A-Z_]+)\b")
def to_camel_case(ident):
  return re.sub(CAMEL_CASE_REGEX,
                lambda m: m.group(2) + m.group(3).lower(), ident)
def constant_to_enum(constant):
  return "StyleDisplay::" + to_camel_case(constant) + ("_" if constant == "NONE" else "")
def process_line(line):
  return re.sub(DISPLAY_REGEX,
                lambda m: constant_to_enum(m.group(1)), line)
lines = []
with open(sys.argv[1], "r") as f:
  for line in f:
    lines.append(process_line(line))
with open(sys.argv[1], "w") as f:
  for line in lines:
    f.write(line)
```
And the following shell commands:
```
find . -name '*.cpp' -exec python display.py {} \;
find . -name '*.h' -exec python display.py {} \;
```
MozReview-Commit-ID: 91xYCbLC2Vf
		
	
			
		
			
				
	
	
		
			3974 lines
		
	
	
	
		
			157 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			3974 lines
		
	
	
	
		
			157 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
/**
 | 
						|
 * Code responsible for managing style changes: tracking what style
 | 
						|
 * changes need to happen, scheduling them, and doing them.
 | 
						|
 */
 | 
						|
 | 
						|
#include "mozilla/RestyleManager.h"
 | 
						|
 | 
						|
#include <algorithm> // For std::max
 | 
						|
#include "mozilla/EffectSet.h"
 | 
						|
#include "mozilla/EventStates.h"
 | 
						|
#include "nsLayoutUtils.h"
 | 
						|
#include "AnimationCommon.h" // For GetLayerAnimationInfo
 | 
						|
#include "FrameLayerBuilder.h"
 | 
						|
#include "GeckoProfiler.h"
 | 
						|
#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
 | 
						|
#include "nsAutoPtr.h"
 | 
						|
#include "nsStyleChangeList.h"
 | 
						|
#include "nsRuleProcessorData.h"
 | 
						|
#include "nsStyleSet.h"
 | 
						|
#include "nsStyleUtil.h"
 | 
						|
#include "nsCSSFrameConstructor.h"
 | 
						|
#include "nsSVGEffects.h"
 | 
						|
#include "nsCSSPseudoElements.h"
 | 
						|
#include "nsCSSRendering.h"
 | 
						|
#include "nsAnimationManager.h"
 | 
						|
#include "nsTransitionManager.h"
 | 
						|
#include "nsViewManager.h"
 | 
						|
#include "nsRenderingContext.h"
 | 
						|
#include "nsSVGIntegrationUtils.h"
 | 
						|
#include "nsCSSAnonBoxes.h"
 | 
						|
#include "nsContainerFrame.h"
 | 
						|
#include "nsPlaceholderFrame.h"
 | 
						|
#include "nsBlockFrame.h"
 | 
						|
#include "nsViewportFrame.h"
 | 
						|
#include "SVGTextFrame.h"
 | 
						|
#include "StickyScrollContainer.h"
 | 
						|
#include "nsIRootBox.h"
 | 
						|
#include "nsIDOMMutationEvent.h"
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsIFrameInlines.h"
 | 
						|
#include "ActiveLayerTracker.h"
 | 
						|
#include "nsDisplayList.h"
 | 
						|
#include "RestyleTrackerInlines.h"
 | 
						|
#include "nsSMILAnimationController.h"
 | 
						|
#include "nsCSSRuleProcessor.h"
 | 
						|
#include "ChildIterator.h"
 | 
						|
#include "Layers.h"
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
#include "nsAccessibilityService.h"
 | 
						|
#endif
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
 | 
						|
using namespace layers;
 | 
						|
using namespace dom;
 | 
						|
 | 
						|
#define LOG_RESTYLE_CONTINUE(reason_, ...) \
 | 
						|
  LOG_RESTYLE("continuing restyle since " reason_, ##__VA_ARGS__)
 | 
						|
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
static nsCString
 | 
						|
FrameTagToString(const nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  nsCString result;
 | 
						|
  aFrame->ListTag(result);
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
static nsCString
 | 
						|
ElementTagToString(dom::Element* aElement)
 | 
						|
{
 | 
						|
  nsCString result;
 | 
						|
  nsDependentAtomString buf(aElement->NodeInfo()->NameAtom());
 | 
						|
  result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
 | 
						|
  return result;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
RestyleManager::RestyleManager(nsPresContext* aPresContext)
 | 
						|
  : RestyleManagerBase(aPresContext)
 | 
						|
  , mDoRebuildAllStyleData(false)
 | 
						|
  , mInRebuildAllStyleData(false)
 | 
						|
  , mSkipAnimationRules(false)
 | 
						|
  , mHavePendingNonAnimationRestyles(false)
 | 
						|
  , mRebuildAllExtraHint(nsChangeHint(0))
 | 
						|
  , mRebuildAllRestyleHint(nsRestyleHint(0))
 | 
						|
  , mAnimationGeneration(0)
 | 
						|
  , mReframingStyleContexts(nullptr)
 | 
						|
  , mAnimationsWithDestroyedFrame(nullptr)
 | 
						|
  , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
 | 
						|
                     ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
 | 
						|
                     ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)
 | 
						|
  , mIsProcessingRestyles(false)
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
  , mLoggingDepth(0)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  mPendingRestyles.Init(this);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::RestyleElement(Element*               aElement,
 | 
						|
                               nsIFrame*              aPrimaryFrame,
 | 
						|
                               nsChangeHint           aMinHint,
 | 
						|
                               RestyleTracker&        aRestyleTracker,
 | 
						|
                               nsRestyleHint          aRestyleHint,
 | 
						|
                               const RestyleHintData& aRestyleHintData)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
 | 
						|
  NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(),
 | 
						|
               "frame/content mismatch");
 | 
						|
  if (aPrimaryFrame && aPrimaryFrame->GetContent() != aElement) {
 | 
						|
    // XXXbz this is due to image maps messing with the primary frame pointer
 | 
						|
    // of <area>s.  See bug 135040.  We can remove this block once that's fixed.
 | 
						|
    aPrimaryFrame = nullptr;
 | 
						|
  }
 | 
						|
  NS_ASSERTION(!aPrimaryFrame || aPrimaryFrame->GetContent() == aElement,
 | 
						|
               "frame/content mismatch");
 | 
						|
 | 
						|
  // If we're restyling the root element and there are 'rem' units in
 | 
						|
  // use, handle dynamic changes to the definition of a 'rem' here.
 | 
						|
  if (PresContext()->UsesRootEMUnits() && aPrimaryFrame &&
 | 
						|
      !mInRebuildAllStyleData) {
 | 
						|
    nsStyleContext* oldContext = aPrimaryFrame->StyleContext();
 | 
						|
    if (!oldContext->GetParent()) { // check that we're the root element
 | 
						|
      RefPtr<nsStyleContext> newContext = StyleSet()->
 | 
						|
        ResolveStyleFor(aElement, nullptr /* == oldContext->GetParent() */);
 | 
						|
      if (oldContext->StyleFont()->mFont.size !=
 | 
						|
          newContext->StyleFont()->mFont.size) {
 | 
						|
        // The basis for 'rem' units has changed.
 | 
						|
        mRebuildAllRestyleHint |= aRestyleHint;
 | 
						|
        if (aRestyleHint & eRestyle_SomeDescendants) {
 | 
						|
          mRebuildAllRestyleHint |= eRestyle_Subtree;
 | 
						|
        }
 | 
						|
        mRebuildAllExtraHint |= aMinHint;
 | 
						|
        StartRebuildAllStyleData(aRestyleTracker);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (aMinHint & nsChangeHint_ReconstructFrame) {
 | 
						|
    FrameConstructor()->RecreateFramesForContent(aElement, false,
 | 
						|
      nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
 | 
						|
  } else if (aPrimaryFrame) {
 | 
						|
    ComputeAndProcessStyleChange(aPrimaryFrame, aMinHint, aRestyleTracker,
 | 
						|
                                 aRestyleHint, aRestyleHintData);
 | 
						|
  } else if (aRestyleHint & ~eRestyle_LaterSiblings) {
 | 
						|
    // We're restyling an element with no frame, so we should try to
 | 
						|
    // make one if its new style says it should have one.  But in order
 | 
						|
    // to try to honor the restyle hint (which we'd like to do so that,
 | 
						|
    // for example, an animation-only style flush doesn't flush other
 | 
						|
    // buffered style changes), we only do this if the restyle hint says
 | 
						|
    // we have *some* restyling for this frame.  This means we'll
 | 
						|
    // potentially get ahead of ourselves in that case, but not as much
 | 
						|
    // as we would if we didn't check the restyle hint.
 | 
						|
    nsStyleContext* newContext =
 | 
						|
      FrameConstructor()->MaybeRecreateFramesForElement(aElement);
 | 
						|
    if (newContext &&
 | 
						|
        newContext->StyleDisplay()->mDisplay == StyleDisplay::Contents) {
 | 
						|
      // Style change for a display:contents node that did not recreate frames.
 | 
						|
      ComputeAndProcessStyleChange(newContext, aElement, aMinHint,
 | 
						|
                                   aRestyleTracker, aRestyleHint,
 | 
						|
                                   aRestyleHintData);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
RestyleManager::ReframingStyleContexts::ReframingStyleContexts(
 | 
						|
                                          RestyleManager* aRestyleManager)
 | 
						|
  : mRestyleManager(aRestyleManager)
 | 
						|
  , mRestorePointer(mRestyleManager->mReframingStyleContexts)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!mRestyleManager->mReframingStyleContexts,
 | 
						|
             "shouldn't construct recursively");
 | 
						|
  mRestyleManager->mReframingStyleContexts = this;
 | 
						|
}
 | 
						|
 | 
						|
RestyleManager::ReframingStyleContexts::~ReframingStyleContexts()
 | 
						|
{
 | 
						|
  // Before we go away, we need to flush out any frame construction that
 | 
						|
  // was enqueued, so that we start transitions.
 | 
						|
  // Note that this is a little bit evil in that we're calling into code
 | 
						|
  // that calls our member functions from our destructor, but it's at
 | 
						|
  // the beginning of our destructor, so it shouldn't be too bad.
 | 
						|
  mRestyleManager->PresContext()->FrameConstructor()->CreateNeededFrames();
 | 
						|
}
 | 
						|
 | 
						|
RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
 | 
						|
                                          RestyleManager* aRestyleManager)
 | 
						|
  : mRestyleManager(aRestyleManager)
 | 
						|
  , mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
 | 
						|
             "shouldn't construct recursively");
 | 
						|
  mRestyleManager->mAnimationsWithDestroyedFrame = this;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsForElementsWithoutFrames()
 | 
						|
{
 | 
						|
  StopAnimationsWithoutFrame(mContents, CSSPseudoElementType::NotPseudo);
 | 
						|
  StopAnimationsWithoutFrame(mBeforeContents, CSSPseudoElementType::before);
 | 
						|
  StopAnimationsWithoutFrame(mAfterContents, CSSPseudoElementType::after);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame(
 | 
						|
  nsTArray<RefPtr<nsIContent>>& aArray,
 | 
						|
  CSSPseudoElementType aPseudoType)
 | 
						|
{
 | 
						|
  nsAnimationManager* animationManager =
 | 
						|
    mRestyleManager->PresContext()->AnimationManager();
 | 
						|
  nsTransitionManager* transitionManager =
 | 
						|
    mRestyleManager->PresContext()->TransitionManager();
 | 
						|
  for (nsIContent* content : aArray) {
 | 
						|
    if (content->GetPrimaryFrame()) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    dom::Element* element = content->AsElement();
 | 
						|
 | 
						|
    animationManager->StopAnimationsForElement(element, aPseudoType);
 | 
						|
    transitionManager->StopTransitionsForElement(element, aPseudoType);
 | 
						|
 | 
						|
    // All other animations should keep running but not running on the
 | 
						|
    // *compositor* at this point.
 | 
						|
    EffectSet* effectSet = EffectSet::GetEffectSet(element, aPseudoType);
 | 
						|
    if (effectSet) {
 | 
						|
      for (KeyframeEffectReadOnly* effect : *effectSet) {
 | 
						|
        effect->ResetIsRunningOnCompositor();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline dom::Element*
 | 
						|
ElementForStyleContext(nsIContent* aParentContent,
 | 
						|
                       nsIFrame* aFrame,
 | 
						|
                       CSSPseudoElementType aPseudoType);
 | 
						|
 | 
						|
// Forwarded nsIDocumentObserver method, to handle restyling (and
 | 
						|
// passing the notification to the frame).
 | 
						|
nsresult
 | 
						|
RestyleManager::ContentStateChanged(nsIContent* aContent,
 | 
						|
                                    EventStates aStateMask)
 | 
						|
{
 | 
						|
  // XXXbz it would be good if this function only took Elements, but
 | 
						|
  // we'd have to make ESM guarantee that usefully.
 | 
						|
  if (!aContent->IsElement()) {
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  Element* aElement = aContent->AsElement();
 | 
						|
 | 
						|
  nsChangeHint changeHint;
 | 
						|
  nsRestyleHint restyleHint;
 | 
						|
  ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
 | 
						|
 | 
						|
  PostRestyleEvent(aElement, restyleHint, changeHint);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
// Forwarded nsIMutationObserver method, to handle restyling.
 | 
						|
void
 | 
						|
RestyleManager::AttributeWillChange(Element* aElement,
 | 
						|
                                    int32_t aNameSpaceID,
 | 
						|
                                    nsIAtom* aAttribute,
 | 
						|
                                    int32_t aModType,
 | 
						|
                                    const nsAttrValue* aNewValue)
 | 
						|
{
 | 
						|
  RestyleHintData rsdata;
 | 
						|
  nsRestyleHint rshint =
 | 
						|
    StyleSet()->HasAttributeDependentStyle(aElement,
 | 
						|
                                           aNameSpaceID,
 | 
						|
                                           aAttribute,
 | 
						|
                                           aModType,
 | 
						|
                                           false,
 | 
						|
                                           aNewValue,
 | 
						|
                                           rsdata);
 | 
						|
  PostRestyleEvent(aElement, rshint, nsChangeHint(0), &rsdata);
 | 
						|
}
 | 
						|
 | 
						|
// Forwarded nsIMutationObserver method, to handle restyling (and
 | 
						|
// passing the notification to the frame).
 | 
						|
void
 | 
						|
RestyleManager::AttributeChanged(Element* aElement,
 | 
						|
                                 int32_t aNameSpaceID,
 | 
						|
                                 nsIAtom* aAttribute,
 | 
						|
                                 int32_t aModType,
 | 
						|
                                 const nsAttrValue* aOldValue)
 | 
						|
{
 | 
						|
  // Hold onto the PresShell to prevent ourselves from being destroyed.
 | 
						|
  // XXXbz how, exactly, would this attribute change cause us to be
 | 
						|
  // destroyed from inside this function?
 | 
						|
  nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
 | 
						|
 | 
						|
  // Get the frame associated with the content which is the highest in the frame tree
 | 
						|
  nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
 | 
						|
 | 
						|
#if 0
 | 
						|
  NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
 | 
						|
     ("RestyleManager::AttributeChanged: content=%p[%s] frame=%p",
 | 
						|
      aContent, ContentTag(aElement, 0), frame));
 | 
						|
#endif
 | 
						|
 | 
						|
  // the style tag has its own interpretation based on aHint
 | 
						|
  nsChangeHint hint = aElement->GetAttributeChangeHint(aAttribute, aModType);
 | 
						|
 | 
						|
  bool reframe = (hint & nsChangeHint_ReconstructFrame) != 0;
 | 
						|
 | 
						|
#ifdef MOZ_XUL
 | 
						|
  // The following listbox widget trap prevents offscreen listbox widget
 | 
						|
  // content from being removed and re-inserted (which is what would
 | 
						|
  // happen otherwise).
 | 
						|
  if (!primaryFrame && !reframe) {
 | 
						|
    int32_t namespaceID;
 | 
						|
    nsIAtom* tag = PresContext()->Document()->BindingManager()->
 | 
						|
                     ResolveTag(aElement, &namespaceID);
 | 
						|
 | 
						|
    if (namespaceID == kNameSpaceID_XUL &&
 | 
						|
        (tag == nsGkAtoms::listitem ||
 | 
						|
         tag == nsGkAtoms::listcell))
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aAttribute == nsGkAtoms::tooltiptext ||
 | 
						|
      aAttribute == nsGkAtoms::tooltip)
 | 
						|
  {
 | 
						|
    nsIRootBox* rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell());
 | 
						|
    if (rootBox) {
 | 
						|
      if (aModType == nsIDOMMutationEvent::REMOVAL)
 | 
						|
        rootBox->RemoveTooltipSupport(aElement);
 | 
						|
      if (aModType == nsIDOMMutationEvent::ADDITION)
 | 
						|
        rootBox->AddTooltipSupport(aElement);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
#endif // MOZ_XUL
 | 
						|
 | 
						|
  if (primaryFrame) {
 | 
						|
    // See if we have appearance information for a theme.
 | 
						|
    const nsStyleDisplay* disp = primaryFrame->StyleDisplay();
 | 
						|
    if (disp->mAppearance) {
 | 
						|
      nsITheme* theme = PresContext()->GetTheme();
 | 
						|
      if (theme && theme->ThemeSupportsWidget(PresContext(), primaryFrame, disp->mAppearance)) {
 | 
						|
        bool repaint = false;
 | 
						|
        theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute,
 | 
						|
            &repaint, aOldValue);
 | 
						|
        if (repaint)
 | 
						|
          hint |= nsChangeHint_RepaintFrame;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // let the frame deal with it now, so we don't have to deal later
 | 
						|
    primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
 | 
						|
    // XXXwaterson should probably check for IB split siblings
 | 
						|
    // here, and propagate the AttributeChanged notification to
 | 
						|
    // them, as well. Currently, inline frames don't do anything on
 | 
						|
    // this notification, so it's not that big a deal.
 | 
						|
  }
 | 
						|
 | 
						|
  // See if we can optimize away the style re-resolution -- must be called after
 | 
						|
  // the frame's AttributeChanged() in case it does something that affects the style
 | 
						|
  RestyleHintData rsdata;
 | 
						|
  nsRestyleHint rshint =
 | 
						|
    StyleSet()->HasAttributeDependentStyle(aElement,
 | 
						|
                                           aNameSpaceID,
 | 
						|
                                           aAttribute,
 | 
						|
                                           aModType,
 | 
						|
                                           true,
 | 
						|
                                           aOldValue,
 | 
						|
                                           rsdata);
 | 
						|
  PostRestyleEvent(aElement, rshint, hint, &rsdata);
 | 
						|
}
 | 
						|
 | 
						|
/* static */ uint64_t
 | 
						|
RestyleManager::GetAnimationGenerationForFrame(nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  EffectSet* effectSet = EffectSet::GetEffectSet(aFrame);
 | 
						|
  return effectSet ? effectSet->GetAnimationGeneration() : 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::RestyleForEmptyChange(Element* aContainer)
 | 
						|
{
 | 
						|
  // In some cases (:empty + E, :empty ~ E), a change in the content of
 | 
						|
  // an element requires restyling its parent's siblings.
 | 
						|
  nsRestyleHint hint = eRestyle_Subtree;
 | 
						|
  nsIContent* grandparent = aContainer->GetParent();
 | 
						|
  if (grandparent &&
 | 
						|
      (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
 | 
						|
    hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
 | 
						|
  }
 | 
						|
  PostRestyleEvent(aContainer, hint, nsChangeHint(0));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::RestyleForAppend(nsIContent* aContainer,
 | 
						|
                                 nsIContent* aFirstNewContent)
 | 
						|
{
 | 
						|
  // The container cannot be a document, but might be a ShadowRoot.
 | 
						|
  if (!aContainer->IsElement()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Element* container = aContainer->AsElement();
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  {
 | 
						|
    for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
 | 
						|
      NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(),
 | 
						|
                   "anonymous nodes should not be in child lists");
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  uint32_t selectorFlags =
 | 
						|
    container->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
 | 
						|
                             ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
 | 
						|
  if (selectorFlags == 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
 | 
						|
    // see whether we need to restyle the container
 | 
						|
    bool wasEmpty = true; // :empty or :-moz-only-whitespace
 | 
						|
    for (nsIContent* cur = container->GetFirstChild();
 | 
						|
         cur != aFirstNewContent;
 | 
						|
         cur = cur->GetNextSibling()) {
 | 
						|
      // We don't know whether we're testing :empty or :-moz-only-whitespace,
 | 
						|
      // so be conservative and assume :-moz-only-whitespace (i.e., make
 | 
						|
      // IsSignificantChild less likely to be true, and thus make us more
 | 
						|
      // likely to restyle).
 | 
						|
      if (nsStyleUtil::IsSignificantChild(cur, true, false)) {
 | 
						|
        wasEmpty = false;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (wasEmpty) {
 | 
						|
      RestyleForEmptyChange(container);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
 | 
						|
    PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
 | 
						|
    // Restyling the container is the most we can do here, so we're done.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
 | 
						|
    // restyle the last element child before this node
 | 
						|
    for (nsIContent* cur = aFirstNewContent->GetPreviousSibling();
 | 
						|
         cur;
 | 
						|
         cur = cur->GetPreviousSibling()) {
 | 
						|
      if (cur->IsElement()) {
 | 
						|
        PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, nsChangeHint(0));
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Needed since we can't use PostRestyleEvent on non-elements (with
 | 
						|
// eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
 | 
						|
// eRestyle_LaterSiblings) as appropriate).
 | 
						|
static void
 | 
						|
RestyleSiblingsStartingWith(RestyleManager* aRestyleManager,
 | 
						|
                            nsIContent* aStartingSibling /* may be null */)
 | 
						|
{
 | 
						|
  for (nsIContent* sibling = aStartingSibling; sibling;
 | 
						|
       sibling = sibling->GetNextSibling()) {
 | 
						|
    if (sibling->IsElement()) {
 | 
						|
      aRestyleManager->
 | 
						|
        PostRestyleEvent(sibling->AsElement(),
 | 
						|
                         nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings),
 | 
						|
                         nsChangeHint(0));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Restyling for a ContentInserted or CharacterDataChanged notification.
 | 
						|
// This could be used for ContentRemoved as well if we got the
 | 
						|
// notification before the removal happened (and sometimes
 | 
						|
// CharacterDataChanged is more like a removal than an addition).
 | 
						|
// The comments are written and variables are named in terms of it being
 | 
						|
// a ContentInserted notification.
 | 
						|
void
 | 
						|
RestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
 | 
						|
                                         nsIContent* aChild)
 | 
						|
{
 | 
						|
  // The container might be a document or a ShadowRoot.
 | 
						|
  if (!aContainer->IsElement()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Element* container = aContainer->AsElement();
 | 
						|
 | 
						|
  NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(),
 | 
						|
               "anonymous nodes should not be in child lists");
 | 
						|
  uint32_t selectorFlags =
 | 
						|
    container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
 | 
						|
  if (selectorFlags == 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
 | 
						|
    // see whether we need to restyle the container
 | 
						|
    bool wasEmpty = true; // :empty or :-moz-only-whitespace
 | 
						|
    for (nsIContent* child = container->GetFirstChild();
 | 
						|
         child;
 | 
						|
         child = child->GetNextSibling()) {
 | 
						|
      if (child == aChild)
 | 
						|
        continue;
 | 
						|
      // We don't know whether we're testing :empty or :-moz-only-whitespace,
 | 
						|
      // so be conservative and assume :-moz-only-whitespace (i.e., make
 | 
						|
      // IsSignificantChild less likely to be true, and thus make us more
 | 
						|
      // likely to restyle).
 | 
						|
      if (nsStyleUtil::IsSignificantChild(child, true, false)) {
 | 
						|
        wasEmpty = false;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (wasEmpty) {
 | 
						|
      RestyleForEmptyChange(container);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
 | 
						|
    PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
 | 
						|
    // Restyling the container is the most we can do here, so we're done.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
 | 
						|
    // Restyle all later siblings.
 | 
						|
    RestyleSiblingsStartingWith(this, aChild->GetNextSibling());
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
 | 
						|
    // restyle the previously-first element child if it is after this node
 | 
						|
    bool passedChild = false;
 | 
						|
    for (nsIContent* content = container->GetFirstChild();
 | 
						|
         content;
 | 
						|
         content = content->GetNextSibling()) {
 | 
						|
      if (content == aChild) {
 | 
						|
        passedChild = true;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (content->IsElement()) {
 | 
						|
        if (passedChild) {
 | 
						|
          PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
 | 
						|
                           nsChangeHint(0));
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // restyle the previously-last element child if it is before this node
 | 
						|
    passedChild = false;
 | 
						|
    for (nsIContent* content = container->GetLastChild();
 | 
						|
         content;
 | 
						|
         content = content->GetPreviousSibling()) {
 | 
						|
      if (content == aChild) {
 | 
						|
        passedChild = true;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (content->IsElement()) {
 | 
						|
        if (passedChild) {
 | 
						|
          PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
 | 
						|
                           nsChangeHint(0));
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::ContentRemoved(nsINode* aContainer,
 | 
						|
                               nsIContent* aOldChild,
 | 
						|
                               nsIContent* aFollowingSibling)
 | 
						|
{
 | 
						|
  // The container might be a document or a ShadowRoot.
 | 
						|
  if (!aContainer->IsElement()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Element* container = aContainer->AsElement();
 | 
						|
 | 
						|
  if (aOldChild->IsRootOfAnonymousSubtree()) {
 | 
						|
    // This should be an assert, but this is called incorrectly in
 | 
						|
    // HTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging
 | 
						|
    // up the logs.  Make it an assert again when that's fixed.
 | 
						|
    MOZ_ASSERT(aOldChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
 | 
						|
               "anonymous nodes should not be in child lists (bug 439258)");
 | 
						|
  }
 | 
						|
  uint32_t selectorFlags =
 | 
						|
    container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
 | 
						|
  if (selectorFlags == 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
 | 
						|
    // see whether we need to restyle the container
 | 
						|
    bool isEmpty = true; // :empty or :-moz-only-whitespace
 | 
						|
    for (nsIContent* child = container->GetFirstChild();
 | 
						|
         child;
 | 
						|
         child = child->GetNextSibling()) {
 | 
						|
      // We don't know whether we're testing :empty or :-moz-only-whitespace,
 | 
						|
      // so be conservative and assume :-moz-only-whitespace (i.e., make
 | 
						|
      // IsSignificantChild less likely to be true, and thus make us more
 | 
						|
      // likely to restyle).
 | 
						|
      if (nsStyleUtil::IsSignificantChild(child, true, false)) {
 | 
						|
        isEmpty = false;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (isEmpty) {
 | 
						|
      RestyleForEmptyChange(container);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
 | 
						|
    PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
 | 
						|
    // Restyling the container is the most we can do here, so we're done.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
 | 
						|
    // Restyle all later siblings.
 | 
						|
    RestyleSiblingsStartingWith(this, aFollowingSibling);
 | 
						|
  }
 | 
						|
 | 
						|
  if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
 | 
						|
    // restyle the now-first element child if it was after aOldChild
 | 
						|
    bool reachedFollowingSibling = false;
 | 
						|
    for (nsIContent* content = container->GetFirstChild();
 | 
						|
         content;
 | 
						|
         content = content->GetNextSibling()) {
 | 
						|
      if (content == aFollowingSibling) {
 | 
						|
        reachedFollowingSibling = true;
 | 
						|
        // do NOT continue here; we might want to restyle this node
 | 
						|
      }
 | 
						|
      if (content->IsElement()) {
 | 
						|
        if (reachedFollowingSibling) {
 | 
						|
          PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
 | 
						|
                           nsChangeHint(0));
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // restyle the now-last element child if it was before aOldChild
 | 
						|
    reachedFollowingSibling = (aFollowingSibling == nullptr);
 | 
						|
    for (nsIContent* content = container->GetLastChild();
 | 
						|
         content;
 | 
						|
         content = content->GetPreviousSibling()) {
 | 
						|
      if (content->IsElement()) {
 | 
						|
        if (reachedFollowingSibling) {
 | 
						|
          PostRestyleEvent(content->AsElement(), eRestyle_Subtree, nsChangeHint(0));
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      if (content == aFollowingSibling) {
 | 
						|
        reachedFollowingSibling = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
 | 
						|
                                    nsRestyleHint aRestyleHint)
 | 
						|
{
 | 
						|
  NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
 | 
						|
               "Should not reconstruct the root of the frame tree.  "
 | 
						|
               "Use ReconstructDocElementHierarchy instead.");
 | 
						|
  MOZ_ASSERT(!(aRestyleHint & ~(eRestyle_Subtree | eRestyle_ForceDescendants)),
 | 
						|
             "the only bits allowed in aRestyleHint are eRestyle_Subtree and "
 | 
						|
             "eRestyle_ForceDescendants");
 | 
						|
 | 
						|
  mRebuildAllExtraHint |= aExtraHint;
 | 
						|
  mRebuildAllRestyleHint |= aRestyleHint;
 | 
						|
 | 
						|
  // Processing the style changes could cause a flush that propagates to
 | 
						|
  // the parent frame and thus destroys the pres shell, so we must hold
 | 
						|
  // a reference.
 | 
						|
  nsCOMPtr<nsIPresShell> presShell = PresContext()->GetPresShell();
 | 
						|
  if (!presShell || !presShell->GetRootFrame()) {
 | 
						|
    mDoRebuildAllStyleData = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Make sure that the viewmanager will outlive the presshell
 | 
						|
  RefPtr<nsViewManager> vm = presShell->GetViewManager();
 | 
						|
 | 
						|
  // We may reconstruct frames below and hence process anything that is in the
 | 
						|
  // tree. We don't want to get notified to process those items again after.
 | 
						|
  presShell->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify);
 | 
						|
 | 
						|
  nsAutoScriptBlocker scriptBlocker;
 | 
						|
 | 
						|
  mDoRebuildAllStyleData = true;
 | 
						|
 | 
						|
  ProcessPendingRestyles();
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::StartRebuildAllStyleData(RestyleTracker& aRestyleTracker)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mIsProcessingRestyles);
 | 
						|
 | 
						|
  nsIFrame* rootFrame = PresContext()->PresShell()->GetRootFrame();
 | 
						|
  if (!rootFrame) {
 | 
						|
    // No need to do anything.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mInRebuildAllStyleData = true;
 | 
						|
 | 
						|
  // Tell the style set to get the old rule tree out of the way
 | 
						|
  // so we can recalculate while maintaining rule tree immutability
 | 
						|
  nsresult rv = StyleSet()->BeginReconstruct();
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    MOZ_CRASH("unable to rebuild style data");
 | 
						|
  }
 | 
						|
 | 
						|
  nsRestyleHint restyleHint = mRebuildAllRestyleHint;
 | 
						|
  nsChangeHint changeHint = mRebuildAllExtraHint;
 | 
						|
  mRebuildAllExtraHint = nsChangeHint(0);
 | 
						|
  mRebuildAllRestyleHint = nsRestyleHint(0);
 | 
						|
 | 
						|
  restyleHint |= eRestyle_ForceDescendants;
 | 
						|
 | 
						|
  if (!(restyleHint & eRestyle_Subtree) &&
 | 
						|
      (restyleHint & ~(eRestyle_Force | eRestyle_ForceDescendants))) {
 | 
						|
    // We want this hint to apply to the root node's primary frame
 | 
						|
    // rather than the root frame, since it's the primary frame that has
 | 
						|
    // the styles for the root element (rather than the ancestors of the
 | 
						|
    // primary frame whose mContent is the root node but which have
 | 
						|
    // different styles).  If we use up the hint for one of the
 | 
						|
    // ancestors that we hit first, then we'll fail to do the restyling
 | 
						|
    // we need to do.
 | 
						|
    Element* root = PresContext()->Document()->GetRootElement();
 | 
						|
    if (root) {
 | 
						|
      // If the root element is gone, dropping the hint on the floor
 | 
						|
      // should be fine.
 | 
						|
      aRestyleTracker.AddPendingRestyle(root, restyleHint, nsChangeHint(0));
 | 
						|
    }
 | 
						|
    restyleHint = nsRestyleHint(0);
 | 
						|
  }
 | 
						|
 | 
						|
  // Recalculate all of the style contexts for the document, from the
 | 
						|
  // root frame.  We can't do this with a change hint, since we can't
 | 
						|
  // post a change hint for the root frame.
 | 
						|
  // Note that we can ignore the return value of ComputeStyleChangeFor
 | 
						|
  // because we never need to reframe the root frame.
 | 
						|
  // XXX Does it matter that we're passing aExtraHint to the real root
 | 
						|
  // frame and not the root node's primary frame?  (We could do
 | 
						|
  // roughly what we do for aRestyleHint above.)
 | 
						|
  ComputeAndProcessStyleChange(rootFrame,
 | 
						|
                               changeHint, aRestyleTracker, restyleHint,
 | 
						|
                               RestyleHintData());
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::FinishRebuildAllStyleData()
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mInRebuildAllStyleData, "bad caller");
 | 
						|
 | 
						|
  // Tell the style set it's safe to destroy the old rule tree.  We
 | 
						|
  // must do this after the ProcessRestyledFrames call in case the
 | 
						|
  // change list has frame reconstructs in it (since frames to be
 | 
						|
  // reconstructed will still have their old style context pointers
 | 
						|
  // until they are destroyed).
 | 
						|
  StyleSet()->EndReconstruct();
 | 
						|
 | 
						|
  mInRebuildAllStyleData = false;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::ProcessPendingRestyles()
 | 
						|
{
 | 
						|
  NS_PRECONDITION(PresContext()->Document(), "No document?  Pshaw!");
 | 
						|
  NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
 | 
						|
                  "Missing a script blocker!");
 | 
						|
 | 
						|
  // First do any queued-up frame creation.  (We should really
 | 
						|
  // merge this into the rest of the process, though; see bug 827239.)
 | 
						|
  PresContext()->FrameConstructor()->CreateNeededFrames();
 | 
						|
 | 
						|
  // Process non-animation restyles...
 | 
						|
  MOZ_ASSERT(!mIsProcessingRestyles,
 | 
						|
             "Nesting calls to ProcessPendingRestyles?");
 | 
						|
  mIsProcessingRestyles = true;
 | 
						|
 | 
						|
  // Before we process any restyles, we need to ensure that style
 | 
						|
  // resulting from any animations is up-to-date, so that if any style
 | 
						|
  // changes we cause trigger transitions, we have the correct old style
 | 
						|
  // for starting the transition.
 | 
						|
  bool haveNonAnimation =
 | 
						|
    mHavePendingNonAnimationRestyles || mDoRebuildAllStyleData;
 | 
						|
  if (haveNonAnimation) {
 | 
						|
    ++mAnimationGeneration;
 | 
						|
    UpdateOnlyAnimationStyles();
 | 
						|
  } else {
 | 
						|
    // If we don't have non-animation style updates, then we have queued
 | 
						|
    // up animation style updates from the refresh driver tick.  This
 | 
						|
    // doesn't necessarily include *all* animation style updates, since
 | 
						|
    // we might be suppressing main-thread updates for some animations,
 | 
						|
    // so we don't want to call UpdateOnlyAnimationStyles, which updates
 | 
						|
    // all animations.  In other words, the work that we're about to do
 | 
						|
    // to process the pending restyles queue is a *subset* of the work
 | 
						|
    // that UpdateOnlyAnimationStyles would do, since we're *not*
 | 
						|
    // updating transitions that are running on the compositor thread
 | 
						|
    // and suppressed on the main thread.
 | 
						|
    //
 | 
						|
    // But when we update those styles, we want to suppress updates to
 | 
						|
    // transitions just like we do in UpdateOnlyAnimationStyles.  So we
 | 
						|
    // want to tell the transition manager to act as though we're in
 | 
						|
    // UpdateOnlyAnimationStyles.
 | 
						|
    //
 | 
						|
    // FIXME: In the future, we might want to refactor the way the
 | 
						|
    // animation and transition manager do their refresh driver ticks so
 | 
						|
    // that we can use UpdateOnlyAnimationStyles, with a different
 | 
						|
    // boolean argument, for this update as well, instead of having them
 | 
						|
    // post style updates in their WillRefresh methods.
 | 
						|
    PresContext()->TransitionManager()->SetInAnimationOnlyStyleUpdate(true);
 | 
						|
  }
 | 
						|
 | 
						|
  ProcessRestyles(mPendingRestyles);
 | 
						|
 | 
						|
  if (!haveNonAnimation) {
 | 
						|
    PresContext()->TransitionManager()->SetInAnimationOnlyStyleUpdate(false);
 | 
						|
  }
 | 
						|
 | 
						|
  mIsProcessingRestyles = false;
 | 
						|
 | 
						|
  NS_ASSERTION(haveNonAnimation || !mHavePendingNonAnimationRestyles,
 | 
						|
               "should not have added restyles");
 | 
						|
  mHavePendingNonAnimationRestyles = false;
 | 
						|
 | 
						|
  if (mDoRebuildAllStyleData) {
 | 
						|
    // We probably wasted a lot of work up above, but this seems safest
 | 
						|
    // and it should be rarely used.
 | 
						|
    // This might add us as a refresh observer again; that's ok.
 | 
						|
    ProcessPendingRestyles();
 | 
						|
 | 
						|
    NS_ASSERTION(!mDoRebuildAllStyleData,
 | 
						|
                 "repeatedly setting mDoRebuildAllStyleData?");
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(!mInRebuildAllStyleData,
 | 
						|
             "should have called FinishRebuildAllStyleData");
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::BeginProcessingRestyles(RestyleTracker& aRestyleTracker)
 | 
						|
{
 | 
						|
  // Make sure to not rebuild quote or counter lists while we're
 | 
						|
  // processing restyles
 | 
						|
  PresContext()->FrameConstructor()->BeginUpdate();
 | 
						|
 | 
						|
  mInStyleRefresh = true;
 | 
						|
 | 
						|
  if (ShouldStartRebuildAllFor(aRestyleTracker)) {
 | 
						|
    mDoRebuildAllStyleData = false;
 | 
						|
    StartRebuildAllStyleData(aRestyleTracker);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::EndProcessingRestyles()
 | 
						|
{
 | 
						|
  FlushOverflowChangedTracker();
 | 
						|
 | 
						|
  MOZ_ASSERT(mAnimationsWithDestroyedFrame);
 | 
						|
  mAnimationsWithDestroyedFrame->
 | 
						|
    StopAnimationsForElementsWithoutFrames();
 | 
						|
 | 
						|
  // Set mInStyleRefresh to false now, since the EndUpdate call might
 | 
						|
  // add more restyles.
 | 
						|
  mInStyleRefresh = false;
 | 
						|
 | 
						|
  if (mInRebuildAllStyleData) {
 | 
						|
    FinishRebuildAllStyleData();
 | 
						|
  }
 | 
						|
 | 
						|
  PresContext()->FrameConstructor()->EndUpdate();
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  PresContext()->PresShell()->VerifyStyleTree();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::UpdateOnlyAnimationStyles()
 | 
						|
{
 | 
						|
  bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
 | 
						|
 | 
						|
  nsIDocument* document = PresContext()->Document();
 | 
						|
  nsSMILAnimationController* animationController =
 | 
						|
    document->HasAnimationController() ?
 | 
						|
    document->GetAnimationController() :
 | 
						|
    nullptr;
 | 
						|
  bool doSMIL = animationController &&
 | 
						|
                animationController->MightHavePendingStyleUpdates();
 | 
						|
 | 
						|
  if (!doCSS && !doSMIL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsTransitionManager* transitionManager = PresContext()->TransitionManager();
 | 
						|
 | 
						|
  transitionManager->SetInAnimationOnlyStyleUpdate(true);
 | 
						|
 | 
						|
  RestyleTracker tracker(ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE |
 | 
						|
                         ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT);
 | 
						|
  tracker.Init(this);
 | 
						|
 | 
						|
  if (doCSS) {
 | 
						|
    // FIXME:  We should have the transition manager and animation manager
 | 
						|
    // add only the elements for which animations are currently throttled
 | 
						|
    // (i.e., animating on the compositor with main-thread style updates
 | 
						|
    // suppressed).
 | 
						|
    PresContext()->EffectCompositor()->AddStyleUpdatesTo(tracker);
 | 
						|
  }
 | 
						|
 | 
						|
  if (doSMIL) {
 | 
						|
    animationController->AddStyleUpdatesTo(tracker);
 | 
						|
  }
 | 
						|
 | 
						|
  ProcessRestyles(tracker);
 | 
						|
 | 
						|
  transitionManager->SetInAnimationOnlyStyleUpdate(false);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::PostRestyleEvent(Element* aElement,
 | 
						|
                                 nsRestyleHint aRestyleHint,
 | 
						|
                                 nsChangeHint aMinChangeHint,
 | 
						|
                                 const RestyleHintData* aRestyleHintData)
 | 
						|
{
 | 
						|
  if (MOZ_UNLIKELY(IsDisconnected()) ||
 | 
						|
      MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aRestyleHint == 0 && !aMinChangeHint) {
 | 
						|
    // Nothing to do here
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mPendingRestyles.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint,
 | 
						|
                                     aRestyleHintData);
 | 
						|
 | 
						|
  // Set mHavePendingNonAnimationRestyles for any restyle that could
 | 
						|
  // possibly contain non-animation styles (i.e., those that require us
 | 
						|
  // to do an animation-only style flush before processing style changes
 | 
						|
  // to ensure correct initialization of CSS transitions).
 | 
						|
  if (aRestyleHint & ~eRestyle_AllHintsWithAnimations) {
 | 
						|
    mHavePendingNonAnimationRestyles = true;
 | 
						|
  }
 | 
						|
 | 
						|
  PostRestyleEventInternal(false);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
 | 
						|
                                             nsRestyleHint aRestyleHint)
 | 
						|
{
 | 
						|
  NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
 | 
						|
               "Should not reconstruct the root of the frame tree.  "
 | 
						|
               "Use ReconstructDocElementHierarchy instead.");
 | 
						|
  MOZ_ASSERT(!(aRestyleHint & eRestyle_SomeDescendants),
 | 
						|
             "PostRebuildAllStyleDataEvent does not handle "
 | 
						|
             "eRestyle_SomeDescendants");
 | 
						|
 | 
						|
  mDoRebuildAllStyleData = true;
 | 
						|
  mRebuildAllExtraHint |= aExtraHint;
 | 
						|
  mRebuildAllRestyleHint |= aRestyleHint;
 | 
						|
 | 
						|
  // Get a restyle event posted if necessary
 | 
						|
  PostRestyleEventInternal(false);
 | 
						|
}
 | 
						|
 | 
						|
// aContent must be the content for the frame in question, which may be
 | 
						|
// :before/:after content
 | 
						|
/* static */ bool
 | 
						|
RestyleManager::TryStartingTransition(nsPresContext* aPresContext,
 | 
						|
                                      nsIContent* aContent,
 | 
						|
                                      nsStyleContext* aOldStyleContext,
 | 
						|
                                      RefPtr<nsStyleContext>*
 | 
						|
                                        aNewStyleContext /* inout */)
 | 
						|
{
 | 
						|
  if (!aContent || !aContent->IsElement()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Notify the transition manager.  If it starts a transition,
 | 
						|
  // it might modify the new style context.
 | 
						|
  RefPtr<nsStyleContext> sc = *aNewStyleContext;
 | 
						|
  aPresContext->TransitionManager()->StyleContextChanged(
 | 
						|
    aContent->AsElement(), aOldStyleContext, aNewStyleContext);
 | 
						|
  return *aNewStyleContext != sc;
 | 
						|
}
 | 
						|
 | 
						|
static dom::Element*
 | 
						|
ElementForStyleContext(nsIContent* aParentContent,
 | 
						|
                       nsIFrame* aFrame,
 | 
						|
                       CSSPseudoElementType aPseudoType)
 | 
						|
{
 | 
						|
  // We don't expect XUL tree stuff here.
 | 
						|
  NS_PRECONDITION(aPseudoType == CSSPseudoElementType::NotPseudo ||
 | 
						|
                  aPseudoType == CSSPseudoElementType::AnonBox ||
 | 
						|
                  aPseudoType < CSSPseudoElementType::Count,
 | 
						|
                  "Unexpected pseudo");
 | 
						|
  // XXX see the comments about the various element confusion in
 | 
						|
  // ElementRestyler::Restyle.
 | 
						|
  if (aPseudoType == CSSPseudoElementType::NotPseudo) {
 | 
						|
    return aFrame->GetContent()->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPseudoType == CSSPseudoElementType::AnonBox) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPseudoType == CSSPseudoElementType::firstLetter) {
 | 
						|
    NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame,
 | 
						|
                 "firstLetter pseudoTag without a nsFirstLetterFrame");
 | 
						|
    nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame);
 | 
						|
    return block->GetContent()->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPseudoType == CSSPseudoElementType::mozColorSwatch) {
 | 
						|
    MOZ_ASSERT(aFrame->GetParent() &&
 | 
						|
               aFrame->GetParent()->GetParent(),
 | 
						|
               "Color swatch frame should have a parent & grandparent");
 | 
						|
 | 
						|
    nsIFrame* grandparentFrame = aFrame->GetParent()->GetParent();
 | 
						|
    MOZ_ASSERT(grandparentFrame->GetType() == nsGkAtoms::colorControlFrame,
 | 
						|
               "Color swatch's grandparent should be nsColorControlFrame");
 | 
						|
 | 
						|
    return grandparentFrame->GetContent()->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPseudoType == CSSPseudoElementType::mozNumberText ||
 | 
						|
      aPseudoType == CSSPseudoElementType::mozNumberWrapper ||
 | 
						|
      aPseudoType == CSSPseudoElementType::mozNumberSpinBox ||
 | 
						|
      aPseudoType == CSSPseudoElementType::mozNumberSpinUp ||
 | 
						|
      aPseudoType == CSSPseudoElementType::mozNumberSpinDown) {
 | 
						|
    // Get content for nearest nsNumberControlFrame:
 | 
						|
    nsIFrame* f = aFrame->GetParent();
 | 
						|
    MOZ_ASSERT(f);
 | 
						|
    while (f->GetType() != nsGkAtoms::numberControlFrame) {
 | 
						|
      f = f->GetParent();
 | 
						|
      MOZ_ASSERT(f);
 | 
						|
    }
 | 
						|
    return f->GetContent()->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  if (aParentContent) {
 | 
						|
    return aParentContent->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(aFrame->GetContent()->GetParent(),
 | 
						|
             "should not have got here for the root element");
 | 
						|
  return aFrame->GetContent()->GetParent()->AsElement();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Some pseudo-elements actually have a content node created for them,
 | 
						|
 * whereas others have only a frame but not a content node.  In some
 | 
						|
 * cases, we want to support style attributes or states on those
 | 
						|
 * elements.  For those pseudo-elements, we need to pass the
 | 
						|
 * anonymous pseudo-element content to selector matching processes in
 | 
						|
 * addition to the element that the pseudo-element is for; in other
 | 
						|
 * cases we should pass null instead.  This function returns the
 | 
						|
 * pseudo-element content that we should pass.
 | 
						|
 */
 | 
						|
static dom::Element*
 | 
						|
PseudoElementForStyleContext(nsIFrame* aFrame,
 | 
						|
                             CSSPseudoElementType aPseudoType)
 | 
						|
{
 | 
						|
  if (aPseudoType >= CSSPseudoElementType::Count) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  if (nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) ||
 | 
						|
      nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType)) {
 | 
						|
    return aFrame->GetContent()->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * FIXME: Temporary.  Should merge with following function.
 | 
						|
 */
 | 
						|
static nsIFrame*
 | 
						|
GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  // Account for {ib} splits when looking for "prevContinuation".  In
 | 
						|
  // particular, for the first-continuation of a part of an {ib} split
 | 
						|
  // we want to use the previous ib-split sibling of the previous
 | 
						|
  // ib-split sibling of aFrame, which should have the same style
 | 
						|
  // context as aFrame itself.  In particular, if aFrame is the first
 | 
						|
  // continuation of an inline part of a block-in-inline split then its
 | 
						|
  // previous ib-split sibling is a block, and the previous ib-split
 | 
						|
  // sibling of _that_ is an inline, just like aFrame.  Similarly, if
 | 
						|
  // aFrame is the first continuation of a block part of an
 | 
						|
  // block-in-inline split (a block-in-inline wrapper block), then its
 | 
						|
  // previous ib-split sibling is an inline and the previous ib-split
 | 
						|
  // sibling of that is either another block-in-inline wrapper block box
 | 
						|
  // or null.
 | 
						|
  nsIFrame* prevContinuation = aFrame->GetPrevContinuation();
 | 
						|
  if (!prevContinuation &&
 | 
						|
      (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
 | 
						|
    // We're the first continuation, so we can just get the frame
 | 
						|
    // property directly
 | 
						|
    prevContinuation =
 | 
						|
      aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling());
 | 
						|
    if (prevContinuation) {
 | 
						|
      prevContinuation =
 | 
						|
        prevContinuation->Properties().Get(nsIFrame::IBSplitPrevSibling());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  NS_ASSERTION(!prevContinuation ||
 | 
						|
               prevContinuation->GetContent() == aFrame->GetContent(),
 | 
						|
               "unexpected content mismatch");
 | 
						|
 | 
						|
  return prevContinuation;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Get the previous continuation or similar ib-split sibling (assuming
 | 
						|
 * block/inline alternation), conditionally on it having the same style.
 | 
						|
 * This assumes that we're not between resolving the two (i.e., that
 | 
						|
 * they're both already resolved.
 | 
						|
 */
 | 
						|
static nsIFrame*
 | 
						|
GetPrevContinuationWithSameStyle(nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  nsIFrame* prevContinuation = GetPrevContinuationWithPossiblySameStyle(aFrame);
 | 
						|
  if (!prevContinuation) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsStyleContext* prevStyle = prevContinuation->StyleContext();
 | 
						|
  nsStyleContext* selfStyle = aFrame->StyleContext();
 | 
						|
  if (prevStyle != selfStyle) {
 | 
						|
    NS_ASSERTION(prevStyle->GetPseudo() != selfStyle->GetPseudo() ||
 | 
						|
                 prevStyle->GetParent() != selfStyle->GetParent(),
 | 
						|
                 "continuations should have the same style context");
 | 
						|
    prevContinuation = nullptr;
 | 
						|
  }
 | 
						|
  return prevContinuation;
 | 
						|
}
 | 
						|
 | 
						|
nsresult
 | 
						|
RestyleManager::ReparentStyleContext(nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  nsIAtom* frameType = aFrame->GetType();
 | 
						|
  if (frameType == nsGkAtoms::placeholderFrame) {
 | 
						|
    // Also reparent the out-of-flow and all its continuations.
 | 
						|
    nsIFrame* outOfFlow =
 | 
						|
      nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
 | 
						|
    NS_ASSERTION(outOfFlow, "no out-of-flow frame");
 | 
						|
    do {
 | 
						|
      ReparentStyleContext(outOfFlow);
 | 
						|
    } while ((outOfFlow = outOfFlow->GetNextContinuation()));
 | 
						|
  } else if (frameType == nsGkAtoms::backdropFrame) {
 | 
						|
    // Style context of backdrop frame has no parent style context, and
 | 
						|
    // thus we do not need to reparent it.
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  // DO NOT verify the style tree before reparenting.  The frame
 | 
						|
  // tree has already been changed, so this check would just fail.
 | 
						|
  nsStyleContext* oldContext = aFrame->StyleContext();
 | 
						|
 | 
						|
  RefPtr<nsStyleContext> newContext;
 | 
						|
  nsIFrame* providerFrame;
 | 
						|
  nsStyleContext* newParentContext = aFrame->GetParentStyleContext(&providerFrame);
 | 
						|
  bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
 | 
						|
  nsIFrame* providerChild = nullptr;
 | 
						|
  if (isChild) {
 | 
						|
    ReparentStyleContext(providerFrame);
 | 
						|
    // Get the style context again after ReparentStyleContext() which might have
 | 
						|
    // changed it.
 | 
						|
    newParentContext = providerFrame->StyleContext();
 | 
						|
    providerChild = providerFrame;
 | 
						|
  }
 | 
						|
  NS_ASSERTION(newParentContext, "Reparenting something that has no usable"
 | 
						|
               " parent? Shouldn't happen!");
 | 
						|
  // XXX need to do something here to produce the correct style context for
 | 
						|
  // an IB split whose first inline part is inside a first-line frame.
 | 
						|
  // Currently the first IB anonymous block's style context takes the first
 | 
						|
  // part's style context as parent, which is wrong since first-line style
 | 
						|
  // should not apply to the anonymous block.
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  {
 | 
						|
    // Check that our assumption that continuations of the same
 | 
						|
    // pseudo-type and with the same style context parent have the
 | 
						|
    // same style context is valid before the reresolution.  (We need
 | 
						|
    // to check the pseudo-type and style context parent because of
 | 
						|
    // :first-letter and :first-line, where we create styled and
 | 
						|
    // unstyled letter/line frames distinguished by pseudo-type, and
 | 
						|
    // then need to distinguish their descendants based on having
 | 
						|
    // different parents.)
 | 
						|
    nsIFrame* nextContinuation = aFrame->GetNextContinuation();
 | 
						|
    if (nextContinuation) {
 | 
						|
      nsStyleContext* nextContinuationContext =
 | 
						|
        nextContinuation->StyleContext();
 | 
						|
      NS_ASSERTION(oldContext == nextContinuationContext ||
 | 
						|
                   oldContext->GetPseudo() !=
 | 
						|
                     nextContinuationContext->GetPseudo() ||
 | 
						|
                   oldContext->GetParent() !=
 | 
						|
                     nextContinuationContext->GetParent(),
 | 
						|
                   "continuations should have the same style context");
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  nsIFrame* prevContinuation =
 | 
						|
    GetPrevContinuationWithPossiblySameStyle(aFrame);
 | 
						|
  nsStyleContext* prevContinuationContext;
 | 
						|
  bool copyFromContinuation =
 | 
						|
    prevContinuation &&
 | 
						|
    (prevContinuationContext = prevContinuation->StyleContext())
 | 
						|
      ->GetPseudo() == oldContext->GetPseudo() &&
 | 
						|
     prevContinuationContext->GetParent() == newParentContext;
 | 
						|
  if (copyFromContinuation) {
 | 
						|
    // Just use the style context from the frame's previous
 | 
						|
    // continuation (see assertion about aFrame->GetNextContinuation()
 | 
						|
    // above, which we would have previously hit for aFrame's previous
 | 
						|
    // continuation).
 | 
						|
    newContext = prevContinuationContext;
 | 
						|
  } else {
 | 
						|
    nsIFrame* parentFrame = aFrame->GetParent();
 | 
						|
    Element* element =
 | 
						|
      ElementForStyleContext(parentFrame ? parentFrame->GetContent() : nullptr,
 | 
						|
                             aFrame,
 | 
						|
                             oldContext->GetPseudoType());
 | 
						|
    newContext = StyleSet()->
 | 
						|
                   ReparentStyleContext(oldContext, newParentContext, element);
 | 
						|
  }
 | 
						|
 | 
						|
  if (newContext) {
 | 
						|
    if (newContext != oldContext) {
 | 
						|
      // We probably don't want to initiate transitions from
 | 
						|
      // ReparentStyleContext, since we call it during frame
 | 
						|
      // construction rather than in response to dynamic changes.
 | 
						|
      // Also see the comment at the start of
 | 
						|
      // nsTransitionManager::ConsiderStartingTransition.
 | 
						|
#if 0
 | 
						|
      if (!copyFromContinuation) {
 | 
						|
        TryStartingTransition(mPresContext, aFrame->GetContent(),
 | 
						|
                              oldContext, &newContext);
 | 
						|
      }
 | 
						|
#endif
 | 
						|
 | 
						|
      // Make sure to call CalcStyleDifference so that the new context ends
 | 
						|
      // up resolving all the structs the old context resolved.
 | 
						|
      if (!copyFromContinuation) {
 | 
						|
        uint32_t equalStructs;
 | 
						|
        uint32_t samePointerStructs;
 | 
						|
        DebugOnly<nsChangeHint> styleChange =
 | 
						|
          oldContext->CalcStyleDifference(newContext, nsChangeHint(0),
 | 
						|
                                          &equalStructs,
 | 
						|
                                          &samePointerStructs);
 | 
						|
        // The style change is always 0 because we have the same rulenode and
 | 
						|
        // CalcStyleDifference optimizes us away.  That's OK, though:
 | 
						|
        // reparenting should never trigger a frame reconstruct, and whenever
 | 
						|
        // it's happening we already plan to reflow and repaint the frames.
 | 
						|
        NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
 | 
						|
                     "Our frame tree is likely to be bogus!");
 | 
						|
      }
 | 
						|
 | 
						|
      aFrame->SetStyleContext(newContext);
 | 
						|
 | 
						|
      nsIFrame::ChildListIterator lists(aFrame);
 | 
						|
      for (; !lists.IsDone(); lists.Next()) {
 | 
						|
        for (nsIFrame* child : lists.CurrentList()) {
 | 
						|
          // only do frames that are in flow
 | 
						|
          if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
 | 
						|
              child != providerChild) {
 | 
						|
#ifdef DEBUG
 | 
						|
            if (nsGkAtoms::placeholderFrame == child->GetType()) {
 | 
						|
              nsIFrame* outOfFlowFrame =
 | 
						|
                nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
 | 
						|
              NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
 | 
						|
 | 
						|
              NS_ASSERTION(outOfFlowFrame != providerChild,
 | 
						|
                           "Out of flow provider?");
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            ReparentStyleContext(child);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // If this frame is part of an IB split, then the style context of
 | 
						|
      // the next part of the split might be a child of our style context.
 | 
						|
      // Reparent its style context just in case one of our ancestors
 | 
						|
      // (split or not) hasn't done so already). It's not a problem to
 | 
						|
      // reparent the same frame twice because the "if (newContext !=
 | 
						|
      // oldContext)" check will prevent us from redoing work.
 | 
						|
      if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
 | 
						|
          !aFrame->GetPrevContinuation()) {
 | 
						|
        nsIFrame* sib =
 | 
						|
          aFrame->Properties().Get(nsIFrame::IBSplitSibling());
 | 
						|
        if (sib) {
 | 
						|
          ReparentStyleContext(sib);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // do additional contexts
 | 
						|
      int32_t contextIndex = 0;
 | 
						|
      for (nsStyleContext* oldExtraContext;
 | 
						|
           (oldExtraContext = aFrame->GetAdditionalStyleContext(contextIndex));
 | 
						|
           ++contextIndex) {
 | 
						|
        RefPtr<nsStyleContext> newExtraContext;
 | 
						|
        newExtraContext = StyleSet()->
 | 
						|
                            ReparentStyleContext(oldExtraContext,
 | 
						|
                                                 newContext, nullptr);
 | 
						|
        if (newExtraContext) {
 | 
						|
          if (newExtraContext != oldExtraContext) {
 | 
						|
            // Make sure to call CalcStyleDifference so that the new
 | 
						|
            // context ends up resolving all the structs the old context
 | 
						|
            // resolved.
 | 
						|
            uint32_t equalStructs;
 | 
						|
            uint32_t samePointerStructs;
 | 
						|
            DebugOnly<nsChangeHint> styleChange =
 | 
						|
              oldExtraContext->CalcStyleDifference(newExtraContext,
 | 
						|
                                                   nsChangeHint(0),
 | 
						|
                                                   &equalStructs,
 | 
						|
                                                   &samePointerStructs);
 | 
						|
            // The style change is always 0 because we have the same
 | 
						|
            // rulenode and CalcStyleDifference optimizes us away.  That's
 | 
						|
            // OK, though: reparenting should never trigger a frame
 | 
						|
            // reconstruct, and whenever it's happening we already plan to
 | 
						|
            // reflow and repaint the frames.
 | 
						|
            NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
 | 
						|
                         "Our frame tree is likely to be bogus!");
 | 
						|
          }
 | 
						|
 | 
						|
          aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
 | 
						|
        }
 | 
						|
      }
 | 
						|
#ifdef DEBUG
 | 
						|
      DebugVerifyStyleTree(aFrame);
 | 
						|
#endif
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
 | 
						|
                                 nsIFrame* aFrame,
 | 
						|
                                 nsStyleChangeList* aChangeList,
 | 
						|
                                 nsChangeHint aHintsHandledByAncestors,
 | 
						|
                                 RestyleTracker& aRestyleTracker,
 | 
						|
                                 nsTArray<nsCSSSelector*>&
 | 
						|
                                   aSelectorsForDescendants,
 | 
						|
                                 TreeMatchContext& aTreeMatchContext,
 | 
						|
                                 nsTArray<nsIContent*>&
 | 
						|
                                   aVisibleKidsOfHiddenElement,
 | 
						|
                                 nsTArray<ContextToClear>& aContextsToClear,
 | 
						|
                                 nsTArray<RefPtr<nsStyleContext>>&
 | 
						|
                                   aSwappedStructOwners)
 | 
						|
  : mPresContext(aPresContext)
 | 
						|
  , mFrame(aFrame)
 | 
						|
  , mParentContent(nullptr)
 | 
						|
    // XXXldb Why does it make sense to use aParentContent?  (See
 | 
						|
    // comment above assertion at start of ElementRestyler::Restyle.)
 | 
						|
  , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent)
 | 
						|
  , mChangeList(aChangeList)
 | 
						|
  , mHintsHandled(aHintsHandledByAncestors &
 | 
						|
                  ~NS_HintsNotHandledForDescendantsIn(aHintsHandledByAncestors))
 | 
						|
  , mParentFrameHintsNotHandledForDescendants(nsChangeHint(0))
 | 
						|
  , mHintsNotHandledForDescendants(nsChangeHint(0))
 | 
						|
  , mRestyleTracker(aRestyleTracker)
 | 
						|
  , mSelectorsForDescendants(aSelectorsForDescendants)
 | 
						|
  , mTreeMatchContext(aTreeMatchContext)
 | 
						|
  , mResolvedChild(nullptr)
 | 
						|
  , mContextsToClear(aContextsToClear)
 | 
						|
  , mSwappedStructOwners(aSwappedStructOwners)
 | 
						|
  , mIsRootOfRestyle(true)
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  , mDesiredA11yNotifications(eSendAllNotifications)
 | 
						|
  , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
 | 
						|
  , mOurA11yNotification(eDontNotify)
 | 
						|
  , mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
 | 
						|
#endif
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
  , mLoggingDepth(aRestyleTracker.LoggingDepth() + 1)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  MOZ_ASSERT_IF(mContent, !mContent->IsStyledByServo());
 | 
						|
}
 | 
						|
 | 
						|
ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler,
 | 
						|
                                 nsIFrame* aFrame,
 | 
						|
                                 uint32_t aConstructorFlags)
 | 
						|
  : mPresContext(aParentRestyler.mPresContext)
 | 
						|
  , mFrame(aFrame)
 | 
						|
  , mParentContent(aParentRestyler.mContent)
 | 
						|
    // XXXldb Why does it make sense to use aParentContent?  (See
 | 
						|
    // comment above assertion at start of ElementRestyler::Restyle.)
 | 
						|
  , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent)
 | 
						|
  , mChangeList(aParentRestyler.mChangeList)
 | 
						|
  , mHintsHandled(aParentRestyler.mHintsHandled &
 | 
						|
                  ~NS_HintsNotHandledForDescendantsIn(aParentRestyler.mHintsHandled))
 | 
						|
  , mParentFrameHintsNotHandledForDescendants(
 | 
						|
      aParentRestyler.mHintsNotHandledForDescendants)
 | 
						|
  , mHintsNotHandledForDescendants(nsChangeHint(0))
 | 
						|
  , mRestyleTracker(aParentRestyler.mRestyleTracker)
 | 
						|
  , mSelectorsForDescendants(aParentRestyler.mSelectorsForDescendants)
 | 
						|
  , mTreeMatchContext(aParentRestyler.mTreeMatchContext)
 | 
						|
  , mResolvedChild(nullptr)
 | 
						|
  , mContextsToClear(aParentRestyler.mContextsToClear)
 | 
						|
  , mSwappedStructOwners(aParentRestyler.mSwappedStructOwners)
 | 
						|
  , mIsRootOfRestyle(false)
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  , mDesiredA11yNotifications(aParentRestyler.mKidsDesiredA11yNotifications)
 | 
						|
  , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
 | 
						|
  , mOurA11yNotification(eDontNotify)
 | 
						|
  , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
 | 
						|
#endif
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
  , mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  MOZ_ASSERT_IF(mContent, !mContent->IsStyledByServo());
 | 
						|
  if (aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) {
 | 
						|
    // Note that the out-of-flow may not be a geometric descendant of
 | 
						|
    // the frame where we started the reresolve.  Therefore, even if
 | 
						|
    // mHintsHandled already includes nsChangeHint_AllReflowHints we
 | 
						|
    // don't want to pass that on to the out-of-flow reresolve, since
 | 
						|
    // that can lead to the out-of-flow not getting reflowed when it
 | 
						|
    // should be (eg a reresolve starting at <body> that involves
 | 
						|
    // reflowing the <body> would miss reflowing fixed-pos nodes that
 | 
						|
    // also need reflow).  In the cases when the out-of-flow _is_ a
 | 
						|
    // geometric descendant of a frame we already have a reflow hint
 | 
						|
    // for, reflow coalescing should keep us from doing the work twice.
 | 
						|
    mHintsHandled &= ~nsChangeHint_AllReflowHints;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
ElementRestyler::ElementRestyler(ParentContextFromChildFrame,
 | 
						|
                                 const ElementRestyler& aParentRestyler,
 | 
						|
                                 nsIFrame* aFrame)
 | 
						|
  : mPresContext(aParentRestyler.mPresContext)
 | 
						|
  , mFrame(aFrame)
 | 
						|
  , mParentContent(aParentRestyler.mParentContent)
 | 
						|
    // XXXldb Why does it make sense to use aParentContent?  (See
 | 
						|
    // comment above assertion at start of ElementRestyler::Restyle.)
 | 
						|
  , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent)
 | 
						|
  , mChangeList(aParentRestyler.mChangeList)
 | 
						|
  , mHintsHandled(aParentRestyler.mHintsHandled &
 | 
						|
                  ~NS_HintsNotHandledForDescendantsIn(aParentRestyler.mHintsHandled))
 | 
						|
  , mParentFrameHintsNotHandledForDescendants(
 | 
						|
      // assume the worst
 | 
						|
      nsChangeHint_Hints_NotHandledForDescendants)
 | 
						|
  , mHintsNotHandledForDescendants(nsChangeHint(0))
 | 
						|
  , mRestyleTracker(aParentRestyler.mRestyleTracker)
 | 
						|
  , mSelectorsForDescendants(aParentRestyler.mSelectorsForDescendants)
 | 
						|
  , mTreeMatchContext(aParentRestyler.mTreeMatchContext)
 | 
						|
  , mResolvedChild(nullptr)
 | 
						|
  , mContextsToClear(aParentRestyler.mContextsToClear)
 | 
						|
  , mSwappedStructOwners(aParentRestyler.mSwappedStructOwners)
 | 
						|
  , mIsRootOfRestyle(false)
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  , mDesiredA11yNotifications(aParentRestyler.mDesiredA11yNotifications)
 | 
						|
  , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
 | 
						|
  , mOurA11yNotification(eDontNotify)
 | 
						|
  , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
 | 
						|
#endif
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
  , mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  MOZ_ASSERT_IF(mContent, !mContent->IsStyledByServo());
 | 
						|
}
 | 
						|
 | 
						|
ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
 | 
						|
                                 nsIContent* aContent,
 | 
						|
                                 nsStyleChangeList* aChangeList,
 | 
						|
                                 nsChangeHint aHintsHandledByAncestors,
 | 
						|
                                 RestyleTracker& aRestyleTracker,
 | 
						|
                                 nsTArray<nsCSSSelector*>& aSelectorsForDescendants,
 | 
						|
                                 TreeMatchContext& aTreeMatchContext,
 | 
						|
                                 nsTArray<nsIContent*>&
 | 
						|
                                   aVisibleKidsOfHiddenElement,
 | 
						|
                                 nsTArray<ContextToClear>& aContextsToClear,
 | 
						|
                                 nsTArray<RefPtr<nsStyleContext>>&
 | 
						|
                                   aSwappedStructOwners)
 | 
						|
  : mPresContext(aPresContext)
 | 
						|
  , mFrame(nullptr)
 | 
						|
  , mParentContent(nullptr)
 | 
						|
  , mContent(aContent)
 | 
						|
  , mChangeList(aChangeList)
 | 
						|
  , mHintsHandled(aHintsHandledByAncestors &
 | 
						|
                  ~NS_HintsNotHandledForDescendantsIn(aHintsHandledByAncestors))
 | 
						|
  , mParentFrameHintsNotHandledForDescendants(nsChangeHint(0))
 | 
						|
  , mHintsNotHandledForDescendants(nsChangeHint(0))
 | 
						|
  , mRestyleTracker(aRestyleTracker)
 | 
						|
  , mSelectorsForDescendants(aSelectorsForDescendants)
 | 
						|
  , mTreeMatchContext(aTreeMatchContext)
 | 
						|
  , mResolvedChild(nullptr)
 | 
						|
  , mContextsToClear(aContextsToClear)
 | 
						|
  , mSwappedStructOwners(aSwappedStructOwners)
 | 
						|
  , mIsRootOfRestyle(true)
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  , mDesiredA11yNotifications(eSendAllNotifications)
 | 
						|
  , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
 | 
						|
  , mOurA11yNotification(eDontNotify)
 | 
						|
  , mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
 | 
						|
#endif
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::AddLayerChangesForAnimation()
 | 
						|
{
 | 
						|
  // Bug 847286 - We should have separate animation generation counters
 | 
						|
  // on layers for transitions and animations and use != comparison below
 | 
						|
  // rather than a > comparison.
 | 
						|
  uint64_t frameGeneration =
 | 
						|
    RestyleManager::GetAnimationGenerationForFrame(mFrame);
 | 
						|
 | 
						|
  nsChangeHint hint = nsChangeHint(0);
 | 
						|
  for (const LayerAnimationInfo::Record& layerInfo :
 | 
						|
         LayerAnimationInfo::sRecords) {
 | 
						|
    Layer* layer =
 | 
						|
      FrameLayerBuilder::GetDedicatedLayer(mFrame, layerInfo.mLayerType);
 | 
						|
    if (layer && frameGeneration > layer->GetAnimationGeneration()) {
 | 
						|
      // If we have a transform layer but don't have any transform style, we
 | 
						|
      // probably just removed the transform but haven't destroyed the layer
 | 
						|
      // yet. In this case we will add the appropriate change hint
 | 
						|
      // (nsChangeHint_UpdateContainingBlock) when we compare style contexts
 | 
						|
      // so we can skip adding any change hint here. (If we *were* to add
 | 
						|
      // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
 | 
						|
      // complain that we're updating a transform layer without a transform).
 | 
						|
      if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
 | 
						|
          !mFrame->StyleDisplay()->HasTransformStyle()) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      hint |= layerInfo.mChangeHint;
 | 
						|
    }
 | 
						|
 | 
						|
    // We consider it's the first paint for the frame if we have an animation
 | 
						|
    // for the property but have no layer.
 | 
						|
    // Note that in case of animations which has properties preventing running
 | 
						|
    // on the compositor, e.g., width or height, corresponding layer is not
 | 
						|
    // created at all, but even in such cases, we normally set valid change
 | 
						|
    // hint for such animations in each tick, i.e. restyles in each tick. As
 | 
						|
    // a result, we usually do restyles for such animations in every tick on
 | 
						|
    // the main-thread.  The only animations which will be affected by this
 | 
						|
    // explicit change hint are animations that have opacity/transform but did
 | 
						|
    // not have those properies just before. e.g,  setting transform by
 | 
						|
    // setKeyframes or changing target element from other target which prevents
 | 
						|
    // running on the compositor, etc.
 | 
						|
    if (!layer &&
 | 
						|
        nsLayoutUtils::HasRelevantAnimationOfProperty(mFrame,
 | 
						|
                                                      layerInfo.mProperty)) {
 | 
						|
      hint |= layerInfo.mChangeHint;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (hint) {
 | 
						|
    mChangeList->AppendChange(mFrame, mContent, hint);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
 | 
						|
                               nsStyleContext* aNewContext,
 | 
						|
                               nsChangeHint aChangeToAssume,
 | 
						|
                               uint32_t* aEqualStructs,
 | 
						|
                               uint32_t* aSamePointerStructs)
 | 
						|
{
 | 
						|
  static_assert(nsStyleStructID_Length <= 32,
 | 
						|
                "aEqualStructs is not big enough");
 | 
						|
 | 
						|
  // Check some invariants about replacing one style context with another.
 | 
						|
  NS_ASSERTION(aOldContext->GetPseudo() == aNewContext->GetPseudo(),
 | 
						|
               "old and new style contexts should have the same pseudo");
 | 
						|
  NS_ASSERTION(aOldContext->GetPseudoType() == aNewContext->GetPseudoType(),
 | 
						|
               "old and new style contexts should have the same pseudo");
 | 
						|
 | 
						|
  nsChangeHint ourChange =
 | 
						|
    aOldContext->CalcStyleDifference(aNewContext,
 | 
						|
                                     mParentFrameHintsNotHandledForDescendants,
 | 
						|
                                     aEqualStructs,
 | 
						|
                                     aSamePointerStructs);
 | 
						|
  NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) ||
 | 
						|
               (ourChange & nsChangeHint_NeedReflow),
 | 
						|
               "Reflow hint bits set without actually asking for a reflow");
 | 
						|
 | 
						|
  LOG_RESTYLE("CaptureChange, ourChange = %s, aChangeToAssume = %s",
 | 
						|
              RestyleManager::ChangeHintToString(ourChange).get(),
 | 
						|
              RestyleManager::ChangeHintToString(aChangeToAssume).get());
 | 
						|
  LOG_RESTYLE_INDENT();
 | 
						|
 | 
						|
  // nsChangeHint_UpdateEffects is inherited, but it can be set due to changes
 | 
						|
  // in inherited properties (fill and stroke).  Avoid propagating it into
 | 
						|
  // text nodes.
 | 
						|
  if ((ourChange & nsChangeHint_UpdateEffects) &&
 | 
						|
      mContent && !mContent->IsElement()) {
 | 
						|
    ourChange &= ~nsChangeHint_UpdateEffects;
 | 
						|
  }
 | 
						|
 | 
						|
  ourChange |= aChangeToAssume;
 | 
						|
  if (!NS_IsHintSubset(ourChange, mHintsHandled)) {
 | 
						|
    mHintsHandled |= ourChange;
 | 
						|
    if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) {
 | 
						|
      LOG_RESTYLE("appending change %s",
 | 
						|
                  RestyleManager::ChangeHintToString(ourChange).get());
 | 
						|
      mChangeList->AppendChange(mFrame, mContent, ourChange);
 | 
						|
    } else {
 | 
						|
      LOG_RESTYLE("change has already been handled");
 | 
						|
    }
 | 
						|
  }
 | 
						|
  mHintsNotHandledForDescendants |=
 | 
						|
    NS_HintsNotHandledForDescendantsIn(ourChange);
 | 
						|
  LOG_RESTYLE("mHintsNotHandledForDescendants = %s",
 | 
						|
              RestyleManager::ChangeHintToString(mHintsNotHandledForDescendants).get());
 | 
						|
}
 | 
						|
 | 
						|
class MOZ_RAII AutoSelectorArrayTruncater final
 | 
						|
{
 | 
						|
public:
 | 
						|
  explicit AutoSelectorArrayTruncater(
 | 
						|
        nsTArray<nsCSSSelector*>& aSelectorsForDescendants)
 | 
						|
    : mSelectorsForDescendants(aSelectorsForDescendants)
 | 
						|
    , mOriginalLength(aSelectorsForDescendants.Length())
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  ~AutoSelectorArrayTruncater()
 | 
						|
  {
 | 
						|
    mSelectorsForDescendants.TruncateLength(mOriginalLength);
 | 
						|
  }
 | 
						|
 | 
						|
private:
 | 
						|
  nsTArray<nsCSSSelector*>& mSelectorsForDescendants;
 | 
						|
  size_t mOriginalLength;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Called when we are stopping a restyle with eRestyle_SomeDescendants, to
 | 
						|
 * search for descendants that match any of the selectors in
 | 
						|
 * mSelectorsForDescendants.  If the element does match one of the selectors,
 | 
						|
 * we cause it to be restyled with eRestyle_Self.
 | 
						|
 *
 | 
						|
 * We traverse down the frame tree (and through the flattened content tree
 | 
						|
 * when we find undisplayed content) unless we find an element that (a) already
 | 
						|
 * has a pending restyle, or (b) does not have a pending restyle but does match
 | 
						|
 * one of the selectors in mSelectorsForDescendants.  For (a), we add the
 | 
						|
 * current mSelectorsForDescendants into the existing restyle data, and for (b)
 | 
						|
 * we add a new pending restyle with that array.  So in both cases, when we
 | 
						|
 * come to restyling this element back up in ProcessPendingRestyles, we will
 | 
						|
 * again find the eRestyle_SomeDescendants hint and its selectors array.
 | 
						|
 *
 | 
						|
 * This ensures that we don't visit descendant elements and check them
 | 
						|
 * against mSelectorsForDescendants more than once.
 | 
						|
 */
 | 
						|
void
 | 
						|
ElementRestyler::ConditionallyRestyleChildren()
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mContent == mFrame->GetContent());
 | 
						|
 | 
						|
  if (!mContent->IsElement() || mSelectorsForDescendants.IsEmpty()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Element* element = mContent->AsElement();
 | 
						|
 | 
						|
  LOG_RESTYLE("traversing descendants of frame %s (with element %s) to "
 | 
						|
              "propagate eRestyle_SomeDescendants for these %d selectors:",
 | 
						|
              FrameTagToString(mFrame).get(),
 | 
						|
              ElementTagToString(element).get(),
 | 
						|
              int(mSelectorsForDescendants.Length()));
 | 
						|
  LOG_RESTYLE_INDENT();
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
  for (nsCSSSelector* sel : mSelectorsForDescendants) {
 | 
						|
    LOG_RESTYLE("%s", sel->RestrictedSelectorToString().get());
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  Element* restyleRoot = mRestyleTracker.FindClosestRestyleRoot(element);
 | 
						|
  ConditionallyRestyleChildren(mFrame, restyleRoot);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::ConditionallyRestyleChildren(nsIFrame* aFrame,
 | 
						|
                                              Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aFrame->GetContent());
 | 
						|
  MOZ_ASSERT(aFrame->GetContent()->IsElement());
 | 
						|
  MOZ_ASSERT(!aFrame->GetContent()->IsStyledByServo());
 | 
						|
 | 
						|
  ConditionallyRestyleUndisplayedDescendants(aFrame, aRestyleRoot);
 | 
						|
  ConditionallyRestyleContentChildren(aFrame, aRestyleRoot);
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels RestyleContentChildren.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::ConditionallyRestyleContentChildren(nsIFrame* aFrame,
 | 
						|
                                                     Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aFrame->GetContent());
 | 
						|
  MOZ_ASSERT(aFrame->GetContent()->IsElement());
 | 
						|
  MOZ_ASSERT(!aFrame->GetContent()->IsStyledByServo());
 | 
						|
 | 
						|
  if (aFrame->GetContent()->HasFlag(mRestyleTracker.RootBit())) {
 | 
						|
    aRestyleRoot = aFrame->GetContent()->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  for (nsIFrame* f = aFrame; f;
 | 
						|
       f = RestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
 | 
						|
    nsIFrame::ChildListIterator lists(f);
 | 
						|
    for (; !lists.IsDone(); lists.Next()) {
 | 
						|
      for (nsIFrame* child : lists.CurrentList()) {
 | 
						|
        // Out-of-flows are reached through their placeholders.  Continuations
 | 
						|
        // and block-in-inline splits are reached through those chains.
 | 
						|
        if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
 | 
						|
            !GetPrevContinuationWithSameStyle(child)) {
 | 
						|
          // only do frames that are in flow
 | 
						|
          if (child->GetType() == nsGkAtoms::placeholderFrame) { // placeholder
 | 
						|
            // get out of flow frame and recur there
 | 
						|
            nsIFrame* outOfFlowFrame =
 | 
						|
              nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
 | 
						|
 | 
						|
            // |nsFrame::GetParentStyleContext| checks being out
 | 
						|
            // of flow so that this works correctly.
 | 
						|
            do {
 | 
						|
              if (GetPrevContinuationWithSameStyle(outOfFlowFrame)) {
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
              if (!ConditionallyRestyle(outOfFlowFrame, aRestyleRoot)) {
 | 
						|
                ConditionallyRestyleChildren(outOfFlowFrame, aRestyleRoot);
 | 
						|
              }
 | 
						|
            } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
 | 
						|
          } else {  // regular child frame
 | 
						|
            if (child != mResolvedChild) {
 | 
						|
              if (!ConditionallyRestyle(child, aRestyleRoot)) {
 | 
						|
                ConditionallyRestyleChildren(child, aRestyleRoot);
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels RestyleUndisplayedDescendants.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::ConditionallyRestyleUndisplayedDescendants(
 | 
						|
    nsIFrame* aFrame,
 | 
						|
    Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  nsIContent* undisplayedParent;
 | 
						|
  if (MustCheckUndisplayedContent(aFrame, undisplayedParent)) {
 | 
						|
    DoConditionallyRestyleUndisplayedDescendants(undisplayedParent,
 | 
						|
                                                 aRestyleRoot);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels DoRestyleUndisplayedDescendants.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::DoConditionallyRestyleUndisplayedDescendants(
 | 
						|
    nsIContent* aParent,
 | 
						|
    Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
 | 
						|
  UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
 | 
						|
  ConditionallyRestyleUndisplayedNodes(nodes, aParent,
 | 
						|
                                       StyleDisplay::None_, aRestyleRoot);
 | 
						|
  nodes = fc->GetAllDisplayContentsIn(aParent);
 | 
						|
  ConditionallyRestyleUndisplayedNodes(nodes, aParent,
 | 
						|
                                       StyleDisplay::Contents, aRestyleRoot);
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels RestyleUndisplayedNodes.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::ConditionallyRestyleUndisplayedNodes(
 | 
						|
    UndisplayedNode* aUndisplayed,
 | 
						|
    nsIContent* aUndisplayedParent,
 | 
						|
    const StyleDisplay aDisplay,
 | 
						|
    Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aDisplay == StyleDisplay::None_ ||
 | 
						|
             aDisplay == StyleDisplay::Contents);
 | 
						|
  if (!aUndisplayed) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aUndisplayedParent &&
 | 
						|
      aUndisplayedParent->IsElement() &&
 | 
						|
      aUndisplayedParent->HasFlag(mRestyleTracker.RootBit())) {
 | 
						|
    MOZ_ASSERT(!aUndisplayedParent->IsStyledByServo());
 | 
						|
    aRestyleRoot = aUndisplayedParent->AsElement();
 | 
						|
  }
 | 
						|
 | 
						|
  for (UndisplayedNode* undisplayed = aUndisplayed; undisplayed;
 | 
						|
       undisplayed = undisplayed->mNext) {
 | 
						|
 | 
						|
    if (!undisplayed->mContent->IsElement()) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Element* element = undisplayed->mContent->AsElement();
 | 
						|
 | 
						|
    if (!ConditionallyRestyle(element, aRestyleRoot)) {
 | 
						|
      if (aDisplay == StyleDisplay::None_) {
 | 
						|
        ConditionallyRestyleContentDescendants(element, aRestyleRoot);
 | 
						|
      } else {  // StyleDisplay::Contents
 | 
						|
        DoConditionallyRestyleUndisplayedDescendants(element, aRestyleRoot);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::ConditionallyRestyleContentDescendants(Element* aElement,
 | 
						|
                                                        Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!aElement->IsStyledByServo());
 | 
						|
  if (aElement->HasFlag(mRestyleTracker.RootBit())) {
 | 
						|
    aRestyleRoot = aElement;
 | 
						|
  }
 | 
						|
 | 
						|
  FlattenedChildIterator it(aElement);
 | 
						|
  for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
 | 
						|
    if (n->IsElement()) {
 | 
						|
      Element* e = n->AsElement();
 | 
						|
      if (!ConditionallyRestyle(e, aRestyleRoot)) {
 | 
						|
        ConditionallyRestyleContentDescendants(e, aRestyleRoot);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aFrame->GetContent());
 | 
						|
 | 
						|
  if (!aFrame->GetContent()->IsElement()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  return ConditionallyRestyle(aFrame->GetContent()->AsElement(), aRestyleRoot);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::ConditionallyRestyle(Element* aElement, Element* aRestyleRoot)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!aElement->IsStyledByServo());
 | 
						|
  LOG_RESTYLE("considering element %s for eRestyle_SomeDescendants",
 | 
						|
              ElementTagToString(aElement).get());
 | 
						|
  LOG_RESTYLE_INDENT();
 | 
						|
 | 
						|
  if (aElement->HasFlag(mRestyleTracker.RootBit())) {
 | 
						|
    aRestyleRoot = aElement;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mRestyleTracker.HasRestyleData(aElement)) {
 | 
						|
    nsRestyleHint rshint = eRestyle_SomeDescendants;
 | 
						|
    if (SelectorMatchesForRestyle(aElement)) {
 | 
						|
      LOG_RESTYLE("element has existing restyle data and matches a selector");
 | 
						|
      rshint |= eRestyle_Self;
 | 
						|
    } else {
 | 
						|
      LOG_RESTYLE("element has existing restyle data but doesn't match selectors");
 | 
						|
    }
 | 
						|
    RestyleHintData data;
 | 
						|
    data.mSelectorsForDescendants = mSelectorsForDescendants;
 | 
						|
    mRestyleTracker.AddPendingRestyle(aElement, rshint, nsChangeHint(0), &data,
 | 
						|
                                      Some(aRestyleRoot));
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SelectorMatchesForRestyle(aElement)) {
 | 
						|
    LOG_RESTYLE("element has no restyle data but matches a selector");
 | 
						|
    RestyleHintData data;
 | 
						|
    data.mSelectorsForDescendants = mSelectorsForDescendants;
 | 
						|
    mRestyleTracker.AddPendingRestyle(aElement,
 | 
						|
                                      eRestyle_Self | eRestyle_SomeDescendants,
 | 
						|
                                      nsChangeHint(0), &data,
 | 
						|
                                      Some(aRestyleRoot));
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::MustCheckUndisplayedContent(nsIFrame* aFrame,
 | 
						|
                                             nsIContent*& aUndisplayedParent)
 | 
						|
{
 | 
						|
  // When the root element is display:none, we still construct *some*
 | 
						|
  // frames that have the root element as their mContent, down to the
 | 
						|
  // DocElementContainingBlock.
 | 
						|
  if (aFrame->StyleContext()->GetPseudo()) {
 | 
						|
    aUndisplayedParent = nullptr;
 | 
						|
    return aFrame == mPresContext->FrameConstructor()->
 | 
						|
                       GetDocElementContainingBlock();
 | 
						|
  }
 | 
						|
 | 
						|
  aUndisplayedParent = aFrame->GetContent();
 | 
						|
  return !!aUndisplayedParent;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Helper for MoveStyleContextsForChildren, below.  Appends the style
 | 
						|
 * contexts to be moved to mFrame's current (new) style context to
 | 
						|
 * aContextsToMove.
 | 
						|
 */
 | 
						|
bool
 | 
						|
ElementRestyler::MoveStyleContextsForContentChildren(
 | 
						|
    nsIFrame* aParent,
 | 
						|
    nsStyleContext* aOldContext,
 | 
						|
    nsTArray<nsStyleContext*>& aContextsToMove)
 | 
						|
{
 | 
						|
  nsIFrame::ChildListIterator lists(aParent);
 | 
						|
  for (; !lists.IsDone(); lists.Next()) {
 | 
						|
    for (nsIFrame* child : lists.CurrentList()) {
 | 
						|
      // Bail out if we have out-of-flow frames.
 | 
						|
      // FIXME: It might be safe to just continue here instead of bailing out.
 | 
						|
      if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (GetPrevContinuationWithSameStyle(child)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      // Bail out if we have placeholder frames.
 | 
						|
      // FIXME: It is probably safe to just continue here instead of bailing out.
 | 
						|
      if (nsGkAtoms::placeholderFrame == child->GetType()) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      nsStyleContext* sc = child->StyleContext();
 | 
						|
      if (sc->GetParent() != aOldContext) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      nsIAtom* type = child->GetType();
 | 
						|
      if (type == nsGkAtoms::letterFrame ||
 | 
						|
          type == nsGkAtoms::lineFrame) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (sc->HasChildThatUsesGrandancestorStyle()) {
 | 
						|
        // XXX Not sure if we need this?
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      nsIAtom* pseudoTag = sc->GetPseudo();
 | 
						|
      if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      aContextsToMove.AppendElement(sc);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Traverses to child elements (through the current frame's same style
 | 
						|
 * continuations, just like RestyleChildren does) and moves any style context
 | 
						|
 * for those children to be parented under mFrame's current (new) style
 | 
						|
 * context.
 | 
						|
 *
 | 
						|
 * False is returned if it encounters any conditions on the child elements'
 | 
						|
 * frames and style contexts that means it is impossible to move a
 | 
						|
 * style context.  If false is returned, no style contexts will have been
 | 
						|
 * moved.
 | 
						|
 */
 | 
						|
bool
 | 
						|
ElementRestyler::MoveStyleContextsForChildren(nsStyleContext* aOldContext)
 | 
						|
{
 | 
						|
  // Bail out if there are undisplayed or display:contents children.
 | 
						|
  // FIXME: We could get this to work if we need to.
 | 
						|
  nsIContent* undisplayedParent;
 | 
						|
  if (MustCheckUndisplayedContent(mFrame, undisplayedParent)) {
 | 
						|
    nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
 | 
						|
    if (fc->GetAllUndisplayedContentIn(undisplayedParent) ||
 | 
						|
        fc->GetAllDisplayContentsIn(undisplayedParent)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsTArray<nsStyleContext*> contextsToMove;
 | 
						|
 | 
						|
  MOZ_ASSERT(!MustReframeForBeforePseudo(),
 | 
						|
             "shouldn't need to reframe ::before as we would have had "
 | 
						|
             "eRestyle_Subtree and wouldn't get in here");
 | 
						|
 | 
						|
  DebugOnly<nsIFrame*> lastContinuation;
 | 
						|
  for (nsIFrame* f = mFrame; f;
 | 
						|
       f = RestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
 | 
						|
    lastContinuation = f;
 | 
						|
    if (!MoveStyleContextsForContentChildren(f, aOldContext, contextsToMove)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(!MustReframeForAfterPseudo(lastContinuation),
 | 
						|
             "shouldn't need to reframe ::after as we would have had "
 | 
						|
             "eRestyle_Subtree and wouldn't get in here");
 | 
						|
 | 
						|
  nsStyleContext* newParent = mFrame->StyleContext();
 | 
						|
  for (nsStyleContext* child : contextsToMove) {
 | 
						|
    // We can have duplicate entries in contextsToMove, so only move
 | 
						|
    // each style context once.
 | 
						|
    if (child->GetParent() != newParent) {
 | 
						|
      child->MoveTo(newParent);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Recompute style for mFrame (which should not have a prev continuation
 | 
						|
 * with the same style), all of its next continuations with the same
 | 
						|
 * style, and all ib-split siblings of the same type (either block or
 | 
						|
 * inline, skipping the intermediates of the other type) and accumulate
 | 
						|
 * changes into mChangeList given that mHintsHandled is already accumulated
 | 
						|
 * for an ancestor.
 | 
						|
 * mParentContent is the content node used to resolve the parent style
 | 
						|
 * context.  This means that, for pseudo-elements, it is the content
 | 
						|
 * that should be used for selector matching (rather than the fake
 | 
						|
 * content node attached to the frame).
 | 
						|
 */
 | 
						|
void
 | 
						|
ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
 | 
						|
{
 | 
						|
  // It would be nice if we could make stronger assertions here; they
 | 
						|
  // would let us simplify the ?: expressions below setting |content|
 | 
						|
  // and |pseudoContent| in sensible ways as well as making what
 | 
						|
  // |content| and |pseudoContent| mean, and their relationship to
 | 
						|
  // |mFrame->GetContent()|, make more sense.  However, we can't,
 | 
						|
  // because of frame trees like the one in
 | 
						|
  // https://bugzilla.mozilla.org/show_bug.cgi?id=472353#c14 .  Once we
 | 
						|
  // fix bug 242277 we should be able to make this make more sense.
 | 
						|
  NS_ASSERTION(mFrame->GetContent() || !mParentContent ||
 | 
						|
               !mParentContent->GetParent(),
 | 
						|
               "frame must have content (unless at the top of the tree)");
 | 
						|
  MOZ_ASSERT(mPresContext == mFrame->PresContext(), "pres contexts match");
 | 
						|
 | 
						|
  NS_ASSERTION(!GetPrevContinuationWithSameStyle(mFrame),
 | 
						|
               "should not be trying to restyle this frame separately");
 | 
						|
 | 
						|
  MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
 | 
						|
             "eRestyle_LaterSiblings must not be part of aRestyleHint");
 | 
						|
 | 
						|
  mPresContext->RestyledElement();
 | 
						|
 | 
						|
  AutoDisplayContentsAncestorPusher adcp(mTreeMatchContext, mPresContext,
 | 
						|
      mFrame->GetContent() ? mFrame->GetContent()->GetParent() : nullptr);
 | 
						|
 | 
						|
  AutoSelectorArrayTruncater asat(mSelectorsForDescendants);
 | 
						|
 | 
						|
  // List of descendant elements of mContent we know we will eventually need to
 | 
						|
  // restyle.  Before we return from this function, we call
 | 
						|
  // RestyleTracker::AddRestyleRootsIfAwaitingRestyle to ensure they get
 | 
						|
  // restyled in RestyleTracker::DoProcessRestyles.
 | 
						|
  nsTArray<RefPtr<Element>> descendants;
 | 
						|
 | 
						|
  nsRestyleHint hintToRestore = nsRestyleHint(0);
 | 
						|
  RestyleHintData hintDataToRestore;
 | 
						|
  if (mContent && mContent->IsElement() &&
 | 
						|
      // If we're resolving from the root of the frame tree (which
 | 
						|
      // we do when mDoRebuildAllStyleData), we need to avoid getting the
 | 
						|
      // root's restyle data until we get to its primary frame, since
 | 
						|
      // it's the primary frame that has the styles for the root element
 | 
						|
      // (rather than the ancestors of the primary frame whose mContent
 | 
						|
      // is the root node but which have different styles).  If we use
 | 
						|
      // up the hint for one of the ancestors that we hit first, then
 | 
						|
      // we'll fail to do the restyling we need to do.
 | 
						|
      // Likewise, if we're restyling something with two nested frames,
 | 
						|
      // and we post a restyle from the transition manager while
 | 
						|
      // computing style for the outer frame (to be computed after the
 | 
						|
      // descendants have been resolved), we don't want to consume it
 | 
						|
      // for the inner frame.
 | 
						|
      mContent->GetPrimaryFrame() == mFrame) {
 | 
						|
    mContent->OwnerDoc()->FlushPendingLinkUpdates();
 | 
						|
    nsAutoPtr<RestyleTracker::RestyleData> restyleData;
 | 
						|
    if (mRestyleTracker.GetRestyleData(mContent->AsElement(), restyleData)) {
 | 
						|
      if (!NS_IsHintSubset(restyleData->mChangeHint, mHintsHandled)) {
 | 
						|
        mHintsHandled |= restyleData->mChangeHint;
 | 
						|
        mChangeList->AppendChange(mFrame, mContent, restyleData->mChangeHint);
 | 
						|
      }
 | 
						|
      mSelectorsForDescendants.AppendElements(
 | 
						|
          restyleData->mRestyleHintData.mSelectorsForDescendants);
 | 
						|
      hintToRestore = restyleData->mRestyleHint;
 | 
						|
      hintDataToRestore = Move(restyleData->mRestyleHintData);
 | 
						|
      aRestyleHint = nsRestyleHint(aRestyleHint | restyleData->mRestyleHint);
 | 
						|
      descendants.SwapElements(restyleData->mDescendants);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // If we are restyling this frame with eRestyle_Self or weaker hints,
 | 
						|
  // we restyle children with nsRestyleHint(0).  But we pass the
 | 
						|
  // eRestyle_ForceDescendants flag down too.
 | 
						|
  nsRestyleHint childRestyleHint =
 | 
						|
    nsRestyleHint(aRestyleHint & (eRestyle_SomeDescendants |
 | 
						|
                                  eRestyle_Subtree |
 | 
						|
                                  eRestyle_ForceDescendants));
 | 
						|
 | 
						|
  RefPtr<nsStyleContext> oldContext = mFrame->StyleContext();
 | 
						|
 | 
						|
  nsTArray<SwapInstruction> swaps;
 | 
						|
 | 
						|
  // TEMPORARY (until bug 918064):  Call RestyleSelf for each
 | 
						|
  // continuation or block-in-inline sibling.
 | 
						|
 | 
						|
  // We must make a single decision on how to process this frame and
 | 
						|
  // its descendants, yet RestyleSelf might return different RestyleResult
 | 
						|
  // values for the different same-style continuations.  |result| is our
 | 
						|
  // overall decision.
 | 
						|
  RestyleResult result = RestyleResult::eNone;
 | 
						|
  uint32_t swappedStructs = 0;
 | 
						|
 | 
						|
  nsRestyleHint thisRestyleHint = aRestyleHint;
 | 
						|
 | 
						|
  bool haveMoreContinuations = false;
 | 
						|
  for (nsIFrame* f = mFrame; f; ) {
 | 
						|
    RestyleResult thisResult =
 | 
						|
      RestyleSelf(f, thisRestyleHint, &swappedStructs, swaps);
 | 
						|
 | 
						|
    if (thisResult != RestyleResult::eStop) {
 | 
						|
      // Calls to RestyleSelf for later same-style continuations must not
 | 
						|
      // return RestyleResult::eStop, so pass eRestyle_Force in to them.
 | 
						|
      thisRestyleHint = nsRestyleHint(thisRestyleHint | eRestyle_Force);
 | 
						|
 | 
						|
      if (result == RestyleResult::eStop) {
 | 
						|
        // We received RestyleResult::eStop for earlier same-style
 | 
						|
        // continuations, and RestyleResult::eStopWithStyleChange or
 | 
						|
        // RestyleResult::eContinue(AndForceDescendants) for this one; go
 | 
						|
        // back and force-restyle the earlier continuations.
 | 
						|
        result = thisResult;
 | 
						|
        f = mFrame;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (thisResult > result) {
 | 
						|
      // We take the highest RestyleResult value when working out what to do
 | 
						|
      // with this frame and its descendants.  Higher RestyleResult values
 | 
						|
      // represent a superset of the work done by lower values.
 | 
						|
      result = thisResult;
 | 
						|
    }
 | 
						|
 | 
						|
    f = RestyleManager::GetNextContinuationWithSameStyle(f,
 | 
						|
                                                         oldContext,
 | 
						|
                                                         &haveMoreContinuations);
 | 
						|
  }
 | 
						|
 | 
						|
  // Some changes to animations don't affect the computed style and yet still
 | 
						|
  // require the layer to be updated. For example, pausing an animation via
 | 
						|
  // the Web Animations API won't affect an element's style but still
 | 
						|
  // requires us to pull the animation off the layer.
 | 
						|
  //
 | 
						|
  // Although we only expect this code path to be called when computed style
 | 
						|
  // is not changing, we can sometimes reach this at the end of a transition
 | 
						|
  // when the animated style is being removed. Since
 | 
						|
  // AddLayerChangesForAnimation checks if mFrame has a transform style or not,
 | 
						|
  // we need to call it *after* calling RestyleSelf to ensure the animated
 | 
						|
  // transform has been removed first.
 | 
						|
  AddLayerChangesForAnimation();
 | 
						|
 | 
						|
  if (haveMoreContinuations && hintToRestore) {
 | 
						|
    // If we have more continuations with different style (e.g., because
 | 
						|
    // we're inside a ::first-letter or ::first-line), put the restyle
 | 
						|
    // hint back.
 | 
						|
    mRestyleTracker.AddPendingRestyleToTable(mContent->AsElement(),
 | 
						|
                                             hintToRestore, nsChangeHint(0));
 | 
						|
  }
 | 
						|
 | 
						|
  if (result == RestyleResult::eStop) {
 | 
						|
    MOZ_ASSERT(mFrame->StyleContext() == oldContext,
 | 
						|
               "frame should have been left with its old style context");
 | 
						|
 | 
						|
    nsIFrame* unused;
 | 
						|
    nsStyleContext* newParent = mFrame->GetParentStyleContext(&unused);
 | 
						|
    if (oldContext->GetParent() != newParent) {
 | 
						|
      // If we received RestyleResult::eStop, then the old style context was
 | 
						|
      // left on mFrame.  Since we ended up restyling our parent, change
 | 
						|
      // this old style context to point to its new parent.
 | 
						|
      LOG_RESTYLE("moving style context %p from old parent %p to new parent %p",
 | 
						|
                  oldContext.get(), oldContext->GetParent(), newParent);
 | 
						|
      // We keep strong references to the new parent around until the end
 | 
						|
      // of the restyle, in case:
 | 
						|
      //   (a) we swapped structs between the old and new parent,
 | 
						|
      //   (b) some descendants of the old parent are not getting restyled
 | 
						|
      //       (which is the reason for the existence of
 | 
						|
      //       ClearCachedInheritedStyleDataOnDescendants),
 | 
						|
      //   (c) something under ProcessPendingRestyles (which notably is called
 | 
						|
      //       *before* ClearCachedInheritedStyleDataOnDescendants is called
 | 
						|
      //       on the old context) causes the new parent to be destroyed, thus
 | 
						|
      //       destroying its owned structs, and
 | 
						|
      //   (d) something under ProcessPendingRestyles then wants to use of those
 | 
						|
      //       now destroyed structs (through the old parent's descendants).
 | 
						|
      mSwappedStructOwners.AppendElement(newParent);
 | 
						|
      oldContext->MoveTo(newParent);
 | 
						|
    }
 | 
						|
 | 
						|
    // Send the accessibility notifications that RestyleChildren otherwise
 | 
						|
    // would have sent.
 | 
						|
    if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
      InitializeAccessibilityNotifications(mFrame->StyleContext());
 | 
						|
      SendAccessibilityNotifications();
 | 
						|
    }
 | 
						|
 | 
						|
    mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
 | 
						|
    if (aRestyleHint & eRestyle_SomeDescendants) {
 | 
						|
      ConditionallyRestyleChildren();
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (result == RestyleResult::eStopWithStyleChange &&
 | 
						|
      !(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
    MOZ_ASSERT(mFrame->StyleContext() != oldContext,
 | 
						|
               "RestyleResult::eStopWithStyleChange should only be returned "
 | 
						|
               "if we got a new style context or we will reconstruct");
 | 
						|
    MOZ_ASSERT(swappedStructs == 0,
 | 
						|
               "should have ensured we didn't swap structs when "
 | 
						|
               "returning RestyleResult::eStopWithStyleChange");
 | 
						|
 | 
						|
    // We need to ensure that all of the frames that inherit their style
 | 
						|
    // from oldContext are able to be moved across to newContext.
 | 
						|
    // MoveStyleContextsForChildren will check for certain conditions
 | 
						|
    // to ensure it is safe to move all of the relevant child style
 | 
						|
    // contexts to newContext.  If these conditions fail, it will
 | 
						|
    // return false, and we'll have to continue restyling.
 | 
						|
    const bool canStop = MoveStyleContextsForChildren(oldContext);
 | 
						|
 | 
						|
    if (canStop) {
 | 
						|
      // Send the accessibility notifications that RestyleChildren otherwise
 | 
						|
      // would have sent.
 | 
						|
      if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
        InitializeAccessibilityNotifications(mFrame->StyleContext());
 | 
						|
        SendAccessibilityNotifications();
 | 
						|
      }
 | 
						|
 | 
						|
      mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
 | 
						|
      if (aRestyleHint & eRestyle_SomeDescendants) {
 | 
						|
        ConditionallyRestyleChildren();
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Turns out we couldn't stop restyling here.  Process the struct
 | 
						|
    // swaps that RestyleSelf would've done had we not returned
 | 
						|
    // RestyleResult::eStopWithStyleChange.
 | 
						|
    for (SwapInstruction& swap : swaps) {
 | 
						|
      LOG_RESTYLE("swapping style structs between %p and %p",
 | 
						|
                  swap.mOldContext.get(), swap.mNewContext.get());
 | 
						|
      swap.mOldContext->SwapStyleData(swap.mNewContext, swap.mStructsToSwap);
 | 
						|
      swappedStructs |= swap.mStructsToSwap;
 | 
						|
    }
 | 
						|
    swaps.Clear();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!swappedStructs) {
 | 
						|
    // If we swapped any structs from the old context, then we need to keep
 | 
						|
    // it alive until after the RestyleChildren call so that we can fix up
 | 
						|
    // its descendants' cached structs.
 | 
						|
    oldContext = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  if (result == RestyleResult::eContinueAndForceDescendants) {
 | 
						|
    childRestyleHint =
 | 
						|
      nsRestyleHint(childRestyleHint | eRestyle_ForceDescendants);
 | 
						|
  }
 | 
						|
 | 
						|
  // No need to do this if we're planning to reframe already.
 | 
						|
  // It's also important to check mHintsHandled since we use
 | 
						|
  // mFrame->StyleContext(), which is out of date if mHintsHandled
 | 
						|
  // has a ReconstructFrame hint.  Using an out of date style
 | 
						|
  // context could trigger assertions about mismatched rule trees.
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
    RestyleChildren(childRestyleHint);
 | 
						|
  }
 | 
						|
 | 
						|
  if (oldContext && !oldContext->HasSingleReference()) {
 | 
						|
    // If we swapped some structs out of oldContext in the RestyleSelf call
 | 
						|
    // and after the RestyleChildren call we still have other strong references
 | 
						|
    // to it, we need to make ensure its descendants don't cache any of the
 | 
						|
    // structs that were swapped out.
 | 
						|
    //
 | 
						|
    // Much of the time we will not get in here; we do for example when the
 | 
						|
    // style context is shared with a later IB split sibling (which we won't
 | 
						|
    // restyle until a bit later) or if other code is holding a strong reference
 | 
						|
    // to the style context (as is done by nsTransformedTextRun objects, which
 | 
						|
    // can be referenced by a text frame's mTextRun longer than the frame's
 | 
						|
    // mStyleContext).
 | 
						|
    //
 | 
						|
    // Also, we don't want this style context to get any more uses by being
 | 
						|
    // returned from nsStyleContext::FindChildWithRules, so we add the
 | 
						|
    // NS_STYLE_INELIGIBLE_FOR_SHARING bit to it.
 | 
						|
    oldContext->SetIneligibleForSharing();
 | 
						|
 | 
						|
    ContextToClear* toClear = mContextsToClear.AppendElement();
 | 
						|
    toClear->mStyleContext = Move(oldContext);
 | 
						|
    toClear->mStructs = swappedStructs;
 | 
						|
  }
 | 
						|
 | 
						|
  mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Depending on the details of the frame we are restyling or its old style
 | 
						|
 * context, we may or may not be able to stop restyling after this frame if
 | 
						|
 * we find we had no style changes.
 | 
						|
 *
 | 
						|
 * This function returns RestyleResult::eStop if it does not find any
 | 
						|
 * conditions that would preclude stopping restyling, and
 | 
						|
 * RestyleResult::eContinue if it does.
 | 
						|
 */
 | 
						|
void
 | 
						|
ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf,
 | 
						|
                                               RestyleResult& aRestyleResult,
 | 
						|
                                               bool& aCanStopWithStyleChange)
 | 
						|
{
 | 
						|
  // We can't handle situations where the primary style context of a frame
 | 
						|
  // has not had any style data changes, but its additional style contexts
 | 
						|
  // have, so we don't considering stopping if this frame has any additional
 | 
						|
  // style contexts.
 | 
						|
  if (aSelf->GetAdditionalStyleContext(0)) {
 | 
						|
    LOG_RESTYLE_CONTINUE("there are additional style contexts");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Style changes might have moved children between the two nsLetterFrames
 | 
						|
  // (the one matching ::first-letter and the one containing the rest of the
 | 
						|
  // content).  Continue restyling to the children of the nsLetterFrame so
 | 
						|
  // that they get the correct style context parent.  Similarly for
 | 
						|
  // nsLineFrames.
 | 
						|
  nsIAtom* type = aSelf->GetType();
 | 
						|
 | 
						|
  if (type == nsGkAtoms::letterFrame) {
 | 
						|
    LOG_RESTYLE_CONTINUE("frame is a letter frame");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (type == nsGkAtoms::lineFrame) {
 | 
						|
    LOG_RESTYLE_CONTINUE("frame is a line frame");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Some style computations depend not on the parent's style, but a grandparent
 | 
						|
  // or one the grandparent's ancestors.  An example is an explicit 'inherit'
 | 
						|
  // value for align-self, where if the parent frame's value for the property is
 | 
						|
  // 'auto' we end up inheriting the computed value from the grandparent.  We
 | 
						|
  // can't stop the restyling process on this frame (the one with 'auto', in
 | 
						|
  // this example), as the grandparent's computed value might have changed
 | 
						|
  // and we need to recompute the child's 'inherit' to that new value.
 | 
						|
  nsStyleContext* oldContext = aSelf->StyleContext();
 | 
						|
  if (oldContext->HasChildThatUsesGrandancestorStyle()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the old context uses grandancestor style");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // We ignore all situations that involve :visited style.
 | 
						|
  if (oldContext->GetStyleIfVisited()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the old style context has StyleIfVisited");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsStyleContext* parentContext = oldContext->GetParent();
 | 
						|
  if (parentContext && parentContext->GetStyleIfVisited()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the old style context's parent has StyleIfVisited");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // We also ignore frames for pseudos, as their style contexts have
 | 
						|
  // inheritance structures that do not match the frame inheritance
 | 
						|
  // structure.  To avoid enumerating and checking all of the cases
 | 
						|
  // where we have this kind of inheritance, we keep restyling past
 | 
						|
  // pseudos.
 | 
						|
  nsIAtom* pseudoTag = oldContext->GetPseudo();
 | 
						|
  if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsIFrame* parent = mFrame->GetParent();
 | 
						|
 | 
						|
  if (parent) {
 | 
						|
    // Also if the parent has a pseudo, as this frame's style context will
 | 
						|
    // be inheriting from a grandparent frame's style context (or a further
 | 
						|
    // ancestor).
 | 
						|
    nsIAtom* parentPseudoTag = parent->StyleContext()->GetPseudo();
 | 
						|
    if (parentPseudoTag &&
 | 
						|
        parentPseudoTag != nsCSSAnonBoxes::mozOtherNonElement) {
 | 
						|
      MOZ_ASSERT(parentPseudoTag != nsCSSAnonBoxes::mozText,
 | 
						|
                 "Style of text node should not be parent of anything");
 | 
						|
      LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
 | 
						|
      aRestyleResult = RestyleResult::eContinue;
 | 
						|
      // Parent style context pseudo-ness doesn't affect whether we can
 | 
						|
      // return RestyleResult::eStopWithStyleChange.
 | 
						|
      //
 | 
						|
      // If we had later conditions to check in this function, we would
 | 
						|
      // continue to check them, in case we set aCanStopWithStyleChange to
 | 
						|
      // false.
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
 | 
						|
                                                    nsStyleContext* aNewContext,
 | 
						|
                                                    RestyleResult& aRestyleResult,
 | 
						|
                                                    bool& aCanStopWithStyleChange)
 | 
						|
{
 | 
						|
  // If we've already determined that we must continue styling, we don't
 | 
						|
  // need to check anything.
 | 
						|
  if (aRestyleResult == RestyleResult::eContinue && !aCanStopWithStyleChange) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Keep restyling if the new style context has any style-if-visted style, so
 | 
						|
  // that we can avoid the style context tree surgery having to deal to deal
 | 
						|
  // with visited styles.
 | 
						|
  if (aNewContext->GetStyleIfVisited()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the new style context has StyleIfVisited");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // If link-related information has changed, or the pseudo for the frame has
 | 
						|
  // changed, or the new style context points to a different rule node, we can't
 | 
						|
  // leave the old style context on the frame.
 | 
						|
  nsStyleContext* oldContext = aSelf->StyleContext();
 | 
						|
  if (oldContext->IsLinkContext() != aNewContext->IsLinkContext() ||
 | 
						|
      oldContext->RelevantLinkVisited() != aNewContext->RelevantLinkVisited() ||
 | 
						|
      oldContext->GetPseudo() != aNewContext->GetPseudo() ||
 | 
						|
      oldContext->GetPseudoType() != aNewContext->GetPseudoType()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the old and new style contexts have different link/"
 | 
						|
                         "visited/pseudo");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (oldContext->RuleNode() != aNewContext->RuleNode()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("the old and new style contexts have different "
 | 
						|
                         "rulenodes");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    // Continue to check other conditions if aCanStopWithStyleChange might
 | 
						|
    // still need to be set to false.
 | 
						|
    if (!aCanStopWithStyleChange) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // If the old and new style contexts differ in their
 | 
						|
  // NS_STYLE_HAS_TEXT_DECORATION_LINES or NS_STYLE_HAS_PSEUDO_ELEMENT_DATA
 | 
						|
  // bits, then we must keep restyling so that those new bit values are
 | 
						|
  // propagated.
 | 
						|
  if (oldContext->HasTextDecorationLines() !=
 | 
						|
        aNewContext->HasTextDecorationLines()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_TEXT_DECORATION_LINES differs between old"
 | 
						|
                         " and new style contexts");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (oldContext->HasPseudoElementData() !=
 | 
						|
        aNewContext->HasPseudoElementData()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_PSEUDO_ELEMENT_DATA differs between old"
 | 
						|
                         " and new style contexts");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (oldContext->ShouldSuppressLineBreak() !=
 | 
						|
        aNewContext->ShouldSuppressLineBreak()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("NS_STYLE_SUPPRESS_LINEBREAK differs"
 | 
						|
                         "between old and new style contexts");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (oldContext->IsInDisplayNoneSubtree() !=
 | 
						|
        aNewContext->IsInDisplayNoneSubtree()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("NS_STYLE_IN_DISPLAY_NONE_SUBTREE differs between old"
 | 
						|
                         " and new style contexts");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (oldContext->IsTextCombined() != aNewContext->IsTextCombined()) {
 | 
						|
    LOG_RESTYLE_CONTINUE("NS_STYLE_IS_TEXT_COMBINED differs between "
 | 
						|
                         "old and new style contexts");
 | 
						|
    aRestyleResult = RestyleResult::eContinue;
 | 
						|
    aCanStopWithStyleChange = false;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::SelectorMatchesForRestyle(Element* aElement)
 | 
						|
{
 | 
						|
  if (!aElement) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  for (nsCSSSelector* selector : mSelectorsForDescendants) {
 | 
						|
    if (nsCSSRuleProcessor::RestrictedSelectorMatches(aElement, selector,
 | 
						|
                                                      mTreeMatchContext)) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::MustRestyleSelf(nsRestyleHint aRestyleHint,
 | 
						|
                                 Element* aElement)
 | 
						|
{
 | 
						|
  return (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) ||
 | 
						|
         ((aRestyleHint & eRestyle_SomeDescendants) &&
 | 
						|
          SelectorMatchesForRestyle(aElement));
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::CanReparentStyleContext(nsRestyleHint aRestyleHint)
 | 
						|
{
 | 
						|
  // If we had any restyle hints other than the ones listed below,
 | 
						|
  // which don't control whether the current frame/element needs
 | 
						|
  // a new style context by looking up a new rule node, or if
 | 
						|
  // we are reconstructing the entire rule tree, then we can't
 | 
						|
  // use ReparentStyleContext.
 | 
						|
  return !(aRestyleHint & ~(eRestyle_Force |
 | 
						|
                            eRestyle_ForceDescendants |
 | 
						|
                            eRestyle_SomeDescendants)) &&
 | 
						|
         !StyleSet()->IsInRuleTreeReconstruct();
 | 
						|
}
 | 
						|
 | 
						|
// Returns true iff any rule node that is an ancestor-or-self of the
 | 
						|
// two specified rule nodes, but which is not an ancestor of both,
 | 
						|
// has any inherited style data.  If false is returned, then we know
 | 
						|
// that a change from one rule node to the other must not result in
 | 
						|
// any change in inherited style data.
 | 
						|
static bool
 | 
						|
CommonInheritedStyleData(nsRuleNode* aRuleNode1, nsRuleNode* aRuleNode2)
 | 
						|
{
 | 
						|
  if (aRuleNode1 == aRuleNode2) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  nsRuleNode* n1 = aRuleNode1->GetParent();
 | 
						|
  nsRuleNode* n2 = aRuleNode2->GetParent();
 | 
						|
 | 
						|
  if (n1 == n2) {
 | 
						|
    // aRuleNode1 and aRuleNode2 sharing a parent is a common case, e.g.
 | 
						|
    // when modifying a style="" attribute.  (We must null check GetRule()'s
 | 
						|
    // result since although we know the two parents are the same, it might
 | 
						|
    // be null, as in the case of the two rule nodes being roots of two
 | 
						|
    // different rule trees.)
 | 
						|
    if (aRuleNode1->GetRule() &&
 | 
						|
        aRuleNode1->GetRule()->MightMapInheritedStyleData()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if (aRuleNode2->GetRule() &&
 | 
						|
        aRuleNode2->GetRule()->MightMapInheritedStyleData()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Compute the depths of aRuleNode1 and aRuleNode2.
 | 
						|
  int d1 = 0, d2 = 0;
 | 
						|
  while (n1) {
 | 
						|
    ++d1;
 | 
						|
    n1 = n1->GetParent();
 | 
						|
  }
 | 
						|
  while (n2) {
 | 
						|
    ++d2;
 | 
						|
    n2 = n2->GetParent();
 | 
						|
  }
 | 
						|
 | 
						|
  // Make aRuleNode1 be the deeper node.
 | 
						|
  if (d2 > d1) {
 | 
						|
    std::swap(d1, d2);
 | 
						|
    std::swap(aRuleNode1, aRuleNode2);
 | 
						|
  }
 | 
						|
 | 
						|
  // Check all of the rule nodes in the deeper branch until we reach
 | 
						|
  // the same depth as the shallower branch.
 | 
						|
  n1 = aRuleNode1;
 | 
						|
  n2 = aRuleNode2;
 | 
						|
  while (d1 > d2) {
 | 
						|
    nsIStyleRule* rule = n1->GetRule();
 | 
						|
    MOZ_ASSERT(rule, "non-root rule node should have a rule");
 | 
						|
    if (rule->MightMapInheritedStyleData()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    n1 = n1->GetParent();
 | 
						|
    --d1;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check both branches simultaneously until we reach a common ancestor.
 | 
						|
  while (n1 != n2) {
 | 
						|
    MOZ_ASSERT(n1);
 | 
						|
    MOZ_ASSERT(n2);
 | 
						|
    // As above, we must null check GetRule()'s result since we won't find
 | 
						|
    // a common ancestor if the two rule nodes come from different rule trees,
 | 
						|
    // and thus we might reach the root (which has a null rule).
 | 
						|
    if (n1->GetRule() && n1->GetRule()->MightMapInheritedStyleData()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if (n2->GetRule() && n2->GetRule()->MightMapInheritedStyleData()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    n1 = n1->GetParent();
 | 
						|
    n2 = n2->GetParent();
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
ElementRestyler::RestyleResult
 | 
						|
ElementRestyler::RestyleSelf(nsIFrame* aSelf,
 | 
						|
                             nsRestyleHint aRestyleHint,
 | 
						|
                             uint32_t* aSwappedStructs,
 | 
						|
                             nsTArray<SwapInstruction>& aSwaps)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
 | 
						|
             "eRestyle_LaterSiblings must not be part of aRestyleHint");
 | 
						|
 | 
						|
  // XXXldb get new context from prev-in-flow if possible, to avoid
 | 
						|
  // duplication.  (Or should we just let |GetContext| handle that?)
 | 
						|
  // Getting the hint would be nice too, but that's harder.
 | 
						|
 | 
						|
  // XXXbryner we may be able to avoid some of the refcounting goop here.
 | 
						|
  // We do need a reference to oldContext for the lifetime of this function, and it's possible
 | 
						|
  // that the frame has the last reference to it, so AddRef it here.
 | 
						|
 | 
						|
  LOG_RESTYLE("RestyleSelf %s, aRestyleHint = %s",
 | 
						|
              FrameTagToString(aSelf).get(),
 | 
						|
              RestyleManagerBase::RestyleHintToString(aRestyleHint).get());
 | 
						|
  LOG_RESTYLE_INDENT();
 | 
						|
 | 
						|
  // Initially assume that it is safe to stop restyling.
 | 
						|
  //
 | 
						|
  // Throughout most of this function, we update the following two variables
 | 
						|
  // independently.  |result| is set to RestyleResult::eContinue when we
 | 
						|
  // detect a condition that would not allow us to return RestyleResult::eStop.
 | 
						|
  // |canStopWithStyleChange| is set to false when we detect a condition
 | 
						|
  // that would not allow us to return RestyleResult::eStopWithStyleChange.
 | 
						|
  //
 | 
						|
  // Towards the end of this function, we reconcile these two variables --
 | 
						|
  // if |canStopWithStyleChange| is true, we convert |result| into
 | 
						|
  // RestyleResult::eStopWithStyleChange.
 | 
						|
  RestyleResult result = RestyleResult::eStop;
 | 
						|
  bool canStopWithStyleChange = true;
 | 
						|
 | 
						|
  if (aRestyleHint & ~eRestyle_SomeDescendants) {
 | 
						|
    // If we are doing any restyling of the current element, or if we're
 | 
						|
    // forced to continue, we must.
 | 
						|
    result = RestyleResult::eContinue;
 | 
						|
 | 
						|
    // If we have to restyle children, we can't return
 | 
						|
    // RestyleResult::eStopWithStyleChange.
 | 
						|
    if (aRestyleHint & (eRestyle_Subtree | eRestyle_Force |
 | 
						|
                        eRestyle_ForceDescendants)) {
 | 
						|
      canStopWithStyleChange = false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // We only consider returning RestyleResult::eStopWithStyleChange if this
 | 
						|
  // is the root of the restyle.  (Otherwise, we would need to track the
 | 
						|
  // style changes of the ancestors we just restyled.)
 | 
						|
  if (!mIsRootOfRestyle) {
 | 
						|
    canStopWithStyleChange = false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Look at the frame and its current style context for conditions
 | 
						|
  // that would change our RestyleResult.
 | 
						|
  ComputeRestyleResultFromFrame(aSelf, result, canStopWithStyleChange);
 | 
						|
 | 
						|
  nsChangeHint assumeDifferenceHint = nsChangeHint(0);
 | 
						|
  RefPtr<nsStyleContext> oldContext = aSelf->StyleContext();
 | 
						|
  nsStyleSet* styleSet = StyleSet();
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  mWasFrameVisible = nsIPresShell::IsAccessibilityActive() ?
 | 
						|
    oldContext->StyleVisibility()->IsVisible() : false;
 | 
						|
#endif
 | 
						|
 | 
						|
  nsIAtom* const pseudoTag = oldContext->GetPseudo();
 | 
						|
  const CSSPseudoElementType pseudoType = oldContext->GetPseudoType();
 | 
						|
 | 
						|
  // Get the frame providing the parent style context.  If it is a
 | 
						|
  // child, then resolve the provider first.
 | 
						|
  nsIFrame* providerFrame;
 | 
						|
  nsStyleContext* parentContext = aSelf->GetParentStyleContext(&providerFrame);
 | 
						|
  bool isChild = providerFrame && providerFrame->GetParent() == aSelf;
 | 
						|
  if (isChild) {
 | 
						|
    MOZ_ASSERT(providerFrame->GetContent() == aSelf->GetContent(),
 | 
						|
               "Postcondition for GetParentStyleContext() violated. "
 | 
						|
               "That means we need to add the current element to the "
 | 
						|
               "ancestor filter.");
 | 
						|
 | 
						|
    // resolve the provider here (before aSelf below).
 | 
						|
    LOG_RESTYLE("resolving child provider frame");
 | 
						|
 | 
						|
    // assumeDifferenceHint forces the parent's change to be also
 | 
						|
    // applied to this frame, no matter what
 | 
						|
    // nsStyleContext::CalcStyleDifference says. CalcStyleDifference
 | 
						|
    // can't be trusted because it assumes any changes to the parent
 | 
						|
    // style context provider will be automatically propagated to
 | 
						|
    // the frame(s) with child style contexts.
 | 
						|
 | 
						|
    ElementRestyler providerRestyler(PARENT_CONTEXT_FROM_CHILD_FRAME,
 | 
						|
                                     *this, providerFrame);
 | 
						|
    providerRestyler.Restyle(aRestyleHint);
 | 
						|
    assumeDifferenceHint = providerRestyler.HintsHandledForFrame();
 | 
						|
 | 
						|
    // The provider's new context becomes the parent context of
 | 
						|
    // aSelf's context.
 | 
						|
    parentContext = providerFrame->StyleContext();
 | 
						|
    // Set |mResolvedChild| so we don't bother resolving the
 | 
						|
    // provider again.
 | 
						|
    mResolvedChild = providerFrame;
 | 
						|
    LOG_RESTYLE_CONTINUE("we had a provider frame");
 | 
						|
    // Continue restyling past the odd style context inheritance.
 | 
						|
    result = RestyleResult::eContinue;
 | 
						|
    canStopWithStyleChange = false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (providerFrame != aSelf->GetParent()) {
 | 
						|
    // We don't actually know what the parent style context's
 | 
						|
    // non-inherited hints were, so assume the worst.
 | 
						|
    mParentFrameHintsNotHandledForDescendants =
 | 
						|
      nsChangeHint_Hints_NotHandledForDescendants;
 | 
						|
  }
 | 
						|
 | 
						|
  LOG_RESTYLE("parentContext = %p", parentContext);
 | 
						|
 | 
						|
  // do primary context
 | 
						|
  RefPtr<nsStyleContext> newContext;
 | 
						|
  nsIFrame* prevContinuation =
 | 
						|
    GetPrevContinuationWithPossiblySameStyle(aSelf);
 | 
						|
  nsStyleContext* prevContinuationContext;
 | 
						|
  bool copyFromContinuation =
 | 
						|
    prevContinuation &&
 | 
						|
    (prevContinuationContext = prevContinuation->StyleContext())
 | 
						|
      ->GetPseudo() == oldContext->GetPseudo() &&
 | 
						|
     prevContinuationContext->GetParent() == parentContext;
 | 
						|
  if (copyFromContinuation) {
 | 
						|
    // Just use the style context from the frame's previous
 | 
						|
    // continuation.
 | 
						|
    LOG_RESTYLE("using previous continuation's context");
 | 
						|
    newContext = prevContinuationContext;
 | 
						|
  } else if (pseudoTag == nsCSSAnonBoxes::mozText) {
 | 
						|
    MOZ_ASSERT(aSelf->GetType() == nsGkAtoms::textFrame);
 | 
						|
    newContext =
 | 
						|
      styleSet->ResolveStyleForText(aSelf->GetContent(), parentContext);
 | 
						|
  } else if (nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
 | 
						|
    newContext = styleSet->ResolveStyleForOtherNonElement(parentContext);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
 | 
						|
    if (!MustRestyleSelf(aRestyleHint, element)) {
 | 
						|
      if (CanReparentStyleContext(aRestyleHint)) {
 | 
						|
        LOG_RESTYLE("reparenting style context");
 | 
						|
        newContext =
 | 
						|
          styleSet->ReparentStyleContext(oldContext, parentContext, element);
 | 
						|
      } else {
 | 
						|
        // Use ResolveStyleWithReplacement either for actual replacements
 | 
						|
        // or, with no replacements, as a substitute for
 | 
						|
        // ReparentStyleContext that rebuilds the path in the rule tree
 | 
						|
        // rather than reusing the rule node, as we need to do during a
 | 
						|
        // rule tree reconstruct.
 | 
						|
        Element* pseudoElement = PseudoElementForStyleContext(aSelf, pseudoType);
 | 
						|
        MOZ_ASSERT(!element || element != pseudoElement,
 | 
						|
                   "pseudo-element for selector matching should be "
 | 
						|
                   "the anonymous content node that we create, "
 | 
						|
                   "not the real element");
 | 
						|
        LOG_RESTYLE("resolving style with replacement");
 | 
						|
        nsRestyleHint rshint = aRestyleHint & ~eRestyle_SomeDescendants;
 | 
						|
        newContext =
 | 
						|
          styleSet->ResolveStyleWithReplacement(element, pseudoElement,
 | 
						|
                                                parentContext, oldContext,
 | 
						|
                                                rshint);
 | 
						|
      }
 | 
						|
    } else if (pseudoType == CSSPseudoElementType::AnonBox) {
 | 
						|
      newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag,
 | 
						|
                                                      parentContext);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      if (pseudoTag) {
 | 
						|
        if (pseudoTag == nsCSSPseudoElements::before ||
 | 
						|
            pseudoTag == nsCSSPseudoElements::after) {
 | 
						|
          // XXX what other pseudos do we need to treat like this?
 | 
						|
          newContext = styleSet->ProbePseudoElementStyle(element,
 | 
						|
                                                         pseudoType,
 | 
						|
                                                         parentContext,
 | 
						|
                                                         mTreeMatchContext);
 | 
						|
          if (!newContext) {
 | 
						|
            // This pseudo should no longer exist; gotta reframe
 | 
						|
            mHintsHandled |= nsChangeHint_ReconstructFrame;
 | 
						|
            mChangeList->AppendChange(aSelf, element,
 | 
						|
                                      nsChangeHint_ReconstructFrame);
 | 
						|
            // We're reframing anyway; just keep the same context
 | 
						|
            newContext = oldContext;
 | 
						|
#ifdef DEBUG
 | 
						|
            // oldContext's parent might have had its style structs swapped out
 | 
						|
            // with parentContext, so to avoid any assertions that might
 | 
						|
            // otherwise trigger in oldContext's parent's destructor, we set a
 | 
						|
            // flag on oldContext to skip it and its descendants in
 | 
						|
            // nsStyleContext::AssertStructsNotUsedElsewhere.
 | 
						|
            if (oldContext->GetParent() != parentContext) {
 | 
						|
              oldContext->AddStyleBit(NS_STYLE_IS_GOING_AWAY);
 | 
						|
            }
 | 
						|
#endif
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          // Don't expect XUL tree stuff here, since it needs a comparator and
 | 
						|
          // all.
 | 
						|
          NS_ASSERTION(pseudoType < CSSPseudoElementType::Count,
 | 
						|
                       "Unexpected pseudo type");
 | 
						|
          Element* pseudoElement =
 | 
						|
            PseudoElementForStyleContext(aSelf, pseudoType);
 | 
						|
          MOZ_ASSERT(element != pseudoElement,
 | 
						|
                     "pseudo-element for selector matching should be "
 | 
						|
                     "the anonymous content node that we create, "
 | 
						|
                     "not the real element");
 | 
						|
          newContext = styleSet->ResolvePseudoElementStyle(element,
 | 
						|
                                                           pseudoType,
 | 
						|
                                                           parentContext,
 | 
						|
                                                           pseudoElement);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        NS_ASSERTION(aSelf->GetContent(),
 | 
						|
                     "non pseudo-element frame without content node");
 | 
						|
        // Skip parent display based style fixup for anonymous subtrees:
 | 
						|
        TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
 | 
						|
          parentDisplayBasedFixupSkipper(mTreeMatchContext,
 | 
						|
                                 element->IsRootOfNativeAnonymousSubtree());
 | 
						|
        newContext = styleSet->ResolveStyleFor(element, parentContext,
 | 
						|
                                               mTreeMatchContext);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(newContext);
 | 
						|
 | 
						|
  if (!parentContext) {
 | 
						|
    if (oldContext->RuleNode() == newContext->RuleNode() &&
 | 
						|
        oldContext->IsLinkContext() == newContext->IsLinkContext() &&
 | 
						|
        oldContext->RelevantLinkVisited() ==
 | 
						|
          newContext->RelevantLinkVisited()) {
 | 
						|
      // We're the root of the style context tree and the new style
 | 
						|
      // context returned has the same rule node.  This means that
 | 
						|
      // we can use FindChildWithRules to keep a lot of the old
 | 
						|
      // style contexts around.  However, we need to start from the
 | 
						|
      // same root.
 | 
						|
      LOG_RESTYLE("restyling root and keeping old context");
 | 
						|
      LOG_RESTYLE_IF(this, result != RestyleResult::eContinue,
 | 
						|
                     "continuing restyle since this is the root");
 | 
						|
      newContext = oldContext;
 | 
						|
      // Never consider stopping restyling at the root.
 | 
						|
      result = RestyleResult::eContinue;
 | 
						|
      canStopWithStyleChange = false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  LOG_RESTYLE("oldContext = %p, newContext = %p%s",
 | 
						|
              oldContext.get(), newContext.get(),
 | 
						|
              oldContext == newContext ? (const char*) " (same)" :
 | 
						|
                                         (const char*) "");
 | 
						|
 | 
						|
  if (newContext != oldContext) {
 | 
						|
    if (oldContext->IsShared()) {
 | 
						|
      // If the old style context was shared, then we can't return
 | 
						|
      // RestyleResult::eStop and patch its parent to point to the
 | 
						|
      // new parent style context, as that change might not be valid
 | 
						|
      // for the other frames sharing the style context.
 | 
						|
      LOG_RESTYLE_CONTINUE("the old style context is shared");
 | 
						|
      result = RestyleResult::eContinue;
 | 
						|
 | 
						|
      // It is not safe to return RestyleResult::eStopWithStyleChange
 | 
						|
      // when oldContext is shared and newContext has different
 | 
						|
      // inherited style data, regardless of whether the oldContext has
 | 
						|
      // that inherited style data cached.  We can't simply rely on the
 | 
						|
      // samePointerStructs check later on, as the descendent style
 | 
						|
      // contexts just might not have had their inherited style data
 | 
						|
      // requested yet (which is possible for example if we flush style
 | 
						|
      // between resolving an initial style context for a frame and
 | 
						|
      // building its display list items).  Therefore we must compare
 | 
						|
      // the rule nodes of oldContext and newContext to see if the
 | 
						|
      // restyle results in new inherited style data.  If not, then
 | 
						|
      // we can continue assuming that RestyleResult::eStopWithStyleChange
 | 
						|
      // is safe.  Without this check, we could end up with style contexts
 | 
						|
      // shared between elements which should have different styles.
 | 
						|
      if (!CommonInheritedStyleData(oldContext->RuleNode(),
 | 
						|
                                    newContext->RuleNode())) {
 | 
						|
        canStopWithStyleChange = false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Look at some details of the new style context to see if it would
 | 
						|
    // be safe to stop restyling, if we discover it has the same style
 | 
						|
    // data as the old style context.
 | 
						|
    ComputeRestyleResultFromNewContext(aSelf, newContext,
 | 
						|
                                       result, canStopWithStyleChange);
 | 
						|
 | 
						|
    uint32_t equalStructs = 0;
 | 
						|
    uint32_t samePointerStructs = 0;
 | 
						|
 | 
						|
    if (copyFromContinuation) {
 | 
						|
      // In theory we should know whether there was any style data difference,
 | 
						|
      // since we would have calculated that in the previous call to
 | 
						|
      // RestyleSelf, so until we perform only one restyling per chain-of-
 | 
						|
      // same-style continuations (bug 918064), we need to check again here to
 | 
						|
      // determine whether it is safe to stop restyling.
 | 
						|
      if (result == RestyleResult::eStop) {
 | 
						|
        oldContext->CalcStyleDifference(newContext, nsChangeHint(0),
 | 
						|
                                        &equalStructs,
 | 
						|
                                        &samePointerStructs);
 | 
						|
        if (equalStructs != NS_STYLE_INHERIT_MASK) {
 | 
						|
          // At least one struct had different data in it, so we must
 | 
						|
          // continue restyling children.
 | 
						|
          LOG_RESTYLE_CONTINUE("there is different style data: %s",
 | 
						|
                      RestyleManager::StructNamesToString(
 | 
						|
                        ~equalStructs & NS_STYLE_INHERIT_MASK).get());
 | 
						|
          result = RestyleResult::eContinue;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      bool changedStyle =
 | 
						|
        RestyleManager::TryStartingTransition(mPresContext, aSelf->GetContent(),
 | 
						|
                                              oldContext, &newContext);
 | 
						|
      if (changedStyle) {
 | 
						|
        LOG_RESTYLE_CONTINUE("TryStartingTransition changed the new style context");
 | 
						|
        result = RestyleResult::eContinue;
 | 
						|
        canStopWithStyleChange = false;
 | 
						|
      }
 | 
						|
      CaptureChange(oldContext, newContext, assumeDifferenceHint,
 | 
						|
                    &equalStructs, &samePointerStructs);
 | 
						|
      if (equalStructs != NS_STYLE_INHERIT_MASK) {
 | 
						|
        // At least one struct had different data in it, so we must
 | 
						|
        // continue restyling children.
 | 
						|
        LOG_RESTYLE_CONTINUE("there is different style data: %s",
 | 
						|
                    RestyleManager::StructNamesToString(
 | 
						|
                      ~equalStructs & NS_STYLE_INHERIT_MASK).get());
 | 
						|
        result = RestyleResult::eContinue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (canStopWithStyleChange) {
 | 
						|
      // If any inherited struct pointers are different, or if any
 | 
						|
      // reset struct pointers are different and we have descendants
 | 
						|
      // that rely on those reset struct pointers, we can't return
 | 
						|
      // RestyleResult::eStopWithStyleChange.
 | 
						|
      if ((samePointerStructs & NS_STYLE_INHERITED_STRUCT_MASK) !=
 | 
						|
            NS_STYLE_INHERITED_STRUCT_MASK) {
 | 
						|
        LOG_RESTYLE("can't return RestyleResult::eStopWithStyleChange since "
 | 
						|
                    "there is different inherited data");
 | 
						|
        canStopWithStyleChange = false;
 | 
						|
      } else if ((samePointerStructs & NS_STYLE_RESET_STRUCT_MASK) !=
 | 
						|
                   NS_STYLE_RESET_STRUCT_MASK &&
 | 
						|
                 oldContext->HasChildThatUsesResetStyle()) {
 | 
						|
        LOG_RESTYLE("can't return RestyleResult::eStopWithStyleChange since "
 | 
						|
                    "there is different reset data and descendants use it");
 | 
						|
        canStopWithStyleChange = false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (result == RestyleResult::eStop) {
 | 
						|
      // Since we currently have RestyleResult::eStop, we know at this
 | 
						|
      // point that all of our style structs are equal in terms of styles.
 | 
						|
      // However, some of them might be different pointers.  Since our
 | 
						|
      // descendants might share those pointers, we have to continue to
 | 
						|
      // restyling our descendants.
 | 
						|
      //
 | 
						|
      // However, because of the swapping of equal structs we've done on
 | 
						|
      // ancestors (later in this function), we've ensured that for structs
 | 
						|
      // that cannot be stored in the rule tree, we keep the old equal structs
 | 
						|
      // around rather than replacing them with new ones.  This means that we
 | 
						|
      // only time we hit this deoptimization is either
 | 
						|
      //
 | 
						|
      // (a) when at least one of the (old or new) equal structs could be stored
 | 
						|
      //     in the rule tree, and those structs are then inherited (by pointer
 | 
						|
      //     sharing) to descendant style contexts; or
 | 
						|
      //
 | 
						|
      // (b) when we were unable to swap the structs on the parent because
 | 
						|
      //     either or both of the old parent and new parent are shared.
 | 
						|
      //
 | 
						|
      // FIXME This loop could be rewritten as bit operations on
 | 
						|
      //       oldContext->mBits and samePointerStructs.
 | 
						|
      for (nsStyleStructID sid = nsStyleStructID(0);
 | 
						|
           sid < nsStyleStructID_Length;
 | 
						|
           sid = nsStyleStructID(sid + 1)) {
 | 
						|
        if (oldContext->HasCachedDependentStyleData(sid) &&
 | 
						|
            !(samePointerStructs & nsCachedStyleData::GetBitForSID(sid))) {
 | 
						|
          LOG_RESTYLE_CONTINUE("there are different struct pointers");
 | 
						|
          result = RestyleResult::eContinue;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // From this point we no longer do any assignments of
 | 
						|
    // RestyleResult::eContinue to |result|.  If canStopWithStyleChange is true,
 | 
						|
    // it means that we can convert |result| (whether it is
 | 
						|
    // RestyleResult::eContinue or RestyleResult::eStop) into
 | 
						|
    // RestyleResult::eStopWithStyleChange.
 | 
						|
    if (canStopWithStyleChange) {
 | 
						|
      LOG_RESTYLE("converting %s into RestyleResult::eStopWithStyleChange",
 | 
						|
                  RestyleResultToString(result).get());
 | 
						|
      result = RestyleResult::eStopWithStyleChange;
 | 
						|
    }
 | 
						|
 | 
						|
    if (aRestyleHint & eRestyle_ForceDescendants) {
 | 
						|
      result = RestyleResult::eContinueAndForceDescendants;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
      // If the frame gets regenerated, let it keep its old context,
 | 
						|
      // which is important to maintain various invariants about
 | 
						|
      // frame types matching their style contexts.
 | 
						|
      // Note that this check even makes sense if we didn't call
 | 
						|
      // CaptureChange because of copyFromContinuation being true,
 | 
						|
      // since we'll have copied the existing context from the
 | 
						|
      // previous continuation, so newContext == oldContext.
 | 
						|
 | 
						|
      if (result != RestyleResult::eStop) {
 | 
						|
        if (copyFromContinuation) {
 | 
						|
          LOG_RESTYLE("not swapping style structs, since we copied from a "
 | 
						|
                      "continuation");
 | 
						|
        } else if (oldContext->IsShared() && newContext->IsShared()) {
 | 
						|
          LOG_RESTYLE("not swapping style structs, since both old and contexts "
 | 
						|
                      "are shared");
 | 
						|
        } else if (oldContext->IsShared()) {
 | 
						|
          LOG_RESTYLE("not swapping style structs, since the old context is "
 | 
						|
                      "shared");
 | 
						|
        } else if (newContext->IsShared()) {
 | 
						|
          LOG_RESTYLE("not swapping style structs, since the new context is "
 | 
						|
                      "shared");
 | 
						|
        } else {
 | 
						|
          if (result == RestyleResult::eStopWithStyleChange) {
 | 
						|
            LOG_RESTYLE("recording a style struct swap between %p and %p to "
 | 
						|
                        "do if RestyleResult::eStopWithStyleChange fails",
 | 
						|
                        oldContext.get(), newContext.get());
 | 
						|
            SwapInstruction* swap = aSwaps.AppendElement();
 | 
						|
            swap->mOldContext = oldContext;
 | 
						|
            swap->mNewContext = newContext;
 | 
						|
            swap->mStructsToSwap = equalStructs;
 | 
						|
          } else {
 | 
						|
            LOG_RESTYLE("swapping style structs between %p and %p",
 | 
						|
                        oldContext.get(), newContext.get());
 | 
						|
            oldContext->SwapStyleData(newContext, equalStructs);
 | 
						|
            *aSwappedStructs |= equalStructs;
 | 
						|
          }
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
          uint32_t structs = RestyleManager::StructsToLog() & equalStructs;
 | 
						|
          if (structs) {
 | 
						|
            LOG_RESTYLE_INDENT();
 | 
						|
            LOG_RESTYLE("old style context now has: %s",
 | 
						|
                        oldContext->GetCachedStyleDataAsString(structs).get());
 | 
						|
            LOG_RESTYLE("new style context now has: %s",
 | 
						|
                        newContext->GetCachedStyleDataAsString(structs).get());
 | 
						|
          }
 | 
						|
#endif
 | 
						|
        }
 | 
						|
        LOG_RESTYLE("setting new style context");
 | 
						|
        aSelf->SetStyleContext(newContext);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      LOG_RESTYLE("not setting new style context, since we'll reframe");
 | 
						|
      // We need to keep the new parent alive, in case it had structs
 | 
						|
      // swapped into it that our frame's style context still has cached.
 | 
						|
      // This is a similar scenario to the one described in the
 | 
						|
      // ElementRestyler::Restyle comment where we append to
 | 
						|
      // mSwappedStructOwners.
 | 
						|
      //
 | 
						|
      // We really only need to do this if we did swap structs on the
 | 
						|
      // parent, but we don't have that information here.
 | 
						|
      mSwappedStructOwners.AppendElement(newContext->GetParent());
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if (aRestyleHint & eRestyle_ForceDescendants) {
 | 
						|
      result = RestyleResult::eContinueAndForceDescendants;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  oldContext = nullptr;
 | 
						|
 | 
						|
  // do additional contexts
 | 
						|
  // XXXbz might be able to avoid selector matching here in some
 | 
						|
  // cases; won't worry about it for now.
 | 
						|
  int32_t contextIndex = 0;
 | 
						|
  for (nsStyleContext* oldExtraContext;
 | 
						|
       (oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex));
 | 
						|
       ++contextIndex) {
 | 
						|
    LOG_RESTYLE("extra context %d", contextIndex);
 | 
						|
    LOG_RESTYLE_INDENT();
 | 
						|
    RefPtr<nsStyleContext> newExtraContext;
 | 
						|
    nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
 | 
						|
    const CSSPseudoElementType extraPseudoType =
 | 
						|
      oldExtraContext->GetPseudoType();
 | 
						|
    NS_ASSERTION(extraPseudoTag &&
 | 
						|
                 !nsCSSAnonBoxes::IsNonElement(extraPseudoTag),
 | 
						|
                 "extra style context is not pseudo element");
 | 
						|
    Element* element = extraPseudoType != CSSPseudoElementType::AnonBox
 | 
						|
                         ? mContent->AsElement() : nullptr;
 | 
						|
    if (!MustRestyleSelf(aRestyleHint, element)) {
 | 
						|
      if (CanReparentStyleContext(aRestyleHint)) {
 | 
						|
        newExtraContext =
 | 
						|
          styleSet->ReparentStyleContext(oldExtraContext, newContext, element);
 | 
						|
      } else {
 | 
						|
        // Use ResolveStyleWithReplacement as a substitute for
 | 
						|
        // ReparentStyleContext that rebuilds the path in the rule tree
 | 
						|
        // rather than reusing the rule node, as we need to do during a
 | 
						|
        // rule tree reconstruct.
 | 
						|
        Element* pseudoElement =
 | 
						|
          PseudoElementForStyleContext(aSelf, extraPseudoType);
 | 
						|
        MOZ_ASSERT(!element || element != pseudoElement,
 | 
						|
                   "pseudo-element for selector matching should be "
 | 
						|
                   "the anonymous content node that we create, "
 | 
						|
                   "not the real element");
 | 
						|
        newExtraContext =
 | 
						|
          styleSet->ResolveStyleWithReplacement(element, pseudoElement,
 | 
						|
                                                newContext, oldExtraContext,
 | 
						|
                                                nsRestyleHint(0));
 | 
						|
      }
 | 
						|
    } else if (extraPseudoType == CSSPseudoElementType::AnonBox) {
 | 
						|
      newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag,
 | 
						|
                                                           newContext);
 | 
						|
    } else {
 | 
						|
      // Don't expect XUL tree stuff here, since it needs a comparator and
 | 
						|
      // all.
 | 
						|
      NS_ASSERTION(extraPseudoType < CSSPseudoElementType::Count,
 | 
						|
                   "Unexpected type");
 | 
						|
      newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(),
 | 
						|
                                                            extraPseudoType,
 | 
						|
                                                            newContext,
 | 
						|
                                                            nullptr);
 | 
						|
    }
 | 
						|
 | 
						|
    MOZ_ASSERT(newExtraContext);
 | 
						|
 | 
						|
    LOG_RESTYLE("newExtraContext = %p", newExtraContext.get());
 | 
						|
 | 
						|
    if (oldExtraContext != newExtraContext) {
 | 
						|
      uint32_t equalStructs;
 | 
						|
      uint32_t samePointerStructs;
 | 
						|
      CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint,
 | 
						|
                    &equalStructs, &samePointerStructs);
 | 
						|
      if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
        LOG_RESTYLE("setting new extra style context");
 | 
						|
        aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext);
 | 
						|
      } else {
 | 
						|
        LOG_RESTYLE("not setting new extra style context, since we'll reframe");
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  LOG_RESTYLE("returning %s", RestyleResultToString(result).get());
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!(mHintsHandled & nsChangeHint_ReconstructFrame),
 | 
						|
             "No need to do this if we're planning to reframe already.");
 | 
						|
 | 
						|
  // We'd like style resolution to be exact in the sense that an
 | 
						|
  // animation-only style flush flushes only the styles it requests
 | 
						|
  // flushing and doesn't update any other styles.  This means avoiding
 | 
						|
  // constructing new frames during such a flush.
 | 
						|
  //
 | 
						|
  // For a ::before or ::after, we'll do an eRestyle_Subtree due to
 | 
						|
  // RestyleHintForOp in nsCSSRuleProcessor.cpp (via its
 | 
						|
  // HasAttributeDependentStyle or HasStateDependentStyle), given that
 | 
						|
  // we store pseudo-elements in selectors like they were children.
 | 
						|
  //
 | 
						|
  // Also, it's faster to skip the work we do on undisplayed children
 | 
						|
  // and pseudo-elements when we can skip it.
 | 
						|
  bool mightReframePseudos = aChildRestyleHint & eRestyle_Subtree;
 | 
						|
 | 
						|
  RestyleUndisplayedDescendants(aChildRestyleHint);
 | 
						|
 | 
						|
  // Check whether we might need to create a new ::before frame.
 | 
						|
  // There's no need to do this if we're planning to reframe already
 | 
						|
  // or if we're not forcing restyles on kids.
 | 
						|
  // It's also important to check mHintsHandled since we use
 | 
						|
  // mFrame->StyleContext(), which is out of date if mHintsHandled has a
 | 
						|
  // ReconstructFrame hint.  Using an out of date style context could
 | 
						|
  // trigger assertions about mismatched rule trees.
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
 | 
						|
      mightReframePseudos) {
 | 
						|
    MaybeReframeForBeforePseudo();
 | 
						|
  }
 | 
						|
 | 
						|
  // There is no need to waste time crawling into a frame's children
 | 
						|
  // on a frame change.  The act of reconstructing frames will force
 | 
						|
  // new style contexts to be resolved on all of this frame's
 | 
						|
  // descendants anyway, so we want to avoid wasting time processing
 | 
						|
  // style contexts that we're just going to throw away anyway. - dwh
 | 
						|
  // It's also important to check mHintsHandled since reresolving the
 | 
						|
  // kids would use mFrame->StyleContext(), which is out of date if
 | 
						|
  // mHintsHandled has a ReconstructFrame hint; doing this could trigger
 | 
						|
  // assertions about mismatched rule trees.
 | 
						|
  nsIFrame* lastContinuation;
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
    InitializeAccessibilityNotifications(mFrame->StyleContext());
 | 
						|
 | 
						|
    for (nsIFrame* f = mFrame; f;
 | 
						|
         f = RestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
 | 
						|
      lastContinuation = f;
 | 
						|
      RestyleContentChildren(f, aChildRestyleHint);
 | 
						|
    }
 | 
						|
 | 
						|
    SendAccessibilityNotifications();
 | 
						|
  }
 | 
						|
 | 
						|
  // Check whether we might need to create a new ::after frame.
 | 
						|
  // See comments above regarding :before.
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
 | 
						|
      mightReframePseudos) {
 | 
						|
    MaybeReframeForAfterPseudo(lastContinuation);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::RestyleChildrenOfDisplayContentsElement(
 | 
						|
  nsIFrame*              aParentFrame,
 | 
						|
  nsStyleContext*        aNewContext,
 | 
						|
  nsChangeHint           aMinHint,
 | 
						|
  RestyleTracker&        aRestyleTracker,
 | 
						|
  nsRestyleHint          aRestyleHint,
 | 
						|
  const RestyleHintData& aRestyleHintData)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(!(mHintsHandled & nsChangeHint_ReconstructFrame), "why call me?");
 | 
						|
 | 
						|
  const bool mightReframePseudos = aRestyleHint & eRestyle_Subtree;
 | 
						|
  DoRestyleUndisplayedDescendants(nsRestyleHint(0), mContent, aNewContext);
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) {
 | 
						|
    MaybeReframeForPseudo(CSSPseudoElementType::before,
 | 
						|
                          aParentFrame, nullptr, mContent, aNewContext);
 | 
						|
  }
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) {
 | 
						|
    MaybeReframeForPseudo(CSSPseudoElementType::after,
 | 
						|
                          aParentFrame, nullptr, mContent, aNewContext);
 | 
						|
  }
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
    InitializeAccessibilityNotifications(aNewContext);
 | 
						|
 | 
						|
    // Then process child frames for content that is a descendant of mContent.
 | 
						|
    // XXX perhaps it's better to walk child frames (before reresolving
 | 
						|
    // XXX undisplayed contexts above) and mark those that has a stylecontext
 | 
						|
    // XXX leading up to mContent's old context? (instead of the
 | 
						|
    // XXX ContentIsDescendantOf check below)
 | 
						|
    nsIFrame::ChildListIterator lists(aParentFrame);
 | 
						|
    for ( ; !lists.IsDone(); lists.Next()) {
 | 
						|
      for (nsIFrame* f : lists.CurrentList()) {
 | 
						|
        if (nsContentUtils::ContentIsDescendantOf(f->GetContent(), mContent) &&
 | 
						|
            !f->GetPrevContinuation()) {
 | 
						|
          if (!(f->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
 | 
						|
            ComputeStyleChangeFor(f, mChangeList, aMinHint, aRestyleTracker,
 | 
						|
                                  aRestyleHint, aRestyleHintData,
 | 
						|
                                  mContextsToClear, mSwappedStructOwners);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
 | 
						|
    SendAccessibilityNotifications();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::ComputeStyleChangeFor(nsIFrame*          aFrame,
 | 
						|
                                       nsStyleChangeList* aChangeList,
 | 
						|
                                       nsChangeHint       aMinChange,
 | 
						|
                                       RestyleTracker&    aRestyleTracker,
 | 
						|
                                       nsRestyleHint      aRestyleHint,
 | 
						|
                                       const RestyleHintData& aRestyleHintData,
 | 
						|
                                       nsTArray<ContextToClear>&
 | 
						|
                                         aContextsToClear,
 | 
						|
                                       nsTArray<RefPtr<nsStyleContext>>&
 | 
						|
                                         aSwappedStructOwners)
 | 
						|
{
 | 
						|
  nsIContent* content = aFrame->GetContent();
 | 
						|
  nsAutoCString localDescriptor;
 | 
						|
  if (profiler_is_active() && content) {
 | 
						|
    std::string elemDesc = ToString(*content);
 | 
						|
    localDescriptor.Assign(elemDesc.c_str());
 | 
						|
  }
 | 
						|
 | 
						|
  PROFILER_LABEL_PRINTF("ElementRestyler", "ComputeStyleChangeFor",
 | 
						|
                        js::ProfileEntry::Category::CSS,
 | 
						|
                        content ? "Element: %s" : "%s",
 | 
						|
                        content ? localDescriptor.get() : "");
 | 
						|
  if (aMinChange) {
 | 
						|
    aChangeList->AppendChange(aFrame, content, aMinChange);
 | 
						|
  }
 | 
						|
 | 
						|
  NS_ASSERTION(!aFrame->GetPrevContinuation(),
 | 
						|
               "must start with the first continuation");
 | 
						|
 | 
						|
  // We want to start with this frame and walk all its next-in-flows,
 | 
						|
  // as well as all its ib-split siblings and their next-in-flows,
 | 
						|
  // reresolving style on all the frames we encounter in this walk that
 | 
						|
  // we didn't reach already.  In the normal case, this will mean only
 | 
						|
  // restyling the first two block-in-inline splits and no
 | 
						|
  // continuations, and skipping everything else.  However, when we have
 | 
						|
  // a style change targeted at an element inside a context where styles
 | 
						|
  // vary between continuations (e.g., a style change on an element that
 | 
						|
  // extends from inside a styled ::first-line to outside of that first
 | 
						|
  // line), we might restyle more than that.
 | 
						|
 | 
						|
  nsPresContext* presContext = aFrame->PresContext();
 | 
						|
  FramePropertyTable* propTable = presContext->PropertyTable();
 | 
						|
 | 
						|
  TreeMatchContext treeMatchContext(true,
 | 
						|
                                    nsRuleWalker::eRelevantLinkUnvisited,
 | 
						|
                                    presContext->Document());
 | 
						|
  Element* parent =
 | 
						|
    content ? content->GetParentElementCrossingShadowRoot() : nullptr;
 | 
						|
  treeMatchContext.InitAncestors(parent);
 | 
						|
  nsTArray<nsCSSSelector*> selectorsForDescendants;
 | 
						|
  selectorsForDescendants.AppendElements(
 | 
						|
      aRestyleHintData.mSelectorsForDescendants);
 | 
						|
  nsTArray<nsIContent*> visibleKidsOfHiddenElement;
 | 
						|
  nsIFrame* nextIBSibling;
 | 
						|
  for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) {
 | 
						|
    nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(propTable, ibSibling);
 | 
						|
 | 
						|
    if (nextIBSibling) {
 | 
						|
      // Don't allow some ib-split siblings to be processed with
 | 
						|
      // RestyleResult::eStopWithStyleChange and others not.
 | 
						|
      aRestyleHint |= eRestyle_Force;
 | 
						|
    }
 | 
						|
 | 
						|
    // Outer loop over ib-split siblings
 | 
						|
    for (nsIFrame* cont = ibSibling; cont; cont = cont->GetNextContinuation()) {
 | 
						|
      if (GetPrevContinuationWithSameStyle(cont)) {
 | 
						|
        // We already handled this element when dealing with its earlier
 | 
						|
        // continuation.
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      // Inner loop over next-in-flows of the current frame
 | 
						|
      ElementRestyler restyler(presContext, cont, aChangeList,
 | 
						|
                               aMinChange, aRestyleTracker,
 | 
						|
                               selectorsForDescendants,
 | 
						|
                               treeMatchContext,
 | 
						|
                               visibleKidsOfHiddenElement,
 | 
						|
                               aContextsToClear, aSwappedStructOwners);
 | 
						|
 | 
						|
      restyler.Restyle(aRestyleHint);
 | 
						|
 | 
						|
      if (restyler.HintsHandledForFrame() & nsChangeHint_ReconstructFrame) {
 | 
						|
        // If it's going to cause a framechange, then don't bother
 | 
						|
        // with the continuations or ib-split siblings since they'll be
 | 
						|
        // clobbered by the frame reconstruct anyway.
 | 
						|
        NS_ASSERTION(!cont->GetPrevContinuation(),
 | 
						|
                     "continuing frame had more severe impact than first-in-flow");
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels ConditionallyRestyleUndisplayedDescendants.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint)
 | 
						|
{
 | 
						|
  nsIContent* undisplayedParent;
 | 
						|
  if (MustCheckUndisplayedContent(mFrame, undisplayedParent)) {
 | 
						|
    DoRestyleUndisplayedDescendants(aChildRestyleHint, undisplayedParent,
 | 
						|
                                    mFrame->StyleContext());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels DoConditionallyRestyleUndisplayedDescendants.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
 | 
						|
                                                 nsIContent* aParent,
 | 
						|
                                                 nsStyleContext* aParentContext)
 | 
						|
{
 | 
						|
  nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
 | 
						|
  UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
 | 
						|
  RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
 | 
						|
                          aParentContext, StyleDisplay::None_);
 | 
						|
  nodes = fc->GetAllDisplayContentsIn(aParent);
 | 
						|
  RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
 | 
						|
                          aParentContext, StyleDisplay::Contents);
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels ConditionallyRestyleUndisplayedNodes.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint      aChildRestyleHint,
 | 
						|
                                         UndisplayedNode*   aUndisplayed,
 | 
						|
                                         nsIContent*        aUndisplayedParent,
 | 
						|
                                         nsStyleContext*    aParentContext,
 | 
						|
                                         const StyleDisplay aDisplay)
 | 
						|
{
 | 
						|
  nsIContent* undisplayedParent = aUndisplayedParent;
 | 
						|
  UndisplayedNode* undisplayed = aUndisplayed;
 | 
						|
  TreeMatchContext::AutoAncestorPusher pusher(mTreeMatchContext);
 | 
						|
  if (undisplayed) {
 | 
						|
    pusher.PushAncestorAndStyleScope(undisplayedParent);
 | 
						|
  }
 | 
						|
  for (; undisplayed; undisplayed = undisplayed->mNext) {
 | 
						|
    NS_ASSERTION(undisplayedParent ||
 | 
						|
                 undisplayed->mContent ==
 | 
						|
                   mPresContext->Document()->GetRootElement(),
 | 
						|
                 "undisplayed node child of null must be root");
 | 
						|
    NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
 | 
						|
                 "Shouldn't have random pseudo style contexts in the "
 | 
						|
                 "undisplayed map");
 | 
						|
 | 
						|
    LOG_RESTYLE("RestyleUndisplayedChildren: undisplayed->mContent = %p",
 | 
						|
                undisplayed->mContent.get());
 | 
						|
 | 
						|
    // Get the parent of the undisplayed content and check if it is a XBL
 | 
						|
    // children element. Push the children element as an ancestor here because it does
 | 
						|
    // not have a frame and would not otherwise be pushed as an ancestor.
 | 
						|
    nsIContent* parent = undisplayed->mContent->GetParent();
 | 
						|
    TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
 | 
						|
    if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
 | 
						|
      insertionPointPusher.PushAncestorAndStyleScope(parent);
 | 
						|
    }
 | 
						|
 | 
						|
    nsRestyleHint thisChildHint = aChildRestyleHint;
 | 
						|
    nsAutoPtr<RestyleTracker::RestyleData> undisplayedRestyleData;
 | 
						|
    Element* element = undisplayed->mContent->AsElement();
 | 
						|
    if (mRestyleTracker.GetRestyleData(element,
 | 
						|
                                       undisplayedRestyleData)) {
 | 
						|
      thisChildHint =
 | 
						|
        nsRestyleHint(thisChildHint | undisplayedRestyleData->mRestyleHint);
 | 
						|
    }
 | 
						|
    RefPtr<nsStyleContext> undisplayedContext;
 | 
						|
    nsStyleSet* styleSet = StyleSet();
 | 
						|
    if (MustRestyleSelf(thisChildHint, element)) {
 | 
						|
      undisplayedContext =
 | 
						|
        styleSet->ResolveStyleFor(element, aParentContext, mTreeMatchContext);
 | 
						|
    } else if (CanReparentStyleContext(thisChildHint)) {
 | 
						|
      undisplayedContext =
 | 
						|
        styleSet->ReparentStyleContext(undisplayed->mStyle,
 | 
						|
                                       aParentContext,
 | 
						|
                                       element);
 | 
						|
    } else {
 | 
						|
      // Use ResolveStyleWithReplacement either for actual
 | 
						|
      // replacements, or as a substitute for ReparentStyleContext
 | 
						|
      // that rebuilds the path in the rule tree rather than reusing
 | 
						|
      // the rule node, as we need to do during a rule tree
 | 
						|
      // reconstruct.
 | 
						|
      nsRestyleHint rshint = thisChildHint & ~eRestyle_SomeDescendants;
 | 
						|
      undisplayedContext =
 | 
						|
        styleSet->ResolveStyleWithReplacement(element, nullptr,
 | 
						|
                                              aParentContext,
 | 
						|
                                              undisplayed->mStyle,
 | 
						|
                                              rshint);
 | 
						|
    }
 | 
						|
    const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
 | 
						|
    if (display->mDisplay != aDisplay) {
 | 
						|
      NS_ASSERTION(element, "Must have undisplayed content");
 | 
						|
      mChangeList->AppendChange(nullptr, element,
 | 
						|
                                nsChangeHint_ReconstructFrame);
 | 
						|
      // The node should be removed from the undisplayed map when
 | 
						|
      // we reframe it.
 | 
						|
    } else {
 | 
						|
      // update the undisplayed node with the new context
 | 
						|
      undisplayed->mStyle = undisplayedContext;
 | 
						|
 | 
						|
      if (aDisplay == StyleDisplay::Contents) {
 | 
						|
        DoRestyleUndisplayedDescendants(aChildRestyleHint, element,
 | 
						|
                                        undisplayed->mStyle);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::MaybeReframeForBeforePseudo()
 | 
						|
{
 | 
						|
  MaybeReframeForPseudo(CSSPseudoElementType::before,
 | 
						|
                        mFrame, mFrame, mFrame->GetContent(),
 | 
						|
                        mFrame->StyleContext());
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * aFrame is the last continuation or block-in-inline sibling that this
 | 
						|
 * ElementRestyler is restyling.
 | 
						|
 */
 | 
						|
void
 | 
						|
ElementRestyler::MaybeReframeForAfterPseudo(nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aFrame);
 | 
						|
  MaybeReframeForPseudo(CSSPseudoElementType::after,
 | 
						|
                        aFrame, aFrame, aFrame->GetContent(),
 | 
						|
                        aFrame->StyleContext());
 | 
						|
}
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
bool
 | 
						|
ElementRestyler::MustReframeForBeforePseudo()
 | 
						|
{
 | 
						|
  return MustReframeForPseudo(CSSPseudoElementType::before,
 | 
						|
                              mFrame, mFrame, mFrame->GetContent(),
 | 
						|
                              mFrame->StyleContext());
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::MustReframeForAfterPseudo(nsIFrame* aFrame)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aFrame);
 | 
						|
  return MustReframeForPseudo(CSSPseudoElementType::after,
 | 
						|
                              aFrame, aFrame, aFrame->GetContent(),
 | 
						|
                              aFrame->StyleContext());
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::MaybeReframeForPseudo(CSSPseudoElementType aPseudoType,
 | 
						|
                                       nsIFrame* aGenConParentFrame,
 | 
						|
                                       nsIFrame* aFrame,
 | 
						|
                                       nsIContent* aContent,
 | 
						|
                                       nsStyleContext* aStyleContext)
 | 
						|
{
 | 
						|
  if (MustReframeForPseudo(aPseudoType, aGenConParentFrame, aFrame, aContent,
 | 
						|
                           aStyleContext)) {
 | 
						|
    // Have to create the new ::before/::after frame.
 | 
						|
    LOG_RESTYLE("MaybeReframeForPseudo, appending "
 | 
						|
                "nsChangeHint_ReconstructFrame");
 | 
						|
    mHintsHandled |= nsChangeHint_ReconstructFrame;
 | 
						|
    mChangeList->AppendChange(aFrame, aContent, nsChangeHint_ReconstructFrame);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
ElementRestyler::MustReframeForPseudo(CSSPseudoElementType aPseudoType,
 | 
						|
                                      nsIFrame* aGenConParentFrame,
 | 
						|
                                      nsIFrame* aFrame,
 | 
						|
                                      nsIContent* aContent,
 | 
						|
                                      nsStyleContext* aStyleContext)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aPseudoType == CSSPseudoElementType::before ||
 | 
						|
             aPseudoType == CSSPseudoElementType::after);
 | 
						|
 | 
						|
  // Make sure not to do this for pseudo-frames...
 | 
						|
  if (aStyleContext->GetPseudo()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // ... or frames that can't have generated content.
 | 
						|
  if (!(aGenConParentFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT)) {
 | 
						|
    // Our content insertion frame might have gotten flagged.
 | 
						|
    nsContainerFrame* cif = aGenConParentFrame->GetContentInsertionFrame();
 | 
						|
    if (!cif || !(cif->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPseudoType == CSSPseudoElementType::before) {
 | 
						|
    // Check for a ::before pseudo style and the absence of a ::before content,
 | 
						|
    // but only if aFrame is null or is the first continuation/ib-split.
 | 
						|
    if ((aFrame && !nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) ||
 | 
						|
        nsLayoutUtils::GetBeforeFrameForContent(aGenConParentFrame, aContent)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    // Similarly for ::after, but check for being the last continuation/
 | 
						|
    // ib-split.
 | 
						|
    if ((aFrame && nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) ||
 | 
						|
        nsLayoutUtils::GetAfterFrameForContent(aGenConParentFrame, aContent)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Checking for a ::before frame (which we do above) is cheaper than getting
 | 
						|
  // the ::before style context here.
 | 
						|
  return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, aPseudoType,
 | 
						|
                                       mPresContext);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::InitializeAccessibilityNotifications(nsStyleContext* aNewContext)
 | 
						|
{
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  // Notify a11y for primary frame only if it's a root frame of visibility
 | 
						|
  // changes or its parent frame was hidden while it stays visible and
 | 
						|
  // it is not inside a {ib} split or is the first frame of {ib} split.
 | 
						|
  if (nsIPresShell::IsAccessibilityActive() &&
 | 
						|
      (!mFrame ||
 | 
						|
       (!mFrame->GetPrevContinuation() &&
 | 
						|
        !mFrame->FrameIsNonFirstInIBSplit()))) {
 | 
						|
    if (mDesiredA11yNotifications == eSendAllNotifications) {
 | 
						|
      bool isFrameVisible = aNewContext->StyleVisibility()->IsVisible();
 | 
						|
      if (isFrameVisible != mWasFrameVisible) {
 | 
						|
        if (isFrameVisible) {
 | 
						|
          // Notify a11y the element (perhaps with its children) was shown.
 | 
						|
          // We don't fall into this case if this element gets or stays shown
 | 
						|
          // while its parent becomes hidden.
 | 
						|
          mKidsDesiredA11yNotifications = eSkipNotifications;
 | 
						|
          mOurA11yNotification = eNotifyShown;
 | 
						|
        } else {
 | 
						|
          // The element is being hidden; its children may stay visible, or
 | 
						|
          // become visible after being hidden previously. If we'll find
 | 
						|
          // visible children then we should notify a11y about that as if
 | 
						|
          // they were inserted into tree. Notify a11y this element was
 | 
						|
          // hidden.
 | 
						|
          mKidsDesiredA11yNotifications = eNotifyIfShown;
 | 
						|
          mOurA11yNotification = eNotifyHidden;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else if (mDesiredA11yNotifications == eNotifyIfShown &&
 | 
						|
               aNewContext->StyleVisibility()->IsVisible()) {
 | 
						|
      // Notify a11y that element stayed visible while its parent was hidden.
 | 
						|
      nsIContent* c = mFrame ? mFrame->GetContent() : mContent;
 | 
						|
      mVisibleKidsOfHiddenElement.AppendElement(c);
 | 
						|
      mKidsDesiredA11yNotifications = eSkipNotifications;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
// The structure of this method parallels ConditionallyRestyleContentChildren.
 | 
						|
// If you update this method, you probably want to update that one too.
 | 
						|
void
 | 
						|
ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
 | 
						|
                                        nsRestyleHint aChildRestyleHint)
 | 
						|
{
 | 
						|
  LOG_RESTYLE("RestyleContentChildren");
 | 
						|
 | 
						|
  nsIFrame::ChildListIterator lists(aParent);
 | 
						|
  TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext);
 | 
						|
  if (!lists.IsDone()) {
 | 
						|
    ancestorPusher.PushAncestorAndStyleScope(mContent);
 | 
						|
  }
 | 
						|
  for (; !lists.IsDone(); lists.Next()) {
 | 
						|
    for (nsIFrame* child : lists.CurrentList()) {
 | 
						|
      // Out-of-flows are reached through their placeholders.  Continuations
 | 
						|
      // and block-in-inline splits are reached through those chains.
 | 
						|
      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
 | 
						|
          !GetPrevContinuationWithSameStyle(child)) {
 | 
						|
        // Get the parent of the child frame's content and check if it
 | 
						|
        // is a XBL children element. Push the children element as an
 | 
						|
        // ancestor here because it does not have a frame and would not
 | 
						|
        // otherwise be pushed as an ancestor.
 | 
						|
 | 
						|
        // Check if the frame has a content because |child| may be a
 | 
						|
        // nsPageFrame that does not have a content.
 | 
						|
        nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
 | 
						|
        TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
 | 
						|
        if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
 | 
						|
          insertionPointPusher.PushAncestorAndStyleScope(parent);
 | 
						|
        }
 | 
						|
 | 
						|
        // only do frames that are in flow
 | 
						|
        if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
 | 
						|
          // get out of flow frame and recur there
 | 
						|
          nsIFrame* outOfFlowFrame =
 | 
						|
            nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
 | 
						|
          NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
 | 
						|
          NS_ASSERTION(outOfFlowFrame != mResolvedChild,
 | 
						|
                       "out-of-flow frame not a true descendant");
 | 
						|
 | 
						|
          // |nsFrame::GetParentStyleContext| checks being out
 | 
						|
          // of flow so that this works correctly.
 | 
						|
          do {
 | 
						|
            if (GetPrevContinuationWithSameStyle(outOfFlowFrame)) {
 | 
						|
              // Later continuations are likely restyled as a result of
 | 
						|
              // the restyling of the previous continuation.
 | 
						|
              // (Currently that's always true, but it's likely to
 | 
						|
              // change if we implement overflow:fragments or similar.)
 | 
						|
              continue;
 | 
						|
            }
 | 
						|
            ElementRestyler oofRestyler(*this, outOfFlowFrame,
 | 
						|
                                        FOR_OUT_OF_FLOW_CHILD);
 | 
						|
            oofRestyler.Restyle(aChildRestyleHint);
 | 
						|
          } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
 | 
						|
 | 
						|
          // reresolve placeholder's context under the same parent
 | 
						|
          // as the out-of-flow frame
 | 
						|
          ElementRestyler phRestyler(*this, child, 0);
 | 
						|
          phRestyler.Restyle(aChildRestyleHint);
 | 
						|
        }
 | 
						|
        else {  // regular child frame
 | 
						|
          if (child != mResolvedChild) {
 | 
						|
            ElementRestyler childRestyler(*this, child, 0);
 | 
						|
            childRestyler.Restyle(aChildRestyleHint);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  // XXX need to do overflow frames???
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ElementRestyler::SendAccessibilityNotifications()
 | 
						|
{
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  // Send notifications about visibility changes.
 | 
						|
  if (mOurA11yNotification == eNotifyShown) {
 | 
						|
    nsAccessibilityService* accService = nsIPresShell::AccService();
 | 
						|
    if (accService) {
 | 
						|
      nsIPresShell* presShell = mPresContext->GetPresShell();
 | 
						|
      nsIContent* content = mFrame ? mFrame->GetContent() : mContent;
 | 
						|
 | 
						|
      accService->ContentRangeInserted(presShell, content->GetParent(),
 | 
						|
                                       content,
 | 
						|
                                       content->GetNextSibling());
 | 
						|
    }
 | 
						|
  } else if (mOurA11yNotification == eNotifyHidden) {
 | 
						|
    nsAccessibilityService* accService = nsIPresShell::AccService();
 | 
						|
    if (accService) {
 | 
						|
      nsIPresShell* presShell = mPresContext->GetPresShell();
 | 
						|
      nsIContent* content = mFrame ? mFrame->GetContent() : mContent;
 | 
						|
      accService->ContentRemoved(presShell, content);
 | 
						|
 | 
						|
      // Process children staying shown.
 | 
						|
      uint32_t visibleContentCount = mVisibleKidsOfHiddenElement.Length();
 | 
						|
      for (uint32_t idx = 0; idx < visibleContentCount; idx++) {
 | 
						|
        nsIContent* childContent = mVisibleKidsOfHiddenElement[idx];
 | 
						|
        accService->ContentRangeInserted(presShell, childContent->GetParent(),
 | 
						|
                                         childContent,
 | 
						|
                                         childContent->GetNextSibling());
 | 
						|
      }
 | 
						|
      mVisibleKidsOfHiddenElement.Clear();
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ClearCachedInheritedStyleDataOnDescendants(
 | 
						|
    nsTArray<ElementRestyler::ContextToClear>& aContextsToClear)
 | 
						|
{
 | 
						|
  for (size_t i = 0; i < aContextsToClear.Length(); i++) {
 | 
						|
    auto& entry = aContextsToClear[i];
 | 
						|
    if (!entry.mStyleContext->HasSingleReference()) {
 | 
						|
      entry.mStyleContext->ClearCachedInheritedStyleDataOnDescendants(
 | 
						|
          entry.mStructs);
 | 
						|
    }
 | 
						|
    entry.mStyleContext = nullptr;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::ComputeAndProcessStyleChange(nsIFrame*              aFrame,
 | 
						|
                                             nsChangeHint           aMinChange,
 | 
						|
                                             RestyleTracker&        aRestyleTracker,
 | 
						|
                                             nsRestyleHint          aRestyleHint,
 | 
						|
                                             const RestyleHintData& aRestyleHintData)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
 | 
						|
  nsStyleChangeList changeList;
 | 
						|
  nsTArray<ElementRestyler::ContextToClear> contextsToClear;
 | 
						|
 | 
						|
  // swappedStructOwners needs to be kept alive until after
 | 
						|
  // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
 | 
						|
  // calls; see comment in ElementRestyler::Restyle.
 | 
						|
  nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
 | 
						|
  ElementRestyler::ComputeStyleChangeFor(aFrame, &changeList, aMinChange,
 | 
						|
                                         aRestyleTracker, aRestyleHint,
 | 
						|
                                         aRestyleHintData,
 | 
						|
                                         contextsToClear, swappedStructOwners);
 | 
						|
  ProcessRestyledFrames(changeList);
 | 
						|
  ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RestyleManager::ComputeAndProcessStyleChange(nsStyleContext*        aNewContext,
 | 
						|
                                             Element*               aElement,
 | 
						|
                                             nsChangeHint           aMinChange,
 | 
						|
                                             RestyleTracker&        aRestyleTracker,
 | 
						|
                                             nsRestyleHint          aRestyleHint,
 | 
						|
                                             const RestyleHintData& aRestyleHintData)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
 | 
						|
  MOZ_ASSERT(aNewContext->StyleDisplay()->mDisplay == StyleDisplay::Contents);
 | 
						|
  nsIFrame* frame = GetNearestAncestorFrame(aElement);
 | 
						|
  MOZ_ASSERT(frame, "display:contents node in map although it's a "
 | 
						|
                    "display:none descendant?");
 | 
						|
  TreeMatchContext treeMatchContext(true,
 | 
						|
                                    nsRuleWalker::eRelevantLinkUnvisited,
 | 
						|
                                    frame->PresContext()->Document());
 | 
						|
  nsIContent* parent = aElement->GetParent();
 | 
						|
  Element* parentElement =
 | 
						|
    parent && parent->IsElement() ? parent->AsElement() : nullptr;
 | 
						|
  treeMatchContext.InitAncestors(parentElement);
 | 
						|
 | 
						|
  nsTArray<nsCSSSelector*> selectorsForDescendants;
 | 
						|
  nsTArray<nsIContent*> visibleKidsOfHiddenElement;
 | 
						|
  nsTArray<ElementRestyler::ContextToClear> contextsToClear;
 | 
						|
 | 
						|
  // swappedStructOwners needs to be kept alive until after
 | 
						|
  // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
 | 
						|
  // calls; see comment in ElementRestyler::Restyle.
 | 
						|
  nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
 | 
						|
  nsStyleChangeList changeList;
 | 
						|
  ElementRestyler r(frame->PresContext(), aElement, &changeList, aMinChange,
 | 
						|
                    aRestyleTracker, selectorsForDescendants, treeMatchContext,
 | 
						|
                    visibleKidsOfHiddenElement, contextsToClear,
 | 
						|
                    swappedStructOwners);
 | 
						|
  r.RestyleChildrenOfDisplayContentsElement(frame, aNewContext, aMinChange,
 | 
						|
                                            aRestyleTracker,
 | 
						|
                                            aRestyleHint, aRestyleHintData);
 | 
						|
  ProcessRestyledFrames(changeList);
 | 
						|
  ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
 | 
						|
}
 | 
						|
 | 
						|
nsStyleSet*
 | 
						|
ElementRestyler::StyleSet() const
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(),
 | 
						|
             "ElementRestyler should only be used with a Gecko-flavored "
 | 
						|
             "style backend");
 | 
						|
  return mPresContext->StyleSet()->AsGecko();
 | 
						|
}
 | 
						|
 | 
						|
AutoDisplayContentsAncestorPusher::AutoDisplayContentsAncestorPusher(
 | 
						|
  TreeMatchContext& aTreeMatchContext, nsPresContext* aPresContext,
 | 
						|
  nsIContent* aParent)
 | 
						|
  : mTreeMatchContext(aTreeMatchContext)
 | 
						|
  , mPresContext(aPresContext)
 | 
						|
{
 | 
						|
  if (aParent) {
 | 
						|
    nsFrameManager* fm = mPresContext->FrameManager();
 | 
						|
    // Push display:contents mAncestors onto mTreeMatchContext.
 | 
						|
    for (nsIContent* p = aParent; p && fm->GetDisplayContentsStyleFor(p);
 | 
						|
         p = p->GetParent()) {
 | 
						|
      mAncestors.AppendElement(p->AsElement());
 | 
						|
    }
 | 
						|
    bool hasFilter = mTreeMatchContext.mAncestorFilter.HasFilter();
 | 
						|
    nsTArray<mozilla::dom::Element*>::size_type i = mAncestors.Length();
 | 
						|
    while (i--) {
 | 
						|
      if (hasFilter) {
 | 
						|
        mTreeMatchContext.mAncestorFilter.PushAncestor(mAncestors[i]);
 | 
						|
      }
 | 
						|
      mTreeMatchContext.PushStyleScope(mAncestors[i]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
AutoDisplayContentsAncestorPusher::~AutoDisplayContentsAncestorPusher()
 | 
						|
{
 | 
						|
  // Pop the ancestors we pushed in the CTOR, if any.
 | 
						|
  typedef nsTArray<mozilla::dom::Element*>::size_type sz;
 | 
						|
  sz len = mAncestors.Length();
 | 
						|
  bool hasFilter = mTreeMatchContext.mAncestorFilter.HasFilter();
 | 
						|
  for (sz i = 0; i < len; ++i) {
 | 
						|
    if (hasFilter) {
 | 
						|
      mTreeMatchContext.mAncestorFilter.PopAncestor();
 | 
						|
    }
 | 
						|
    mTreeMatchContext.PopStyleScope(mAncestors[i]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#ifdef RESTYLE_LOGGING
 | 
						|
uint32_t
 | 
						|
RestyleManager::StructsToLog()
 | 
						|
{
 | 
						|
  static bool initialized = false;
 | 
						|
  static uint32_t structs;
 | 
						|
  if (!initialized) {
 | 
						|
    structs = 0;
 | 
						|
    const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS");
 | 
						|
    if (value) {
 | 
						|
      nsCString s(value);
 | 
						|
      while (!s.IsEmpty()) {
 | 
						|
        int32_t index = s.FindChar(',');
 | 
						|
        nsStyleStructID sid;
 | 
						|
        bool found;
 | 
						|
        if (index == -1) {
 | 
						|
          found = nsStyleContext::LookupStruct(s, sid);
 | 
						|
          s.Truncate();
 | 
						|
        } else {
 | 
						|
          found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid);
 | 
						|
          s = Substring(s, index + 1);
 | 
						|
        }
 | 
						|
        if (found) {
 | 
						|
          structs |= nsCachedStyleData::GetBitForSID(sid);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    initialized = true;
 | 
						|
  }
 | 
						|
  return structs;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
/* static */ nsCString
 | 
						|
RestyleManager::StructNamesToString(uint32_t aSIDs)
 | 
						|
{
 | 
						|
  nsCString result;
 | 
						|
  bool any = false;
 | 
						|
  for (nsStyleStructID sid = nsStyleStructID(0);
 | 
						|
       sid < nsStyleStructID_Length;
 | 
						|
       sid = nsStyleStructID(sid + 1)) {
 | 
						|
    if (aSIDs & nsCachedStyleData::GetBitForSID(sid)) {
 | 
						|
      if (any) {
 | 
						|
        result.AppendLiteral(",");
 | 
						|
      }
 | 
						|
      result.AppendPrintf("%s", nsStyleContext::StructName(sid));
 | 
						|
      any = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
/* static */ nsCString
 | 
						|
ElementRestyler::RestyleResultToString(RestyleResult aRestyleResult)
 | 
						|
{
 | 
						|
  nsCString result;
 | 
						|
  switch (aRestyleResult) {
 | 
						|
    case RestyleResult::eStop:
 | 
						|
      result.AssignLiteral("RestyleResult::eStop");
 | 
						|
      break;
 | 
						|
    case RestyleResult::eStopWithStyleChange:
 | 
						|
      result.AssignLiteral("RestyleResult::eStopWithStyleChange");
 | 
						|
      break;
 | 
						|
    case RestyleResult::eContinue:
 | 
						|
      result.AssignLiteral("RestyleResult::eContinue");
 | 
						|
      break;
 | 
						|
    case RestyleResult::eContinueAndForceDescendants:
 | 
						|
      result.AssignLiteral("RestyleResult::eContinueAndForceDescendants");
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      MOZ_ASSERT(aRestyleResult == RestyleResult::eNone,
 | 
						|
                 "Unexpected RestyleResult");
 | 
						|
  }
 | 
						|
  return result;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
} // namespace mozilla
 |