2013-07-20 23:14:24 +04:00
|
|
|
/* -*- 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.
|
|
|
|
*/
|
|
|
|
|
2016-02-24 10:01:12 +03:00
|
|
|
#include "mozilla/RestyleManager.h"
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
#include <algorithm> // For std::max
|
2015-08-06 05:42:09 +03:00
|
|
|
#include "mozilla/EffectSet.h"
|
2014-04-03 08:18:36 +04:00
|
|
|
#include "mozilla/EventStates.h"
|
2016-11-30 06:14:29 +03:00
|
|
|
#include "mozilla/ViewportFrame.h"
|
2016-12-31 12:11:05 +03:00
|
|
|
#include "mozilla/css/StyleRule.h" // For nsCSSSelector
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsLayoutUtils.h"
|
2014-11-17 07:46:00 +03:00
|
|
|
#include "AnimationCommon.h" // For GetLayerAnimationInfo
|
2014-11-17 07:46:00 +03:00
|
|
|
#include "FrameLayerBuilder.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "GeckoProfiler.h"
|
2015-09-03 23:59:00 +03:00
|
|
|
#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
|
2016-06-07 23:10:18 +03:00
|
|
|
#include "nsAutoPtr.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsStyleChangeList.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsRuleProcessorData.h"
|
2016-02-24 10:01:10 +03:00
|
|
|
#include "nsStyleSet.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsStyleUtil.h"
|
|
|
|
#include "nsCSSFrameConstructor.h"
|
|
|
|
#include "nsSVGEffects.h"
|
2016-02-17 23:37:00 +03:00
|
|
|
#include "nsCSSPseudoElements.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsCSSRendering.h"
|
|
|
|
#include "nsAnimationManager.h"
|
|
|
|
#include "nsTransitionManager.h"
|
|
|
|
#include "nsViewManager.h"
|
|
|
|
#include "nsRenderingContext.h"
|
|
|
|
#include "nsSVGIntegrationUtils.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsCSSAnonBoxes.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsContainerFrame.h"
|
|
|
|
#include "nsPlaceholderFrame.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsBlockFrame.h"
|
2013-12-20 20:38:51 +04:00
|
|
|
#include "SVGTextFrame.h"
|
2013-09-06 17:35:16 +04:00
|
|
|
#include "StickyScrollContainer.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsIRootBox.h"
|
|
|
|
#include "nsIDOMMutationEvent.h"
|
2013-08-14 10:55:46 +04:00
|
|
|
#include "nsContentUtils.h"
|
2013-10-02 01:00:38 +04:00
|
|
|
#include "nsIFrameInlines.h"
|
2013-09-04 15:30:57 +04:00
|
|
|
#include "ActiveLayerTracker.h"
|
2014-03-05 08:13:22 +04:00
|
|
|
#include "nsDisplayList.h"
|
2014-09-25 09:45:36 +04:00
|
|
|
#include "RestyleTrackerInlines.h"
|
2015-02-17 01:15:02 +03:00
|
|
|
#include "nsSMILAnimationController.h"
|
2015-08-05 15:42:20 +03:00
|
|
|
#include "nsCSSRuleProcessor.h"
|
|
|
|
#include "ChildIterator.h"
|
2015-12-22 18:54:19 +03:00
|
|
|
#include "Layers.h"
|
2013-07-20 23:14:24 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
#include "nsAccessibilityService.h"
|
|
|
|
#endif
|
|
|
|
|
2013-07-20 23:14:24 +04:00
|
|
|
namespace mozilla {
|
|
|
|
|
2014-03-05 09:05:18 +04:00
|
|
|
using namespace layers;
|
2015-12-22 18:54:19 +03:00
|
|
|
using namespace dom;
|
2014-03-05 09:05:18 +04:00
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
#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;
|
|
|
|
}
|
2015-08-05 15:42:21 +03:00
|
|
|
|
|
|
|
static nsCString
|
|
|
|
ElementTagToString(dom::Element* aElement)
|
|
|
|
{
|
|
|
|
nsCString result;
|
|
|
|
nsDependentAtomString buf(aElement->NodeInfo()->NameAtom());
|
|
|
|
result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
|
|
|
|
return result;
|
|
|
|
}
|
2014-09-25 09:45:36 +04:00
|
|
|
#endif
|
|
|
|
|
2013-07-20 23:14:24 +04:00
|
|
|
RestyleManager::RestyleManager(nsPresContext* aPresContext)
|
2016-07-08 10:08:46 +03:00
|
|
|
: RestyleManagerBase(aPresContext)
|
2015-01-14 08:03:11 +03:00
|
|
|
, mDoRebuildAllStyleData(false)
|
2015-01-14 08:03:12 +03:00
|
|
|
, mInRebuildAllStyleData(false)
|
2014-10-03 08:53:23 +04:00
|
|
|
, mSkipAnimationRules(false)
|
2015-02-17 01:15:02 +03:00
|
|
|
, mHavePendingNonAnimationRestyles(false)
|
2013-07-20 23:14:25 +04:00
|
|
|
, mRebuildAllExtraHint(nsChangeHint(0))
|
2014-10-09 01:26:57 +04:00
|
|
|
, mRebuildAllRestyleHint(nsRestyleHint(0))
|
2013-07-20 23:14:25 +04:00
|
|
|
, mAnimationGeneration(0)
|
2014-08-14 02:39:01 +04:00
|
|
|
, mReframingStyleContexts(nullptr)
|
2015-09-15 00:42:00 +03:00
|
|
|
, mAnimationsWithDestroyedFrame(nullptr)
|
2013-07-20 23:14:25 +04:00
|
|
|
, mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
|
2015-09-12 12:08:10 +03:00
|
|
|
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
|
|
|
|
ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)
|
2014-10-03 08:53:23 +04:00
|
|
|
, mIsProcessingRestyles(false)
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
, mLoggingDepth(0)
|
|
|
|
#endif
|
2013-07-20 23:14:24 +04:00
|
|
|
{
|
2013-07-20 23:14:25 +04:00
|
|
|
mPendingRestyles.Init(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-08-05 15:42:20 +03:00
|
|
|
RestyleManager::RestyleElement(Element* aElement,
|
|
|
|
nsIFrame* aPrimaryFrame,
|
|
|
|
nsChangeHint aMinHint,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2015-01-14 08:03:13 +03:00
|
|
|
MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
|
2013-07-20 23:14:25 +04:00
|
|
|
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.
|
2016-07-08 10:08:46 +03:00
|
|
|
if (PresContext()->UsesRootEMUnits() && aPrimaryFrame &&
|
2015-01-14 08:03:12 +03:00
|
|
|
!mInRebuildAllStyleData) {
|
2016-07-08 10:08:46 +03:00
|
|
|
nsStyleContext* oldContext = aPrimaryFrame->StyleContext();
|
2013-07-20 23:14:25 +04:00
|
|
|
if (!oldContext->GetParent()) { // check that we're the root element
|
2016-02-24 10:01:10 +03:00
|
|
|
RefPtr<nsStyleContext> newContext = StyleSet()->
|
2013-07-20 23:14:25 +04:00
|
|
|
ResolveStyleFor(aElement, nullptr /* == oldContext->GetParent() */);
|
|
|
|
if (oldContext->StyleFont()->mFont.size !=
|
|
|
|
newContext->StyleFont()->mFont.size) {
|
|
|
|
// The basis for 'rem' units has changed.
|
2015-01-14 08:03:11 +03:00
|
|
|
mRebuildAllRestyleHint |= aRestyleHint;
|
2015-08-05 15:42:20 +03:00
|
|
|
if (aRestyleHint & eRestyle_SomeDescendants) {
|
|
|
|
mRebuildAllRestyleHint |= eRestyle_Subtree;
|
|
|
|
}
|
2016-05-23 06:26:03 +03:00
|
|
|
mRebuildAllExtraHint |= aMinHint;
|
2015-01-14 08:03:12 +03:00
|
|
|
StartRebuildAllStyleData(aRestyleTracker);
|
2015-01-14 08:03:12 +03:00
|
|
|
return;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aMinHint & nsChangeHint_ReconstructFrame) {
|
2014-10-23 17:19:26 +04:00
|
|
|
FrameConstructor()->RecreateFramesForContent(aElement, false,
|
|
|
|
nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
|
2013-07-20 23:14:25 +04:00
|
|
|
} else if (aPrimaryFrame) {
|
2014-08-14 02:39:00 +04:00
|
|
|
ComputeAndProcessStyleChange(aPrimaryFrame, aMinHint, aRestyleTracker,
|
2015-08-05 15:42:20 +03:00
|
|
|
aRestyleHint, aRestyleHintData);
|
2014-08-04 00:11:55 +04:00
|
|
|
} 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.
|
2014-11-20 21:24:10 +03:00
|
|
|
nsStyleContext* newContext =
|
|
|
|
FrameConstructor()->MaybeRecreateFramesForElement(aElement);
|
|
|
|
if (newContext &&
|
2016-08-28 05:31:50 +03:00
|
|
|
newContext->StyleDisplay()->mDisplay == StyleDisplay::Contents) {
|
2014-11-20 21:24:10 +03:00
|
|
|
// Style change for a display:contents node that did not recreate frames.
|
|
|
|
ComputeAndProcessStyleChange(newContext, aElement, aMinHint,
|
2015-08-05 15:42:20 +03:00
|
|
|
aRestyleTracker, aRestyleHint,
|
|
|
|
aRestyleHintData);
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:13 +03:00
|
|
|
RestyleManager::ReframingStyleContexts::ReframingStyleContexts(
|
|
|
|
RestyleManager* aRestyleManager)
|
|
|
|
: mRestyleManager(aRestyleManager)
|
2015-01-14 08:03:13 +03:00
|
|
|
, mRestorePointer(mRestyleManager->mReframingStyleContexts)
|
2015-01-14 08:03:13 +03:00
|
|
|
{
|
2015-01-14 08:03:13 +03:00
|
|
|
MOZ_ASSERT(!mRestyleManager->mReframingStyleContexts,
|
|
|
|
"shouldn't construct recursively");
|
|
|
|
mRestyleManager->mReframingStyleContexts = this;
|
2015-01-14 08:03:13 +03:00
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:13 +03:00
|
|
|
RestyleManager::ReframingStyleContexts::~ReframingStyleContexts()
|
|
|
|
{
|
|
|
|
// Before we go away, we need to flush out any frame construction that
|
2016-10-19 09:16:52 +03:00
|
|
|
// was enqueued, so that we initiate transitions.
|
2015-01-14 08:03:13 +03:00
|
|
|
// 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.
|
2016-07-08 10:08:46 +03:00
|
|
|
mRestyleManager->PresContext()->FrameConstructor()->CreateNeededFrames();
|
2015-01-14 08:03:13 +03:00
|
|
|
}
|
|
|
|
|
2015-09-15 00:42:00 +03:00
|
|
|
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()
|
|
|
|
{
|
2016-02-17 23:37:00 +03:00
|
|
|
StopAnimationsWithoutFrame(mContents, CSSPseudoElementType::NotPseudo);
|
|
|
|
StopAnimationsWithoutFrame(mBeforeContents, CSSPseudoElementType::before);
|
|
|
|
StopAnimationsWithoutFrame(mAfterContents, CSSPseudoElementType::after);
|
2015-09-15 00:42:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame(
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsIContent>>& aArray,
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType aPseudoType)
|
2015-09-15 00:42:00 +03:00
|
|
|
{
|
|
|
|
nsAnimationManager* animationManager =
|
|
|
|
mRestyleManager->PresContext()->AnimationManager();
|
2016-04-10 22:28:00 +03:00
|
|
|
nsTransitionManager* transitionManager =
|
|
|
|
mRestyleManager->PresContext()->TransitionManager();
|
2015-09-15 00:42:00 +03:00
|
|
|
for (nsIContent* content : aArray) {
|
|
|
|
if (content->GetPrimaryFrame()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
dom::Element* element = content->AsElement();
|
|
|
|
|
|
|
|
animationManager->StopAnimationsForElement(element, aPseudoType);
|
2016-04-10 22:28:00 +03:00
|
|
|
transitionManager->StopTransitionsForElement(element, aPseudoType);
|
2016-05-16 10:25:46 +03:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
}
|
2015-09-15 00:42:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:46:40 +04:00
|
|
|
static inline dom::Element*
|
|
|
|
ElementForStyleContext(nsIContent* aParentContent,
|
|
|
|
nsIFrame* aFrame,
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType aPseudoType);
|
2013-11-28 10:46:40 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// Forwarded nsIDocumentObserver method, to handle restyling (and
|
|
|
|
// passing the notification to the frame).
|
|
|
|
nsresult
|
|
|
|
RestyleManager::ContentStateChanged(nsIContent* aContent,
|
2014-04-03 08:18:36 +04:00
|
|
|
EventStates aStateMask)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
// 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();
|
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
nsChangeHint changeHint;
|
|
|
|
nsRestyleHint restyleHint;
|
|
|
|
ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
|
2013-11-28 10:46:40 +04:00
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
PostRestyleEvent(aElement, restyleHint, changeHint);
|
2013-07-20 23:14:25 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Forwarded nsIMutationObserver method, to handle restyling.
|
|
|
|
void
|
|
|
|
RestyleManager::AttributeWillChange(Element* aElement,
|
|
|
|
int32_t aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
2015-07-22 06:54:07 +03:00
|
|
|
int32_t aModType,
|
|
|
|
const nsAttrValue* aNewValue)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2015-08-05 15:42:21 +03:00
|
|
|
RestyleHintData rsdata;
|
2013-07-20 23:14:25 +04:00
|
|
|
nsRestyleHint rshint =
|
2016-02-24 10:01:10 +03:00
|
|
|
StyleSet()->HasAttributeDependentStyle(aElement,
|
|
|
|
aNameSpaceID,
|
|
|
|
aAttribute,
|
|
|
|
aModType,
|
|
|
|
false,
|
|
|
|
aNewValue,
|
|
|
|
rsdata);
|
2016-07-17 17:20:21 +03:00
|
|
|
PostRestyleEvent(aElement, rshint, nsChangeHint(0), &rsdata);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Forwarded nsIMutationObserver method, to handle restyling (and
|
|
|
|
// passing the notification to the frame).
|
|
|
|
void
|
|
|
|
RestyleManager::AttributeChanged(Element* aElement,
|
|
|
|
int32_t aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
2015-07-22 06:54:07 +03:00
|
|
|
int32_t aModType,
|
|
|
|
const nsAttrValue* aOldValue)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
// 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?
|
2016-07-08 10:08:46 +03:00
|
|
|
nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
|
2016-07-18 19:37:11 +03:00
|
|
|
mozilla::Unused << shell; // Unused within this function
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// 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;
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIAtom* tag = PresContext()->Document()->BindingManager()->
|
2013-07-20 23:14:25 +04:00
|
|
|
ResolveTag(aElement, &namespaceID);
|
|
|
|
|
|
|
|
if (namespaceID == kNameSpaceID_XUL &&
|
|
|
|
(tag == nsGkAtoms::listitem ||
|
|
|
|
tag == nsGkAtoms::listcell))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aAttribute == nsGkAtoms::tooltiptext ||
|
|
|
|
aAttribute == nsGkAtoms::tooltip)
|
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIRootBox* rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell());
|
2013-07-20 23:14:25 +04:00
|
|
|
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) {
|
2016-07-08 10:08:46 +03:00
|
|
|
nsITheme* theme = PresContext()->GetTheme();
|
|
|
|
if (theme && theme->ThemeSupportsWidget(PresContext(), primaryFrame, disp->mAppearance)) {
|
2013-07-20 23:14:25 +04:00
|
|
|
bool repaint = false;
|
2016-04-21 02:49:09 +03:00
|
|
|
theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute,
|
|
|
|
&repaint, aOldValue);
|
2013-07-20 23:14:25 +04:00
|
|
|
if (repaint)
|
2016-05-23 06:26:03 +03:00
|
|
|
hint |= nsChangeHint_RepaintFrame;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// let the frame deal with it now, so we don't have to deal later
|
|
|
|
primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
2014-02-07 05:45:33 +04:00
|
|
|
// XXXwaterson should probably check for IB split siblings
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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
|
2015-08-05 15:42:21 +03:00
|
|
|
RestyleHintData rsdata;
|
2013-07-20 23:14:25 +04:00
|
|
|
nsRestyleHint rshint =
|
2016-02-24 10:01:10 +03:00
|
|
|
StyleSet()->HasAttributeDependentStyle(aElement,
|
|
|
|
aNameSpaceID,
|
|
|
|
aAttribute,
|
|
|
|
aModType,
|
|
|
|
true,
|
|
|
|
aOldValue,
|
|
|
|
rsdata);
|
2015-08-05 15:42:21 +03:00
|
|
|
PostRestyleEvent(aElement, rshint, hint, &rsdata);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
/* static */ uint64_t
|
2016-01-06 05:04:05 +03:00
|
|
|
RestyleManager::GetAnimationGenerationForFrame(nsIFrame* aFrame)
|
2014-11-17 07:46:00 +03:00
|
|
|
{
|
2016-01-06 05:04:05 +03:00
|
|
|
EffectSet* effectSet = EffectSet::GetEffectSet(aFrame);
|
|
|
|
return effectSet ? effectSet->GetAnimationGeneration() : 0;
|
2014-11-17 07:46:00 +03:00
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
void
|
|
|
|
RestyleManager::RestyleForEmptyChange(Element* aContainer)
|
|
|
|
{
|
2015-10-30 02:38:20 +03:00
|
|
|
// In some cases (:empty + E, :empty ~ E), a change in the content of
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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);
|
|
|
|
}
|
2016-07-17 17:20:21 +03:00
|
|
|
PostRestyleEvent(aContainer, hint, nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
RestyleManager::RestyleForAppend(nsIContent* aContainer,
|
2013-07-20 23:14:25 +04:00
|
|
|
nsIContent* aFirstNewContent)
|
|
|
|
{
|
2016-08-16 21:33:30 +03:00
|
|
|
// The container cannot be a document, but might be a ShadowRoot.
|
|
|
|
if (!aContainer->IsElement()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Element* container = aContainer->AsElement();
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
#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 =
|
2016-08-16 21:33:30 +03:00
|
|
|
container->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
|
|
|
|
~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
2013-07-20 23:14:25 +04:00
|
|
|
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
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* cur = container->GetFirstChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
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) {
|
2016-08-16 21:33:30 +03:00
|
|
|
RestyleForEmptyChange(container);
|
2013-07-20 23:14:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
|
2016-08-16 21:33:30 +03:00
|
|
|
PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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()) {
|
2016-07-17 17:20:21 +03:00
|
|
|
PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
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 */)
|
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
for (nsIContent* sibling = aStartingSibling; sibling;
|
2013-07-20 23:14:25 +04:00
|
|
|
sibling = sibling->GetNextSibling()) {
|
|
|
|
if (sibling->IsElement()) {
|
|
|
|
aRestyleManager->
|
|
|
|
PostRestyleEvent(sibling->AsElement(),
|
|
|
|
nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings),
|
2016-07-17 17:20:21 +03:00
|
|
|
nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
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
|
2016-08-16 21:33:30 +03:00
|
|
|
RestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
|
2013-07-20 23:14:25 +04:00
|
|
|
nsIContent* aChild)
|
|
|
|
{
|
2016-08-16 21:33:30 +03:00
|
|
|
// The container might be a document or a ShadowRoot.
|
|
|
|
if (!aContainer->IsElement()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Element* container = aContainer->AsElement();
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(),
|
|
|
|
"anonymous nodes should not be in child lists");
|
|
|
|
uint32_t selectorFlags =
|
2016-08-16 21:33:30 +03:00
|
|
|
container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
|
2013-07-20 23:14:25 +04:00
|
|
|
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
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* child = container->GetFirstChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
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) {
|
2016-08-16 21:33:30 +03:00
|
|
|
RestyleForEmptyChange(container);
|
2013-07-20 23:14:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
|
2016-08-16 21:33:30 +03:00
|
|
|
PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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;
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* content = container->GetFirstChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
content;
|
|
|
|
content = content->GetNextSibling()) {
|
|
|
|
if (content == aChild) {
|
|
|
|
passedChild = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (content->IsElement()) {
|
|
|
|
if (passedChild) {
|
|
|
|
PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
|
2016-07-17 17:20:21 +03:00
|
|
|
nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// restyle the previously-last element child if it is before this node
|
|
|
|
passedChild = false;
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* content = container->GetLastChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
content;
|
|
|
|
content = content->GetPreviousSibling()) {
|
|
|
|
if (content == aChild) {
|
|
|
|
passedChild = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (content->IsElement()) {
|
|
|
|
if (passedChild) {
|
|
|
|
PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
|
2016-07-17 17:20:21 +03:00
|
|
|
nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
RestyleManager::ContentRemoved(nsINode* aContainer,
|
|
|
|
nsIContent* aOldChild,
|
2016-08-11 21:48:27 +03:00
|
|
|
nsIContent* aFollowingSibling)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2016-08-16 21:33:30 +03:00
|
|
|
// The container might be a document or a ShadowRoot.
|
|
|
|
if (!aContainer->IsElement()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Element* container = aContainer->AsElement();
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
if (aOldChild->IsRootOfAnonymousSubtree()) {
|
|
|
|
// This should be an assert, but this is called incorrectly in
|
2016-07-09 05:42:33 +03:00
|
|
|
// HTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging
|
2013-07-20 23:14:25 +04:00
|
|
|
// up the logs. Make it an assert again when that's fixed.
|
2015-07-24 19:47:51 +03:00
|
|
|
MOZ_ASSERT(aOldChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
|
|
|
|
"anonymous nodes should not be in child lists (bug 439258)");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
uint32_t selectorFlags =
|
2016-08-16 21:33:30 +03:00
|
|
|
container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
|
2013-07-20 23:14:25 +04:00
|
|
|
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
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* child = container->GetFirstChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
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) {
|
2016-08-16 21:33:30 +03:00
|
|
|
RestyleForEmptyChange(container);
|
2013-07-20 23:14:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
|
2016-08-16 21:33:30 +03:00
|
|
|
PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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;
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* content = container->GetFirstChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
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,
|
2016-07-17 17:20:21 +03:00
|
|
|
nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// restyle the now-last element child if it was before aOldChild
|
|
|
|
reachedFollowingSibling = (aFollowingSibling == nullptr);
|
2016-08-16 21:33:30 +03:00
|
|
|
for (nsIContent* content = container->GetLastChild();
|
2013-07-20 23:14:25 +04:00
|
|
|
content;
|
|
|
|
content = content->GetPreviousSibling()) {
|
|
|
|
if (content->IsElement()) {
|
|
|
|
if (reachedFollowingSibling) {
|
2016-07-17 17:20:21 +03:00
|
|
|
PostRestyleEvent(content->AsElement(), eRestyle_Subtree, nsChangeHint(0));
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (content == aFollowingSibling) {
|
|
|
|
reachedFollowingSibling = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-10-09 01:26:57 +04:00
|
|
|
RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
|
|
|
|
nsRestyleHint aRestyleHint)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
|
|
|
|
"Should not reconstruct the root of the frame tree. "
|
|
|
|
"Use ReconstructDocElementHierarchy instead.");
|
2015-08-05 15:42:20 +03:00
|
|
|
MOZ_ASSERT(!(aRestyleHint & ~(eRestyle_Subtree | eRestyle_ForceDescendants)),
|
|
|
|
"the only bits allowed in aRestyleHint are eRestyle_Subtree and "
|
|
|
|
"eRestyle_ForceDescendants");
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2016-05-23 06:26:03 +03:00
|
|
|
mRebuildAllExtraHint |= aExtraHint;
|
2015-01-14 08:03:11 +03:00
|
|
|
mRebuildAllRestyleHint |= aRestyleHint;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
// 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.
|
2016-07-08 10:08:46 +03:00
|
|
|
nsCOMPtr<nsIPresShell> presShell = PresContext()->GetPresShell();
|
2015-01-14 08:03:12 +03:00
|
|
|
if (!presShell || !presShell->GetRootFrame()) {
|
|
|
|
mDoRebuildAllStyleData = false;
|
2013-07-20 23:14:25 +04:00
|
|
|
return;
|
2015-01-14 08:03:12 +03:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// Make sure that the viewmanager will outlive the presshell
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsViewManager> vm = presShell->GetViewManager();
|
2016-07-18 19:37:11 +03:00
|
|
|
mozilla::Unused << vm; // Not used within this function
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// 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.
|
2017-01-05 10:31:56 +03:00
|
|
|
presShell->GetDocument()->FlushPendingNotifications(FlushType::ContentAndNotify);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
mDoRebuildAllStyleData = true;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
ProcessPendingRestyles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-14 08:03:12 +03:00
|
|
|
RestyleManager::StartRebuildAllStyleData(RestyleTracker& aRestyleTracker)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2015-01-14 08:03:12 +03:00
|
|
|
MOZ_ASSERT(mIsProcessingRestyles);
|
2015-01-14 08:03:12 +03:00
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIFrame* rootFrame = PresContext()->PresShell()->GetRootFrame();
|
2015-01-14 08:03:12 +03:00
|
|
|
if (!rootFrame) {
|
|
|
|
// No need to do anything.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
mInRebuildAllStyleData = true;
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// Tell the style set to get the old rule tree out of the way
|
|
|
|
// so we can recalculate while maintaining rule tree immutability
|
2016-02-24 10:01:10 +03:00
|
|
|
nsresult rv = StyleSet()->BeginReconstruct();
|
2013-07-20 23:14:25 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2015-01-14 08:03:12 +03:00
|
|
|
MOZ_CRASH("unable to rebuild style data");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:11 +03:00
|
|
|
nsRestyleHint restyleHint = mRebuildAllRestyleHint;
|
|
|
|
nsChangeHint changeHint = mRebuildAllExtraHint;
|
|
|
|
mRebuildAllExtraHint = nsChangeHint(0);
|
|
|
|
mRebuildAllRestyleHint = nsRestyleHint(0);
|
|
|
|
|
|
|
|
restyleHint |= eRestyle_ForceDescendants;
|
2014-10-05 03:59:47 +04:00
|
|
|
|
2015-01-14 08:03:11 +03:00
|
|
|
if (!(restyleHint & eRestyle_Subtree) &&
|
|
|
|
(restyleHint & ~(eRestyle_Force | eRestyle_ForceDescendants))) {
|
2014-08-04 00:11:55 +04:00
|
|
|
// 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.
|
2016-07-08 10:08:46 +03:00
|
|
|
Element* root = PresContext()->Document()->GetRootElement();
|
2014-11-13 10:28:52 +03:00
|
|
|
if (root) {
|
|
|
|
// If the root element is gone, dropping the hint on the floor
|
|
|
|
// should be fine.
|
2015-01-14 08:03:11 +03:00
|
|
|
aRestyleTracker.AddPendingRestyle(root, restyleHint, nsChangeHint(0));
|
2014-11-13 10:28:52 +03:00
|
|
|
}
|
2015-01-14 08:03:11 +03:00
|
|
|
restyleHint = nsRestyleHint(0);
|
2014-08-04 00:11:55 +04:00
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
// 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.
|
2013-07-20 23:14:25 +04:00
|
|
|
// Note that we can ignore the return value of ComputeStyleChangeFor
|
2015-01-14 08:03:12 +03:00
|
|
|
// because we never need to reframe the root frame.
|
2013-07-20 23:14:25 +04:00
|
|
|
// XXX Does it matter that we're passing aExtraHint to the real root
|
2014-08-04 00:11:55 +04:00
|
|
|
// frame and not the root node's primary frame? (We could do
|
|
|
|
// roughly what we do for aRestyleHint above.)
|
2015-01-14 08:03:12 +03:00
|
|
|
ComputeAndProcessStyleChange(rootFrame,
|
2015-08-05 15:42:20 +03:00
|
|
|
changeHint, aRestyleTracker, restyleHint,
|
|
|
|
RestyleHintData());
|
2015-01-14 08:03:12 +03:00
|
|
|
}
|
2015-01-14 08:03:12 +03:00
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
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).
|
2016-02-24 10:01:10 +03:00
|
|
|
StyleSet()->EndReconstruct();
|
2015-01-14 08:03:12 +03:00
|
|
|
|
|
|
|
mInRebuildAllStyleData = false;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RestyleManager::ProcessPendingRestyles()
|
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
NS_PRECONDITION(PresContext()->Document(), "No document? Pshaw!");
|
2013-07-20 23:14:25 +04:00
|
|
|
NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
|
|
|
|
"Missing a script blocker!");
|
|
|
|
|
2014-04-24 20:30:12 +04:00
|
|
|
// First do any queued-up frame creation. (We should really
|
|
|
|
// merge this into the rest of the process, though; see bug 827239.)
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->FrameConstructor()->CreateNeededFrames();
|
2014-04-24 20:30:12 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// Process non-animation restyles...
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(!mIsProcessingRestyles,
|
|
|
|
"Nesting calls to ProcessPendingRestyles?");
|
2014-10-03 08:53:23 +04:00
|
|
|
mIsProcessingRestyles = true;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// Before we process any restyles, we need to ensure that style
|
2015-02-17 01:15:02 +03:00
|
|
|
// 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.
|
2015-02-17 01:15:02 +03:00
|
|
|
bool haveNonAnimation =
|
|
|
|
mHavePendingNonAnimationRestyles || mDoRebuildAllStyleData;
|
|
|
|
if (haveNonAnimation) {
|
Bug 1245260 - Ignore redundant calls to RestyleManager::IncrementAnimationGeneration; r=dbaron
While processing restyles and starting transitions, we may trigger
a call to EffectCompositor::UpdateCascadeResults which may, in turn, call
EffectCompositor::RequestRestyle with RestyleType::Layer, which ultimately
results in a call to RestyleManager::IncrementAnimationGeneration().
Typically, nsTransitionManager::StyleContextChanged compares the animation
generation on its collection with that of the restyle manager and uses this
to ignore the restyle that it generates. However, given the sequence of events
above, that check may no longer help since the restyle manager's animation
generation will be out of step. As a result,
nsTransitionManager::StyleContextChanged will fail to ignore a subsequent
and redundant restyle. With certain combinations of content, this can mean that
restyles are posted in such a manner than an infinite cycle of restyles ensues.
This patch causes RestyleManager to ignore calls to IncrementAnimationGeneration
when it is already processing restyles such that the animation generation is
only ever updated once per restyle. This makes the check for a matching
animation generation in nsTransitionManager::StyleContextChanged work as
expected, preventing us from generating needless transitions which can produce
this endless loop.
MozReview-Commit-ID: 9HYDrknKPAI
--HG--
extra : rebase_source : f7d9f251d20805fcb4d0d9be04d4343336e69836
2016-03-16 10:05:10 +03:00
|
|
|
++mAnimationGeneration;
|
2014-07-25 08:35:34 +04:00
|
|
|
UpdateOnlyAnimationStyles();
|
2015-02-17 01:15:02 +03:00
|
|
|
} 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.
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->TransitionManager()->SetInAnimationOnlyStyleUpdate(true);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
ProcessRestyles(mPendingRestyles);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-02-17 01:15:02 +03:00
|
|
|
if (!haveNonAnimation) {
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->TransitionManager()->SetInAnimationOnlyStyleUpdate(false);
|
2015-02-17 01:15:02 +03:00
|
|
|
}
|
|
|
|
|
2014-10-03 08:53:23 +04:00
|
|
|
mIsProcessingRestyles = false;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-02-17 01:15:02 +03:00
|
|
|
NS_ASSERTION(haveNonAnimation || !mHavePendingNonAnimationRestyles,
|
|
|
|
"should not have added restyles");
|
2015-02-17 01:15:02 +03:00
|
|
|
mHavePendingNonAnimationRestyles = false;
|
|
|
|
|
2015-01-14 08:03:11 +03:00
|
|
|
if (mDoRebuildAllStyleData) {
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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.
|
2015-01-14 08:03:12 +03:00
|
|
|
ProcessPendingRestyles();
|
2015-01-14 08:03:13 +03:00
|
|
|
|
|
|
|
NS_ASSERTION(!mDoRebuildAllStyleData,
|
|
|
|
"repeatedly setting mDoRebuildAllStyleData?");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2015-01-14 08:03:13 +03:00
|
|
|
|
|
|
|
MOZ_ASSERT(!mInRebuildAllStyleData,
|
|
|
|
"should have called FinishRebuildAllStyleData");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2013-07-31 04:36:08 +04:00
|
|
|
void
|
2015-01-14 08:03:12 +03:00
|
|
|
RestyleManager::BeginProcessingRestyles(RestyleTracker& aRestyleTracker)
|
2013-07-31 04:36:08 +04:00
|
|
|
{
|
|
|
|
// Make sure to not rebuild quote or counter lists while we're
|
|
|
|
// processing restyles
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->FrameConstructor()->BeginUpdate();
|
2013-07-31 04:36:08 +04:00
|
|
|
|
|
|
|
mInStyleRefresh = true;
|
2015-01-14 08:03:12 +03:00
|
|
|
|
|
|
|
if (ShouldStartRebuildAllFor(aRestyleTracker)) {
|
|
|
|
mDoRebuildAllStyleData = false;
|
|
|
|
StartRebuildAllStyleData(aRestyleTracker);
|
|
|
|
}
|
2013-07-31 04:36:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RestyleManager::EndProcessingRestyles()
|
|
|
|
{
|
|
|
|
FlushOverflowChangedTracker();
|
|
|
|
|
2015-09-15 00:42:00 +03:00
|
|
|
MOZ_ASSERT(mAnimationsWithDestroyedFrame);
|
|
|
|
mAnimationsWithDestroyedFrame->
|
|
|
|
StopAnimationsForElementsWithoutFrames();
|
|
|
|
|
2013-07-31 04:36:08 +04:00
|
|
|
// Set mInStyleRefresh to false now, since the EndUpdate call might
|
|
|
|
// add more restyles.
|
|
|
|
mInStyleRefresh = false;
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
if (mInRebuildAllStyleData) {
|
|
|
|
FinishRebuildAllStyleData();
|
|
|
|
}
|
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->FrameConstructor()->EndUpdate();
|
2013-07-31 04:36:08 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->PresShell()->VerifyStyleTree();
|
2013-07-31 04:36:08 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-07-25 08:35:34 +04:00
|
|
|
void
|
|
|
|
RestyleManager::UpdateOnlyAnimationStyles()
|
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
|
2015-02-17 01:15:02 +03:00
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIDocument* document = PresContext()->Document();
|
2015-07-31 07:14:46 +03:00
|
|
|
nsSMILAnimationController* animationController =
|
|
|
|
document->HasAnimationController() ?
|
|
|
|
document->GetAnimationController() :
|
|
|
|
nullptr;
|
|
|
|
bool doSMIL = animationController &&
|
|
|
|
animationController->MightHavePendingStyleUpdates();
|
2015-02-17 01:15:02 +03:00
|
|
|
|
|
|
|
if (!doCSS && !doSMIL) {
|
2014-07-25 08:35:34 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
nsTransitionManager* transitionManager = PresContext()->TransitionManager();
|
2014-08-07 09:58:44 +04:00
|
|
|
|
|
|
|
transitionManager->SetInAnimationOnlyStyleUpdate(true);
|
|
|
|
|
2014-08-07 09:58:44 +04:00
|
|
|
RestyleTracker tracker(ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE |
|
|
|
|
ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT);
|
|
|
|
tracker.Init(this);
|
|
|
|
|
2015-02-17 01:15:02 +03:00
|
|
|
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).
|
2016-07-08 10:08:46 +03:00
|
|
|
PresContext()->EffectCompositor()->AddStyleUpdatesTo(tracker);
|
2015-02-17 01:15:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (doSMIL) {
|
|
|
|
animationController->AddStyleUpdatesTo(tracker);
|
|
|
|
}
|
2014-08-07 09:58:44 +04:00
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
ProcessRestyles(tracker);
|
2014-08-07 09:58:44 +04:00
|
|
|
|
|
|
|
transitionManager->SetInAnimationOnlyStyleUpdate(false);
|
2014-07-25 08:35:34 +04:00
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
void
|
Bug 960465 patch 17 - Remove separate animation and non-animation phases of restyling. r=birtles
Note that this means that when we start transitions, we post restyles
that are processed during the current restyling operation, rather than
in a later phase. This depends on patch 11, which makes the transition
manager skip style changes that it posts while starting transitions, to
ensure that this doesn't lead to an infinite loop. This also depends on
patch 16, which only consumes restyle data for the primary frame, to
ensure that the animation restyles posted are processed properly. It
also depends on patch 14, which makes us retain data on finished
transitions, to avoid triggering extra transitions on descendants when
both an ancestor and a descendant transition an inherited property, and
the descendant does so faster.
This fixes a known failure in layout/style/test/test_animations.html and
test_animations_omta.html (as visible in the patch). I believe this is
because this patch changes us to compute keyframe values for animations
on top of a style context *with* animation data rather than one without,
which means what we're computing them on top of changes each time. (The
purpose of patch 3 was to avoid this in the case where avoiding it
matters, i.e., implicit 0% and 100% keyframes.)
2015-02-17 01:15:05 +03:00
|
|
|
RestyleManager::PostRestyleEvent(Element* aElement,
|
|
|
|
nsRestyleHint aRestyleHint,
|
2015-08-05 15:42:20 +03:00
|
|
|
nsChangeHint aMinChangeHint,
|
|
|
|
const RestyleHintData* aRestyleHintData)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
if (MOZ_UNLIKELY(IsDisconnected()) ||
|
|
|
|
MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
|
2013-07-20 23:14:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aRestyleHint == 0 && !aMinChangeHint) {
|
|
|
|
// Nothing to do here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-05 15:42:20 +03:00
|
|
|
mPendingRestyles.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint,
|
|
|
|
aRestyleHintData);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-02-17 01:15:02 +03:00
|
|
|
// Set mHavePendingNonAnimationRestyles for any restyle that could
|
2015-02-19 11:22:05 +03:00
|
|
|
// 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) {
|
2015-02-17 01:15:02 +03:00
|
|
|
mHavePendingNonAnimationRestyles = true;
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
PostRestyleEventInternal(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-10-09 01:27:02 +04:00
|
|
|
RestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
|
|
|
nsRestyleHint aRestyleHint)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
|
|
|
|
"Should not reconstruct the root of the frame tree. "
|
|
|
|
"Use ReconstructDocElementHierarchy instead.");
|
2015-08-05 15:42:20 +03:00
|
|
|
MOZ_ASSERT(!(aRestyleHint & eRestyle_SomeDescendants),
|
|
|
|
"PostRebuildAllStyleDataEvent does not handle "
|
|
|
|
"eRestyle_SomeDescendants");
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-01-14 08:03:11 +03:00
|
|
|
mDoRebuildAllStyleData = true;
|
2016-05-23 06:26:03 +03:00
|
|
|
mRebuildAllExtraHint |= aExtraHint;
|
2014-10-09 01:27:02 +04:00
|
|
|
mRebuildAllRestyleHint |= aRestyleHint;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// Get a restyle event posted if necessary
|
|
|
|
PostRestyleEventInternal(false);
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// aContent must be the content for the frame in question, which may be
|
|
|
|
// :before/:after content
|
2015-03-04 08:08:00 +03:00
|
|
|
/* static */ bool
|
2016-10-19 09:16:52 +03:00
|
|
|
RestyleManager::TryInitiatingTransition(nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aOldStyleContext,
|
|
|
|
RefPtr<nsStyleContext>*
|
|
|
|
aNewStyleContext /* inout */)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
if (!aContent || !aContent->IsElement()) {
|
2015-03-04 08:08:00 +03:00
|
|
|
return false;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2015-02-17 01:15:02 +03:00
|
|
|
// Notify the transition manager. If it starts a transition,
|
|
|
|
// it might modify the new style context.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> sc = *aNewStyleContext;
|
2015-02-17 01:15:02 +03:00
|
|
|
aPresContext->TransitionManager()->StyleContextChanged(
|
|
|
|
aContent->AsElement(), aOldStyleContext, aNewStyleContext);
|
2015-03-04 08:08:00 +03:00
|
|
|
return *aNewStyleContext != sc;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2015-02-17 01:15:05 +03:00
|
|
|
static dom::Element*
|
2013-07-20 23:14:25 +04:00
|
|
|
ElementForStyleContext(nsIContent* aParentContent,
|
|
|
|
nsIFrame* aFrame,
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType aPseudoType)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
// We don't expect XUL tree stuff here.
|
2016-02-17 01:07:00 +03:00
|
|
|
NS_PRECONDITION(aPseudoType == CSSPseudoElementType::NotPseudo ||
|
|
|
|
aPseudoType == CSSPseudoElementType::AnonBox ||
|
|
|
|
aPseudoType < CSSPseudoElementType::Count,
|
2013-07-20 23:14:25 +04:00
|
|
|
"Unexpected pseudo");
|
|
|
|
// XXX see the comments about the various element confusion in
|
2013-07-31 04:36:09 +04:00
|
|
|
// ElementRestyler::Restyle.
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
|
2013-07-20 23:14:25 +04:00
|
|
|
return aFrame->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::AnonBox) {
|
2013-07-20 23:14:25 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::firstLetter) {
|
2013-07-20 23:14:25 +04:00
|
|
|
NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame,
|
|
|
|
"firstLetter pseudoTag without a nsFirstLetterFrame");
|
|
|
|
nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame);
|
|
|
|
return block->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::mozColorSwatch) {
|
2013-10-22 19:29:20 +04:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::mozNumberText ||
|
|
|
|
aPseudoType == CSSPseudoElementType::mozNumberWrapper ||
|
|
|
|
aPseudoType == CSSPseudoElementType::mozNumberSpinBox ||
|
|
|
|
aPseudoType == CSSPseudoElementType::mozNumberSpinUp ||
|
|
|
|
aPseudoType == CSSPseudoElementType::mozNumberSpinDown) {
|
2013-09-04 14:30:36 +04:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
2013-11-28 05:22:20 +04:00
|
|
|
if (aParentContent) {
|
|
|
|
return aParentContent->AsElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(aFrame->GetContent()->GetParent(),
|
|
|
|
"should not have got here for the root element");
|
|
|
|
return aFrame->GetContent()->GetParent()->AsElement();
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2015-02-17 01:15:05 +03:00
|
|
|
/**
|
|
|
|
* 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,
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType aPseudoType)
|
2015-02-17 01:15:05 +03:00
|
|
|
{
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType >= CSSPseudoElementType::Count) {
|
2015-02-17 01:15:05 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) ||
|
|
|
|
nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType)) {
|
|
|
|
return aFrame->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
/**
|
|
|
|
* FIXME: Temporary. Should merge with following function.
|
|
|
|
*/
|
2013-07-20 23:14:25 +04:00
|
|
|
static nsIFrame*
|
|
|
|
GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
// Account for {ib} splits when looking for "prevContinuation". In
|
2014-02-07 05:45:33 +04:00
|
|
|
// 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.
|
2016-06-21 23:17:11 +03:00
|
|
|
nsIFrame* prevContinuation = aFrame->GetPrevContinuation();
|
2014-02-07 05:45:28 +04:00
|
|
|
if (!prevContinuation &&
|
|
|
|
(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
|
2013-07-20 23:14:25 +04:00
|
|
|
// We're the first continuation, so we can just get the frame
|
|
|
|
// property directly
|
2016-06-21 23:17:11 +03:00
|
|
|
prevContinuation =
|
|
|
|
aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling());
|
2013-07-20 23:14:25 +04:00
|
|
|
if (prevContinuation) {
|
2016-06-21 23:17:11 +03:00
|
|
|
prevContinuation =
|
|
|
|
prevContinuation->Properties().Get(nsIFrame::IBSplitPrevSibling());
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
2013-09-25 23:28:07 +04:00
|
|
|
|
|
|
|
NS_ASSERTION(!prevContinuation ||
|
|
|
|
prevContinuation->GetContent() == aFrame->GetContent(),
|
|
|
|
"unexpected content mismatch");
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
return prevContinuation;
|
|
|
|
}
|
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
/**
|
2014-02-07 05:45:33 +04:00
|
|
|
* Get the previous continuation or similar ib-split sibling (assuming
|
2013-09-25 23:28:07 +04:00
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
nsresult
|
|
|
|
RestyleManager::ReparentStyleContext(nsIFrame* aFrame)
|
|
|
|
{
|
2016-01-28 02:11:00 +03:00
|
|
|
nsIAtom* frameType = aFrame->GetType();
|
|
|
|
if (frameType == nsGkAtoms::placeholderFrame) {
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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()));
|
2016-01-28 02:11:00 +03:00
|
|
|
} 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;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
2013-07-31 04:36:11 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> newContext;
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIFrame* providerFrame;
|
|
|
|
nsStyleContext* newParentContext = aFrame->GetParentStyleContext(&providerFrame);
|
2013-07-31 04:36:11 +04:00
|
|
|
bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
|
|
|
|
nsIFrame* providerChild = nullptr;
|
|
|
|
if (isChild) {
|
|
|
|
ReparentStyleContext(providerFrame);
|
2014-11-20 21:24:10 +03:00
|
|
|
// Get the style context again after ReparentStyleContext() which might have
|
|
|
|
// changed it.
|
2013-07-31 04:36:11 +04:00
|
|
|
newParentContext = providerFrame->StyleContext();
|
|
|
|
providerChild = providerFrame;
|
|
|
|
}
|
2014-11-20 21:24:10 +03:00
|
|
|
NS_ASSERTION(newParentContext, "Reparenting something that has no usable"
|
|
|
|
" parent? Shouldn't happen!");
|
2013-07-31 04:36:11 +04:00
|
|
|
// 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.
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2013-07-31 04:36:11 +04:00
|
|
|
{
|
|
|
|
// 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.)
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIFrame* nextContinuation = aFrame->GetNextContinuation();
|
2013-07-31 04:36:11 +04:00
|
|
|
if (nextContinuation) {
|
2016-07-08 10:08:46 +03:00
|
|
|
nsStyleContext* nextContinuationContext =
|
2013-07-31 04:36:11 +04:00
|
|
|
nextContinuation->StyleContext();
|
|
|
|
NS_ASSERTION(oldContext == nextContinuationContext ||
|
|
|
|
oldContext->GetPseudo() !=
|
|
|
|
nextContinuationContext->GetPseudo() ||
|
|
|
|
oldContext->GetParent() !=
|
|
|
|
nextContinuationContext->GetParent(),
|
|
|
|
"continuations should have the same style context");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
#endif
|
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIFrame* prevContinuation =
|
2013-07-31 04:36:11 +04:00
|
|
|
GetPrevContinuationWithPossiblySameStyle(aFrame);
|
2016-07-08 10:08:46 +03:00
|
|
|
nsStyleContext* prevContinuationContext;
|
2013-07-31 04:36:11 +04:00
|
|
|
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());
|
2016-02-24 10:01:10 +03:00
|
|
|
newContext = StyleSet()->
|
2015-02-17 01:15:05 +03:00
|
|
|
ReparentStyleContext(oldContext, newParentContext, element);
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2016-10-19 09:16:52 +03:00
|
|
|
// nsTransitionManager::ConsiderInitiatingTransition.
|
2013-07-20 23:14:25 +04:00
|
|
|
#if 0
|
2013-07-31 04:36:11 +04:00
|
|
|
if (!copyFromContinuation) {
|
2016-10-19 09:16:52 +03:00
|
|
|
TryInitiatingTransition(mPresContext, aFrame->GetContent(),
|
|
|
|
oldContext, &newContext);
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
#endif
|
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
// Make sure to call CalcStyleDifference so that the new context ends
|
|
|
|
// up resolving all the structs the old context resolved.
|
2013-09-25 23:28:08 +04:00
|
|
|
if (!copyFromContinuation) {
|
2014-09-05 07:48:44 +04:00
|
|
|
uint32_t equalStructs;
|
2015-08-28 23:13:47 +03:00
|
|
|
uint32_t samePointerStructs;
|
2013-09-25 23:28:08 +04:00
|
|
|
DebugOnly<nsChangeHint> styleChange =
|
2014-09-05 07:48:44 +04:00
|
|
|
oldContext->CalcStyleDifference(newContext, nsChangeHint(0),
|
2015-08-28 23:13:47 +03:00
|
|
|
&equalStructs,
|
|
|
|
&samePointerStructs);
|
2013-09-25 23:28:08 +04:00
|
|
|
// 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!");
|
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
|
|
|
|
aFrame->SetStyleContext(newContext);
|
|
|
|
|
|
|
|
nsIFrame::ChildListIterator lists(aFrame);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
2015-09-22 21:21:44 +03:00
|
|
|
for (nsIFrame* child : lists.CurrentList()) {
|
2013-07-31 04:36:11 +04:00
|
|
|
// only do frames that are in flow
|
|
|
|
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
|
|
|
|
child != providerChild) {
|
2013-07-20 23:14:25 +04:00
|
|
|
#ifdef DEBUG
|
2013-07-31 04:36:11 +04:00
|
|
|
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?");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
#endif
|
|
|
|
ReparentStyleContext(child);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
// 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.
|
2014-02-07 05:45:28 +04:00
|
|
|
if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
|
2013-07-31 04:36:11 +04:00
|
|
|
!aFrame->GetPrevContinuation()) {
|
2016-06-21 23:17:11 +03:00
|
|
|
nsIFrame* sib =
|
|
|
|
aFrame->Properties().Get(nsIFrame::IBSplitSibling());
|
2013-07-31 04:36:11 +04:00
|
|
|
if (sib) {
|
|
|
|
ReparentStyleContext(sib);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
// do additional contexts
|
2013-07-31 04:36:11 +04:00
|
|
|
int32_t contextIndex = 0;
|
|
|
|
for (nsStyleContext* oldExtraContext;
|
|
|
|
(oldExtraContext = aFrame->GetAdditionalStyleContext(contextIndex));
|
|
|
|
++contextIndex) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> newExtraContext;
|
2016-02-24 10:01:10 +03:00
|
|
|
newExtraContext = StyleSet()->
|
2013-07-31 04:36:12 +04:00
|
|
|
ReparentStyleContext(oldExtraContext,
|
2015-02-17 01:15:05 +03:00
|
|
|
newContext, nullptr);
|
2013-07-31 04:36:12 +04:00
|
|
|
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.
|
2014-09-05 07:48:44 +04:00
|
|
|
uint32_t equalStructs;
|
2015-08-28 23:13:47 +03:00
|
|
|
uint32_t samePointerStructs;
|
2013-09-25 23:28:08 +04:00
|
|
|
DebugOnly<nsChangeHint> styleChange =
|
2013-07-31 04:36:12 +04:00
|
|
|
oldExtraContext->CalcStyleDifference(newExtraContext,
|
2014-09-05 07:48:44 +04:00
|
|
|
nsChangeHint(0),
|
2015-08-28 23:13:47 +03:00
|
|
|
&equalStructs,
|
|
|
|
&samePointerStructs);
|
2013-07-31 04:36:12 +04:00
|
|
|
// 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!");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
|
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
#ifdef DEBUG
|
2016-08-01 23:31:57 +03:00
|
|
|
DebugVerifyStyleTree(aFrame);
|
2013-07-20 23:14:25 +04:00
|
|
|
#endif
|
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
|
2013-07-31 04:36:09 +04:00
|
|
|
nsIFrame* aFrame,
|
2013-07-31 04:36:10 +04:00
|
|
|
nsStyleChangeList* aChangeList,
|
2013-07-31 04:36:10 +04:00
|
|
|
nsChangeHint aHintsHandledByAncestors,
|
2013-07-31 04:36:10 +04:00
|
|
|
RestyleTracker& aRestyleTracker,
|
2015-08-05 15:42:20 +03:00
|
|
|
nsTArray<nsCSSSelector*>&
|
|
|
|
aSelectorsForDescendants,
|
2013-07-31 04:36:10 +04:00
|
|
|
TreeMatchContext& aTreeMatchContext,
|
2013-07-31 04:36:10 +04:00
|
|
|
nsTArray<nsIContent*>&
|
2015-02-18 01:28:53 +03:00
|
|
|
aVisibleKidsOfHiddenElement,
|
|
|
|
nsTArray<ContextToClear>& aContextsToClear,
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>>&
|
2015-02-18 01:28:53 +03:00
|
|
|
aSwappedStructOwners)
|
2013-07-31 04:36:09 +04:00
|
|
|
: mPresContext(aPresContext)
|
2013-07-31 04:36:09 +04:00
|
|
|
, mFrame(aFrame)
|
2013-07-31 04:36:09 +04:00
|
|
|
, 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)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mChangeList(aChangeList)
|
2016-05-23 06:26:03 +03:00
|
|
|
, mHintsHandled(aHintsHandledByAncestors &
|
|
|
|
~NS_HintsNotHandledForDescendantsIn(aHintsHandledByAncestors))
|
2013-07-31 04:36:10 +04:00
|
|
|
, mParentFrameHintsNotHandledForDescendants(nsChangeHint(0))
|
|
|
|
, mHintsNotHandledForDescendants(nsChangeHint(0))
|
2013-07-31 04:36:10 +04:00
|
|
|
, mRestyleTracker(aRestyleTracker)
|
2015-08-05 15:42:20 +03:00
|
|
|
, mSelectorsForDescendants(aSelectorsForDescendants)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mTreeMatchContext(aTreeMatchContext)
|
2013-07-31 04:36:11 +04:00
|
|
|
, mResolvedChild(nullptr)
|
2015-02-18 01:28:53 +03:00
|
|
|
, mContextsToClear(aContextsToClear)
|
|
|
|
, mSwappedStructOwners(aSwappedStructOwners)
|
2015-08-28 23:13:47 +03:00
|
|
|
, mIsRootOfRestyle(true)
|
2013-08-01 06:15:19 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:10 +04:00
|
|
|
, mDesiredA11yNotifications(eSendAllNotifications)
|
|
|
|
, mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
|
|
|
|
, mOurA11yNotification(eDontNotify)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
|
2013-08-01 06:15:19 +04:00
|
|
|
#endif
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
, mLoggingDepth(aRestyleTracker.LoggingDepth() + 1)
|
|
|
|
#endif
|
2013-07-31 04:36:09 +04:00
|
|
|
{
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT_IF(mContent, !mContent->IsStyledByServo());
|
2013-07-31 04:36:09 +04:00
|
|
|
}
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler,
|
2013-07-31 04:36:10 +04:00
|
|
|
nsIFrame* aFrame,
|
|
|
|
uint32_t aConstructorFlags)
|
2013-07-31 04:36:09 +04:00
|
|
|
: mPresContext(aParentRestyler.mPresContext)
|
2013-07-31 04:36:09 +04:00
|
|
|
, mFrame(aFrame)
|
2013-07-31 04:36:09 +04:00
|
|
|
, 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)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mChangeList(aParentRestyler.mChangeList)
|
2016-05-23 06:26:03 +03:00
|
|
|
, mHintsHandled(aParentRestyler.mHintsHandled &
|
|
|
|
~NS_HintsNotHandledForDescendantsIn(aParentRestyler.mHintsHandled))
|
2013-07-31 04:36:10 +04:00
|
|
|
, mParentFrameHintsNotHandledForDescendants(
|
|
|
|
aParentRestyler.mHintsNotHandledForDescendants)
|
|
|
|
, mHintsNotHandledForDescendants(nsChangeHint(0))
|
2013-07-31 04:36:10 +04:00
|
|
|
, mRestyleTracker(aParentRestyler.mRestyleTracker)
|
2015-08-05 15:42:20 +03:00
|
|
|
, mSelectorsForDescendants(aParentRestyler.mSelectorsForDescendants)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mTreeMatchContext(aParentRestyler.mTreeMatchContext)
|
2013-07-31 04:36:11 +04:00
|
|
|
, mResolvedChild(nullptr)
|
2015-02-18 01:28:53 +03:00
|
|
|
, mContextsToClear(aParentRestyler.mContextsToClear)
|
|
|
|
, mSwappedStructOwners(aParentRestyler.mSwappedStructOwners)
|
2015-08-28 23:13:47 +03:00
|
|
|
, mIsRootOfRestyle(false)
|
2013-08-01 06:15:19 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:10 +04:00
|
|
|
, mDesiredA11yNotifications(aParentRestyler.mKidsDesiredA11yNotifications)
|
|
|
|
, mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
|
|
|
|
, mOurA11yNotification(eDontNotify)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
|
2013-08-01 06:15:19 +04:00
|
|
|
#endif
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
, mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
|
|
|
|
#endif
|
2013-07-31 04:36:09 +04:00
|
|
|
{
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT_IF(mContent, !mContent->IsStyledByServo());
|
2013-07-31 04:36:10 +04:00
|
|
|
if (aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) {
|
2013-09-25 23:28:07 +04:00
|
|
|
// 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.
|
2016-05-23 06:26:03 +03:00
|
|
|
mHintsHandled &= ~nsChangeHint_AllReflowHints;
|
2013-07-31 04:36:10 +04:00
|
|
|
}
|
2013-07-31 04:36:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ElementRestyler::ElementRestyler(ParentContextFromChildFrame,
|
2013-07-31 04:36:09 +04:00
|
|
|
const ElementRestyler& aParentRestyler,
|
|
|
|
nsIFrame* aFrame)
|
2013-07-31 04:36:09 +04:00
|
|
|
: mPresContext(aParentRestyler.mPresContext)
|
2013-07-31 04:36:09 +04:00
|
|
|
, mFrame(aFrame)
|
2013-07-31 04:36:09 +04:00
|
|
|
, 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)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mChangeList(aParentRestyler.mChangeList)
|
2016-05-23 06:26:03 +03:00
|
|
|
, mHintsHandled(aParentRestyler.mHintsHandled &
|
|
|
|
~NS_HintsNotHandledForDescendantsIn(aParentRestyler.mHintsHandled))
|
2013-07-31 04:36:10 +04:00
|
|
|
, mParentFrameHintsNotHandledForDescendants(
|
|
|
|
// assume the worst
|
|
|
|
nsChangeHint_Hints_NotHandledForDescendants)
|
|
|
|
, mHintsNotHandledForDescendants(nsChangeHint(0))
|
2013-07-31 04:36:10 +04:00
|
|
|
, mRestyleTracker(aParentRestyler.mRestyleTracker)
|
2015-08-05 15:42:20 +03:00
|
|
|
, mSelectorsForDescendants(aParentRestyler.mSelectorsForDescendants)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mTreeMatchContext(aParentRestyler.mTreeMatchContext)
|
2013-07-31 04:36:11 +04:00
|
|
|
, mResolvedChild(nullptr)
|
2015-02-18 01:28:53 +03:00
|
|
|
, mContextsToClear(aParentRestyler.mContextsToClear)
|
|
|
|
, mSwappedStructOwners(aParentRestyler.mSwappedStructOwners)
|
2015-08-28 23:13:47 +03:00
|
|
|
, mIsRootOfRestyle(false)
|
2013-08-01 06:15:19 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:10 +04:00
|
|
|
, mDesiredA11yNotifications(aParentRestyler.mDesiredA11yNotifications)
|
|
|
|
, mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
|
|
|
|
, mOurA11yNotification(eDontNotify)
|
2013-07-31 04:36:10 +04:00
|
|
|
, mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
|
2013-08-01 06:15:19 +04:00
|
|
|
#endif
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
, mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
|
|
|
|
#endif
|
2013-07-31 04:36:09 +04:00
|
|
|
{
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT_IF(mContent, !mContent->IsStyledByServo());
|
2013-07-31 04:36:09 +04:00
|
|
|
}
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleChangeList* aChangeList,
|
|
|
|
nsChangeHint aHintsHandledByAncestors,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
2015-08-05 15:42:20 +03:00
|
|
|
nsTArray<nsCSSSelector*>& aSelectorsForDescendants,
|
2014-11-20 21:24:10 +03:00
|
|
|
TreeMatchContext& aTreeMatchContext,
|
|
|
|
nsTArray<nsIContent*>&
|
2015-02-18 01:28:53 +03:00
|
|
|
aVisibleKidsOfHiddenElement,
|
|
|
|
nsTArray<ContextToClear>& aContextsToClear,
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>>&
|
2015-02-18 01:28:53 +03:00
|
|
|
aSwappedStructOwners)
|
2014-11-20 21:24:10 +03:00
|
|
|
: mPresContext(aPresContext)
|
|
|
|
, mFrame(nullptr)
|
|
|
|
, mParentContent(nullptr)
|
|
|
|
, mContent(aContent)
|
|
|
|
, mChangeList(aChangeList)
|
2016-05-23 06:26:03 +03:00
|
|
|
, mHintsHandled(aHintsHandledByAncestors &
|
|
|
|
~NS_HintsNotHandledForDescendantsIn(aHintsHandledByAncestors))
|
2014-11-20 21:24:10 +03:00
|
|
|
, mParentFrameHintsNotHandledForDescendants(nsChangeHint(0))
|
|
|
|
, mHintsNotHandledForDescendants(nsChangeHint(0))
|
|
|
|
, mRestyleTracker(aRestyleTracker)
|
2015-08-05 15:42:20 +03:00
|
|
|
, mSelectorsForDescendants(aSelectorsForDescendants)
|
2014-11-20 21:24:10 +03:00
|
|
|
, mTreeMatchContext(aTreeMatchContext)
|
|
|
|
, mResolvedChild(nullptr)
|
2015-02-18 01:28:53 +03:00
|
|
|
, mContextsToClear(aContextsToClear)
|
|
|
|
, mSwappedStructOwners(aSwappedStructOwners)
|
2015-08-28 23:13:47 +03:00
|
|
|
, mIsRootOfRestyle(true)
|
2014-11-20 21:24:10 +03:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
, mDesiredA11yNotifications(eSendAllNotifications)
|
|
|
|
, mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
|
|
|
|
, mOurA11yNotification(eDontNotify)
|
|
|
|
, mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
void
|
|
|
|
ElementRestyler::AddLayerChangesForAnimation()
|
|
|
|
{
|
|
|
|
uint64_t frameGeneration =
|
2016-01-06 05:04:05 +03:00
|
|
|
RestyleManager::GetAnimationGenerationForFrame(mFrame);
|
2014-11-17 07:46:00 +03:00
|
|
|
|
|
|
|
nsChangeHint hint = nsChangeHint(0);
|
2015-09-03 23:59:00 +03:00
|
|
|
for (const LayerAnimationInfo::Record& layerInfo :
|
|
|
|
LayerAnimationInfo::sRecords) {
|
2014-11-17 07:46:00 +03:00
|
|
|
Layer* layer =
|
2015-09-03 23:59:00 +03:00
|
|
|
FrameLayerBuilder::GetDedicatedLayer(mFrame, layerInfo.mLayerType);
|
2016-12-22 02:47:14 +03:00
|
|
|
if (layer && frameGeneration != layer->GetAnimationGeneration()) {
|
2014-11-17 07:46:00 +03:00
|
|
|
// 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
|
2015-08-04 06:18:00 +03:00
|
|
|
// (nsChangeHint_UpdateContainingBlock) when we compare style contexts
|
2014-11-17 07:46:00 +03:00
|
|
|
// 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).
|
2015-09-03 23:59:00 +03:00
|
|
|
if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
|
2015-03-20 07:12:17 +03:00
|
|
|
!mFrame->StyleDisplay()->HasTransformStyle()) {
|
2014-11-17 07:46:00 +03:00
|
|
|
continue;
|
|
|
|
}
|
2016-05-23 06:26:03 +03:00
|
|
|
hint |= layerInfo.mChangeHint;
|
2014-11-17 07:46:00 +03:00
|
|
|
}
|
Bug 1279403 - Part 1: Force to apply corresponding change hint if there is no corresponding layer to generate display item even if animation's segment is transform:none or 100% opacity. r=birtles
To create a stacking context for animations on transform:none segment,
we need to set NS_FRAME_MAY_BE_TRANSFORMED. The fix is comming in part 2.
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. For example:
div.animate([{ opacity: 1, width: '100px' }, { opacity: 0, width: '200px' }], 1000);
This animation causes restyles in every ticks without this patch, this patch
does not affect such animations at all. The only animations which will be
affected by this patch are animations which has opacity/transform but
did not have those properies. e.g, setting transform by setKeyframes or
changing target element from other target which prevents running on the
compositor, etc.
MozReview-Commit-ID: 78fYqyX8uDX
--HG--
extra : rebase_source : c4a6ef244f26f3d808fd2c6a5f80c1a15478ae31
2016-07-11 02:27:02 +03:00
|
|
|
|
|
|
|
// 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 &&
|
2016-10-13 10:54:25 +03:00
|
|
|
nsLayoutUtils::HasEffectiveAnimation(mFrame, layerInfo.mProperty)) {
|
Bug 1279403 - Part 1: Force to apply corresponding change hint if there is no corresponding layer to generate display item even if animation's segment is transform:none or 100% opacity. r=birtles
To create a stacking context for animations on transform:none segment,
we need to set NS_FRAME_MAY_BE_TRANSFORMED. The fix is comming in part 2.
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. For example:
div.animate([{ opacity: 1, width: '100px' }, { opacity: 0, width: '200px' }], 1000);
This animation causes restyles in every ticks without this patch, this patch
does not affect such animations at all. The only animations which will be
affected by this patch are animations which has opacity/transform but
did not have those properies. e.g, setting transform by setKeyframes or
changing target element from other target which prevents running on the
compositor, etc.
MozReview-Commit-ID: 78fYqyX8uDX
--HG--
extra : rebase_source : c4a6ef244f26f3d808fd2c6a5f80c1a15478ae31
2016-07-11 02:27:02 +03:00
|
|
|
hint |= layerInfo.mChangeHint;
|
|
|
|
}
|
2014-11-17 07:46:00 +03:00
|
|
|
}
|
|
|
|
if (hint) {
|
|
|
|
mChangeList->AppendChange(mFrame, mContent, hint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
void
|
|
|
|
ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
|
|
|
|
nsStyleContext* aNewContext,
|
2014-09-05 07:48:45 +04:00
|
|
|
nsChangeHint aChangeToAssume,
|
2015-08-28 23:13:47 +03:00
|
|
|
uint32_t* aEqualStructs,
|
|
|
|
uint32_t* aSamePointerStructs)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2014-09-05 07:48:45 +04:00
|
|
|
static_assert(nsStyleStructID_Length <= 32,
|
|
|
|
"aEqualStructs is not big enough");
|
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
// 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");
|
|
|
|
|
2014-09-05 07:48:44 +04:00
|
|
|
nsChangeHint ourChange =
|
|
|
|
aOldContext->CalcStyleDifference(aNewContext,
|
|
|
|
mParentFrameHintsNotHandledForDescendants,
|
2015-08-28 23:13:47 +03:00
|
|
|
aEqualStructs,
|
|
|
|
aSamePointerStructs);
|
2013-07-20 23:14:25 +04:00
|
|
|
NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) ||
|
|
|
|
(ourChange & nsChangeHint_NeedReflow),
|
|
|
|
"Reflow hint bits set without actually asking for a reflow");
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("CaptureChange, ourChange = %s, aChangeToAssume = %s",
|
|
|
|
RestyleManager::ChangeHintToString(ourChange).get(),
|
|
|
|
RestyleManager::ChangeHintToString(aChangeToAssume).get());
|
|
|
|
LOG_RESTYLE_INDENT();
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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) &&
|
2013-07-31 04:36:09 +04:00
|
|
|
mContent && !mContent->IsElement()) {
|
2016-05-23 06:26:03 +03:00
|
|
|
ourChange &= ~nsChangeHint_UpdateEffects;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2016-05-23 06:26:03 +03:00
|
|
|
ourChange |= aChangeToAssume;
|
|
|
|
if (!NS_IsHintSubset(ourChange, mHintsHandled)) {
|
|
|
|
mHintsHandled |= ourChange;
|
2013-07-31 04:36:09 +04:00
|
|
|
if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("appending change %s",
|
|
|
|
RestyleManager::ChangeHintToString(ourChange).get());
|
2013-09-25 23:28:08 +04:00
|
|
|
mChangeList->AppendChange(mFrame, mContent, ourChange);
|
2014-09-25 09:45:36 +04:00
|
|
|
} else {
|
|
|
|
LOG_RESTYLE("change has already been handled");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
2016-05-23 06:26:03 +03:00
|
|
|
mHintsNotHandledForDescendants |=
|
|
|
|
NS_HintsNotHandledForDescendantsIn(ourChange);
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("mHintsNotHandledForDescendants = %s",
|
|
|
|
RestyleManager::ChangeHintToString(mHintsNotHandledForDescendants).get());
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2016-03-28 15:34:26 +03:00
|
|
|
class MOZ_RAII AutoSelectorArrayTruncater final
|
2015-08-05 15:42:20 +03:00
|
|
|
{
|
|
|
|
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.
|
|
|
|
*
|
2015-09-04 03:00:14 +03:00
|
|
|
* 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.
|
2015-08-05 15:42:20 +03:00
|
|
|
*
|
|
|
|
* This ensures that we don't visit descendant elements and check them
|
|
|
|
* against mSelectorsForDescendants more than once.
|
|
|
|
*/
|
|
|
|
void
|
2015-09-04 03:00:14 +03:00
|
|
|
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());
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT(!aFrame->GetContent()->IsStyledByServo());
|
2015-09-04 03:00:14 +03:00
|
|
|
|
|
|
|
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());
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT(!aFrame->GetContent()->IsStyledByServo());
|
2015-09-04 03:00:14 +03:00
|
|
|
|
|
|
|
if (aFrame->GetContent()->HasFlag(mRestyleTracker.RootBit())) {
|
|
|
|
aRestyleRoot = aFrame->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (nsIFrame* f = aFrame; f;
|
2016-08-01 23:40:27 +03:00
|
|
|
f = RestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
|
2015-09-04 03:00:14 +03:00
|
|
|
nsIFrame::ChildListIterator lists(f);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
2015-09-22 21:21:44 +03:00
|
|
|
for (nsIFrame* child : lists.CurrentList()) {
|
2015-09-04 03:00:14 +03:00
|
|
|
// 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,
|
2015-08-05 15:42:21 +03:00
|
|
|
Element* aRestyleRoot)
|
2015-09-04 03:00:14 +03:00
|
|
|
{
|
|
|
|
nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
|
|
|
|
UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
|
|
|
|
ConditionallyRestyleUndisplayedNodes(nodes, aParent,
|
2016-09-03 21:46:58 +03:00
|
|
|
StyleDisplay::None, aRestyleRoot);
|
2015-09-04 03:00:14 +03:00
|
|
|
nodes = fc->GetAllDisplayContentsIn(aParent);
|
|
|
|
ConditionallyRestyleUndisplayedNodes(nodes, aParent,
|
2016-08-28 05:31:50 +03:00
|
|
|
StyleDisplay::Contents, aRestyleRoot);
|
2015-09-04 03:00:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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,
|
2016-08-28 05:31:50 +03:00
|
|
|
const StyleDisplay aDisplay,
|
2015-09-04 03:00:14 +03:00
|
|
|
Element* aRestyleRoot)
|
|
|
|
{
|
2016-09-03 21:46:58 +03:00
|
|
|
MOZ_ASSERT(aDisplay == StyleDisplay::None ||
|
2016-08-28 05:31:50 +03:00
|
|
|
aDisplay == StyleDisplay::Contents);
|
2015-09-04 03:00:14 +03:00
|
|
|
if (!aUndisplayed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aUndisplayedParent &&
|
|
|
|
aUndisplayedParent->IsElement() &&
|
|
|
|
aUndisplayedParent->HasFlag(mRestyleTracker.RootBit())) {
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT(!aUndisplayedParent->IsStyledByServo());
|
2015-09-04 03:00:14 +03:00
|
|
|
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)) {
|
2016-09-03 21:46:58 +03:00
|
|
|
if (aDisplay == StyleDisplay::None) {
|
2015-09-04 03:00:14 +03:00
|
|
|
ConditionallyRestyleContentDescendants(element, aRestyleRoot);
|
2016-08-28 05:31:50 +03:00
|
|
|
} else { // StyleDisplay::Contents
|
2015-09-04 03:00:14 +03:00
|
|
|
DoConditionallyRestyleUndisplayedDescendants(element, aRestyleRoot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ElementRestyler::ConditionallyRestyleContentDescendants(Element* aElement,
|
|
|
|
Element* aRestyleRoot)
|
|
|
|
{
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT(!aElement->IsStyledByServo());
|
2015-09-04 03:00:14 +03:00
|
|
|
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)
|
2015-08-05 15:42:20 +03:00
|
|
|
{
|
2016-07-08 10:02:56 +03:00
|
|
|
MOZ_ASSERT(!aElement->IsStyledByServo());
|
2015-08-05 15:42:21 +03:00
|
|
|
LOG_RESTYLE("considering element %s for eRestyle_SomeDescendants",
|
|
|
|
ElementTagToString(aElement).get());
|
|
|
|
LOG_RESTYLE_INDENT();
|
|
|
|
|
2015-08-05 15:42:21 +03:00
|
|
|
if (aElement->HasFlag(mRestyleTracker.RootBit())) {
|
|
|
|
aRestyleRoot = aElement;
|
|
|
|
}
|
|
|
|
|
2015-08-05 15:42:20 +03:00
|
|
|
if (mRestyleTracker.HasRestyleData(aElement)) {
|
|
|
|
nsRestyleHint rshint = eRestyle_SomeDescendants;
|
|
|
|
if (SelectorMatchesForRestyle(aElement)) {
|
2015-08-05 15:42:21 +03:00
|
|
|
LOG_RESTYLE("element has existing restyle data and matches a selector");
|
2015-08-05 15:42:20 +03:00
|
|
|
rshint |= eRestyle_Self;
|
2015-08-05 15:42:21 +03:00
|
|
|
} else {
|
|
|
|
LOG_RESTYLE("element has existing restyle data but doesn't match selectors");
|
2015-08-05 15:42:20 +03:00
|
|
|
}
|
|
|
|
RestyleHintData data;
|
|
|
|
data.mSelectorsForDescendants = mSelectorsForDescendants;
|
2015-08-05 15:42:21 +03:00
|
|
|
mRestyleTracker.AddPendingRestyle(aElement, rshint, nsChangeHint(0), &data,
|
|
|
|
Some(aRestyleRoot));
|
2015-09-04 03:00:14 +03:00
|
|
|
return true;
|
2015-08-05 15:42:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (SelectorMatchesForRestyle(aElement)) {
|
2015-08-05 15:42:21 +03:00
|
|
|
LOG_RESTYLE("element has no restyle data but matches a selector");
|
2015-08-05 15:42:20 +03:00
|
|
|
RestyleHintData data;
|
|
|
|
data.mSelectorsForDescendants = mSelectorsForDescendants;
|
|
|
|
mRestyleTracker.AddPendingRestyle(aElement,
|
|
|
|
eRestyle_Self | eRestyle_SomeDescendants,
|
2015-08-05 15:42:21 +03:00
|
|
|
nsChangeHint(0), &data,
|
|
|
|
Some(aRestyleRoot));
|
2015-09-04 03:00:14 +03:00
|
|
|
return true;
|
2015-08-28 23:13:47 +03:00
|
|
|
}
|
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
return false;
|
2015-08-28 23:13:47 +03:00
|
|
|
}
|
|
|
|
|
2015-08-28 23:13:47 +03:00
|
|
|
bool
|
2015-09-04 03:00:14 +03:00
|
|
|
ElementRestyler::MustCheckUndisplayedContent(nsIFrame* aFrame,
|
|
|
|
nsIContent*& aUndisplayedParent)
|
2015-08-28 23:13:47 +03:00
|
|
|
{
|
|
|
|
// When the root element is display:none, we still construct *some*
|
|
|
|
// frames that have the root element as their mContent, down to the
|
|
|
|
// DocElementContainingBlock.
|
2015-09-04 03:00:14 +03:00
|
|
|
if (aFrame->StyleContext()->GetPseudo()) {
|
2015-08-28 23:13:47 +03:00
|
|
|
aUndisplayedParent = nullptr;
|
2015-09-04 03:00:14 +03:00
|
|
|
return aFrame == mPresContext->FrameConstructor()->
|
2015-08-28 23:13:47 +03:00
|
|
|
GetDocElementContainingBlock();
|
|
|
|
}
|
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
aUndisplayedParent = aFrame->GetContent();
|
2015-08-28 23:13:47 +03:00
|
|
|
return !!aUndisplayedParent;
|
|
|
|
}
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
/**
|
|
|
|
* 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()) {
|
2015-09-22 21:21:44 +03:00
|
|
|
for (nsIFrame* child : lists.CurrentList()) {
|
2015-08-28 23:13:48 +03:00
|
|
|
// 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();
|
2016-04-22 02:18:41 +03:00
|
|
|
if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
|
2015-08-28 23:13:48 +03:00
|
|
|
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;
|
2015-09-04 03:00:14 +03:00
|
|
|
if (MustCheckUndisplayedContent(mFrame, undisplayedParent)) {
|
2015-08-28 23:13:48 +03:00
|
|
|
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;
|
2016-08-01 23:40:27 +03:00
|
|
|
f = RestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
|
2015-08-28 23:13:48 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
/**
|
2013-09-25 23:28:07 +04:00
|
|
|
* Recompute style for mFrame (which should not have a prev continuation
|
|
|
|
* with the same style), all of its next continuations with the same
|
2014-02-07 05:45:33 +04:00
|
|
|
* style, and all ib-split siblings of the same type (either block or
|
2013-09-25 23:28:07 +04:00
|
|
|
* inline, skipping the intermediates of the other type) and accumulate
|
|
|
|
* changes into mChangeList given that mHintsHandled is already accumulated
|
|
|
|
* for an ancestor.
|
2013-07-31 04:36:09 +04:00
|
|
|
* mParentContent is the content node used to resolve the parent style
|
2013-07-20 23:14:25 +04:00
|
|
|
* 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).
|
|
|
|
*/
|
2013-07-31 04:36:09 +04:00
|
|
|
void
|
2013-07-31 04:36:10 +04:00
|
|
|
ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
|
|
|
// 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
|
2013-07-31 04:36:09 +04:00
|
|
|
// |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
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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.
|
2013-07-31 04:36:09 +04:00
|
|
|
NS_ASSERTION(mFrame->GetContent() || !mParentContent ||
|
|
|
|
!mParentContent->GetParent(),
|
2013-07-20 23:14:25 +04:00
|
|
|
"frame must have content (unless at the top of the tree)");
|
2016-05-09 21:26:35 +03:00
|
|
|
MOZ_ASSERT(mPresContext == mFrame->PresContext(), "pres contexts match");
|
2013-07-31 04:36:11 +04:00
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
NS_ASSERTION(!GetPrevContinuationWithSameStyle(mFrame),
|
|
|
|
"should not be trying to restyle this frame separately");
|
|
|
|
|
2014-06-19 04:07:26 +04:00
|
|
|
MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
|
|
|
|
"eRestyle_LaterSiblings must not be part of aRestyleHint");
|
|
|
|
|
2016-05-09 21:26:35 +03:00
|
|
|
mPresContext->RestyledElement();
|
|
|
|
|
|
|
|
AutoDisplayContentsAncestorPusher adcp(mTreeMatchContext, mPresContext,
|
2014-11-20 21:24:10 +03:00
|
|
|
mFrame->GetContent() ? mFrame->GetContent()->GetParent() : nullptr);
|
|
|
|
|
2015-08-05 15:42:20 +03:00
|
|
|
AutoSelectorArrayTruncater asat(mSelectorsForDescendants);
|
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
// 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.
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<Element>> descendants;
|
2014-09-05 07:48:47 +04:00
|
|
|
|
2014-08-04 00:11:55 +04:00
|
|
|
nsRestyleHint hintToRestore = nsRestyleHint(0);
|
2015-08-05 15:42:20 +03:00
|
|
|
RestyleHintData hintDataToRestore;
|
2014-08-04 00:11:55 +04:00
|
|
|
if (mContent && mContent->IsElement() &&
|
2014-12-25 10:28:25 +03:00
|
|
|
// If we're resolving from the root of the frame tree (which
|
2015-01-14 08:03:12 +03:00
|
|
|
// we do when mDoRebuildAllStyleData), we need to avoid getting the
|
2014-08-04 00:11:55 +04:00
|
|
|
// 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.
|
2015-02-17 01:15:04 +03:00
|
|
|
// 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) {
|
2013-07-31 04:36:11 +04:00
|
|
|
mContent->OwnerDoc()->FlushPendingLinkUpdates();
|
2014-09-05 07:48:48 +04:00
|
|
|
nsAutoPtr<RestyleTracker::RestyleData> restyleData;
|
|
|
|
if (mRestyleTracker.GetRestyleData(mContent->AsElement(), restyleData)) {
|
2016-05-23 06:26:03 +03:00
|
|
|
if (!NS_IsHintSubset(restyleData->mChangeHint, mHintsHandled)) {
|
|
|
|
mHintsHandled |= restyleData->mChangeHint;
|
2014-09-05 07:48:48 +04:00
|
|
|
mChangeList->AppendChange(mFrame, mContent, restyleData->mChangeHint);
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2015-08-05 15:42:20 +03:00
|
|
|
mSelectorsForDescendants.AppendElements(
|
|
|
|
restyleData->mRestyleHintData.mSelectorsForDescendants);
|
2014-09-05 07:48:48 +04:00
|
|
|
hintToRestore = restyleData->mRestyleHint;
|
2015-08-05 15:42:20 +03:00
|
|
|
hintDataToRestore = Move(restyleData->mRestyleHintData);
|
2014-09-05 07:48:48 +04:00
|
|
|
aRestyleHint = nsRestyleHint(aRestyleHint | restyleData->mRestyleHint);
|
|
|
|
descendants.SwapElements(restyleData->mDescendants);
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-13 10:28:52 +03:00
|
|
|
// If we are restyling this frame with eRestyle_Self or weaker hints,
|
|
|
|
// we restyle children with nsRestyleHint(0). But we pass the
|
2015-02-17 01:15:06 +03:00
|
|
|
// eRestyle_ForceDescendants flag down too.
|
2014-09-05 07:48:45 +04:00
|
|
|
nsRestyleHint childRestyleHint =
|
2015-08-05 15:42:20 +03:00
|
|
|
nsRestyleHint(aRestyleHint & (eRestyle_SomeDescendants |
|
|
|
|
eRestyle_Subtree |
|
2014-09-05 07:48:45 +04:00
|
|
|
eRestyle_ForceDescendants));
|
2013-07-31 04:36:11 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> oldContext = mFrame->StyleContext();
|
2014-09-05 07:48:47 +04:00
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
nsTArray<SwapInstruction> swaps;
|
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
// 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.
|
2016-07-19 16:10:59 +03:00
|
|
|
RestyleResult result = RestyleResult::eNone;
|
2014-09-05 07:48:47 +04:00
|
|
|
uint32_t swappedStructs = 0;
|
|
|
|
|
|
|
|
nsRestyleHint thisRestyleHint = aRestyleHint;
|
|
|
|
|
|
|
|
bool haveMoreContinuations = false;
|
|
|
|
for (nsIFrame* f = mFrame; f; ) {
|
2015-08-28 23:13:48 +03:00
|
|
|
RestyleResult thisResult =
|
|
|
|
RestyleSelf(f, thisRestyleHint, &swappedStructs, swaps);
|
2014-09-05 07:48:45 +04:00
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (thisResult != RestyleResult::eStop) {
|
2014-09-05 07:48:47 +04:00
|
|
|
// Calls to RestyleSelf for later same-style continuations must not
|
2016-07-19 16:10:59 +03:00
|
|
|
// return RestyleResult::eStop, so pass eRestyle_Force in to them.
|
2014-09-05 07:48:47 +04:00
|
|
|
thisRestyleHint = nsRestyleHint(thisRestyleHint | eRestyle_Force);
|
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eStop) {
|
|
|
|
// We received RestyleResult::eStop for earlier same-style
|
|
|
|
// continuations, and RestyleResult::eStopWithStyleChange or
|
|
|
|
// RestyleResult::eContinue(AndForceDescendants) for this one; go
|
2015-08-28 23:13:48 +03:00
|
|
|
// back and force-restyle the earlier continuations.
|
2014-09-05 07:48:45 +04:00
|
|
|
result = thisResult;
|
2014-09-05 07:48:47 +04:00
|
|
|
f = mFrame;
|
|
|
|
continue;
|
2014-09-05 07:48:45 +04:00
|
|
|
}
|
2014-09-05 07:48:47 +04:00
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
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;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
2016-08-01 23:40:27 +03:00
|
|
|
f = RestyleManager::GetNextContinuationWithSameStyle(f,
|
|
|
|
oldContext,
|
|
|
|
&haveMoreContinuations);
|
2014-09-05 07:48:47 +04:00
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2014-12-25 10:28:25 +03:00
|
|
|
// 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();
|
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
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));
|
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eStop) {
|
2014-09-05 07:48:47 +04:00
|
|
|
MOZ_ASSERT(mFrame->StyleContext() == oldContext,
|
|
|
|
"frame should have been left with its old style context");
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIFrame* unused;
|
|
|
|
nsStyleContext* newParent = mFrame->GetParentStyleContext(&unused);
|
2014-09-05 07:48:47 +04:00
|
|
|
if (oldContext->GetParent() != newParent) {
|
2016-07-19 16:10:59 +03:00
|
|
|
// If we received RestyleResult::eStop, then the old style context was
|
2014-09-05 07:48:47 +04:00
|
|
|
// left on mFrame. Since we ended up restyling our parent, change
|
|
|
|
// this old style context to point to its new parent.
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("moving style context %p from old parent %p to new parent %p",
|
|
|
|
oldContext.get(), oldContext->GetParent(), newParent);
|
2015-02-18 01:28:53 +03:00
|
|
|
// 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),
|
2015-04-15 01:13:45 +03:00
|
|
|
// (c) something under ProcessPendingRestyles (which notably is called
|
2015-02-18 01:28:53 +03:00
|
|
|
// *before* ClearCachedInheritedStyleDataOnDescendants is called
|
|
|
|
// on the old context) causes the new parent to be destroyed, thus
|
|
|
|
// destroying its owned structs, and
|
2015-04-15 01:13:45 +03:00
|
|
|
// (d) something under ProcessPendingRestyles then wants to use of those
|
2015-02-18 01:28:53 +03:00
|
|
|
// now destroyed structs (through the old parent's descendants).
|
|
|
|
mSwappedStructOwners.AppendElement(newParent);
|
2014-09-05 07:48:47 +04:00
|
|
|
oldContext->MoveTo(newParent);
|
2014-09-05 07:48:45 +04:00
|
|
|
}
|
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
// Send the accessibility notifications that RestyleChildren otherwise
|
|
|
|
// would have sent.
|
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
2014-11-20 21:24:10 +03:00
|
|
|
InitializeAccessibilityNotifications(mFrame->StyleContext());
|
2014-09-05 07:48:47 +04:00
|
|
|
SendAccessibilityNotifications();
|
2013-09-25 23:28:07 +04:00
|
|
|
}
|
2014-08-04 00:11:55 +04:00
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
|
2015-08-28 23:13:47 +03:00
|
|
|
if (aRestyleHint & eRestyle_SomeDescendants) {
|
2015-09-04 03:00:14 +03:00
|
|
|
ConditionallyRestyleChildren();
|
2015-08-05 15:42:20 +03:00
|
|
|
}
|
2014-09-05 07:48:47 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eStopWithStyleChange &&
|
2015-08-28 23:13:48 +03:00
|
|
|
!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
|
|
|
MOZ_ASSERT(mFrame->StyleContext() != oldContext,
|
2016-07-19 16:10:59 +03:00
|
|
|
"RestyleResult::eStopWithStyleChange should only be returned "
|
2015-08-28 23:13:48 +03:00
|
|
|
"if we got a new style context or we will reconstruct");
|
|
|
|
MOZ_ASSERT(swappedStructs == 0,
|
|
|
|
"should have ensured we didn't swap structs when "
|
2016-07-19 16:10:59 +03:00
|
|
|
"returning RestyleResult::eStopWithStyleChange");
|
2015-08-28 23:13:48 +03:00
|
|
|
|
|
|
|
// 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) {
|
2015-09-04 03:00:14 +03:00
|
|
|
ConditionallyRestyleChildren();
|
2015-08-28 23:13:48 +03:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Turns out we couldn't stop restyling here. Process the struct
|
|
|
|
// swaps that RestyleSelf would've done had we not returned
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eStopWithStyleChange.
|
2015-08-28 23:13:48 +03:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eContinueAndForceDescendants) {
|
2014-09-05 07:48:47 +04:00
|
|
|
childRestyleHint =
|
|
|
|
nsRestyleHint(childRestyleHint | eRestyle_ForceDescendants);
|
2013-09-25 23:28:07 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
// 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);
|
|
|
|
}
|
2014-09-05 07:48:47 +04:00
|
|
|
|
|
|
|
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
|
2015-02-18 01:28:53 +03:00
|
|
|
// to it, we need to make ensure its descendants don't cache any of the
|
2014-09-05 07:48:47 +04:00
|
|
|
// structs that were swapped out.
|
|
|
|
//
|
2015-02-18 01:28:53 +03:00
|
|
|
// 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).
|
2015-04-29 07:47:15 +03:00
|
|
|
//
|
|
|
|
// 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();
|
|
|
|
|
2015-03-04 10:06:29 +03:00
|
|
|
ContextToClear* toClear = mContextsToClear.AppendElement();
|
|
|
|
toClear->mStyleContext = Move(oldContext);
|
|
|
|
toClear->mStructs = swappedStructs;
|
2014-09-05 07:48:47 +04:00
|
|
|
}
|
|
|
|
|
2014-09-05 07:48:47 +04:00
|
|
|
mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
|
|
|
|
2014-09-05 07:48:46 +04:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2016-07-19 16:10:59 +03:00
|
|
|
* This function returns RestyleResult::eStop if it does not find any
|
2014-09-05 07:48:46 +04:00
|
|
|
* conditions that would preclude stopping restyling, and
|
2016-07-19 16:10:59 +03:00
|
|
|
* RestyleResult::eContinue if it does.
|
2014-09-05 07:48:46 +04:00
|
|
|
*/
|
2015-08-28 23:13:48 +03:00
|
|
|
void
|
|
|
|
ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf,
|
|
|
|
RestyleResult& aRestyleResult,
|
|
|
|
bool& aCanStopWithStyleChange)
|
2014-09-05 07:48:46 +04:00
|
|
|
{
|
|
|
|
// 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)) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("there are additional style contexts");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
2014-09-25 09:45:36 +04:00
|
|
|
|
|
|
|
if (type == nsGkAtoms::letterFrame) {
|
|
|
|
LOG_RESTYLE_CONTINUE("frame is a letter frame");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-25 09:45:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type == nsGkAtoms::lineFrame) {
|
|
|
|
LOG_RESTYLE_CONTINUE("frame is a line frame");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the old context uses grandancestor style");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// We ignore all situations that involve :visited style.
|
|
|
|
if (oldContext->GetStyleIfVisited()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the old style context has StyleIfVisited");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsStyleContext* parentContext = oldContext->GetParent();
|
|
|
|
if (parentContext && parentContext->GetStyleIfVisited()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the old style context's parent has StyleIfVisited");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
2016-04-22 02:18:41 +03:00
|
|
|
if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
2016-04-22 02:18:41 +03:00
|
|
|
if (parentPseudoTag &&
|
|
|
|
parentPseudoTag != nsCSSAnonBoxes::mozOtherNonElement) {
|
|
|
|
MOZ_ASSERT(parentPseudoTag != nsCSSAnonBoxes::mozText,
|
|
|
|
"Style of text node should not be parent of anything");
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
// Parent style context pseudo-ness doesn't affect whether we can
|
2016-07-19 16:10:59 +03:00
|
|
|
// return RestyleResult::eStopWithStyleChange.
|
2015-08-28 23:13:48 +03:00
|
|
|
//
|
|
|
|
// If we had later conditions to check in this function, we would
|
|
|
|
// continue to check them, in case we set aCanStopWithStyleChange to
|
|
|
|
// false.
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
void
|
2014-09-05 07:48:46 +04:00
|
|
|
ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
2015-08-28 23:13:48 +03:00
|
|
|
nsStyleContext* aNewContext,
|
|
|
|
RestyleResult& aRestyleResult,
|
|
|
|
bool& aCanStopWithStyleChange)
|
2014-09-05 07:48:46 +04:00
|
|
|
{
|
2015-08-28 23:13:48 +03:00
|
|
|
// If we've already determined that we must continue styling, we don't
|
|
|
|
// need to check anything.
|
2016-07-19 16:10:59 +03:00
|
|
|
if (aRestyleResult == RestyleResult::eContinue && !aCanStopWithStyleChange) {
|
2015-08-28 23:13:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-05 07:48:46 +04:00
|
|
|
// 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()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the new style context has StyleIfVisited");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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() ||
|
2015-08-28 23:13:48 +03:00
|
|
|
oldContext->GetPseudoType() != aNewContext->GetPseudoType()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("the old and new style contexts have different link/"
|
2015-08-28 23:13:48 +03:00
|
|
|
"visited/pseudo");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldContext->RuleNode() != aNewContext->RuleNode()) {
|
|
|
|
LOG_RESTYLE_CONTINUE("the old and new style contexts have different "
|
|
|
|
"rulenodes");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
// Continue to check other conditions if aCanStopWithStyleChange might
|
|
|
|
// still need to be set to false.
|
|
|
|
if (!aCanStopWithStyleChange) {
|
|
|
|
return;
|
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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() !=
|
2014-09-25 09:45:36 +04:00
|
|
|
aNewContext->HasTextDecorationLines()) {
|
|
|
|
LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_TEXT_DECORATION_LINES differs between old"
|
|
|
|
" and new style contexts");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-25 09:45:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldContext->HasPseudoElementData() !=
|
2014-09-05 07:48:46 +04:00
|
|
|
aNewContext->HasPseudoElementData()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_PSEUDO_ELEMENT_DATA differs between old"
|
|
|
|
" and new style contexts");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
2015-03-11 02:28:21 +03:00
|
|
|
if (oldContext->ShouldSuppressLineBreak() !=
|
|
|
|
aNewContext->ShouldSuppressLineBreak()) {
|
2015-03-16 03:28:49 +03:00
|
|
|
LOG_RESTYLE_CONTINUE("NS_STYLE_SUPPRESS_LINEBREAK differs"
|
2014-12-31 08:39:43 +03:00
|
|
|
"between old and new style contexts");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2015-03-16 03:28:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldContext->IsInDisplayNoneSubtree() !=
|
|
|
|
aNewContext->IsInDisplayNoneSubtree()) {
|
|
|
|
LOG_RESTYLE_CONTINUE("NS_STYLE_IN_DISPLAY_NONE_SUBTREE differs between old"
|
|
|
|
" and new style contexts");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
2014-12-11 01:26:18 +03:00
|
|
|
}
|
2016-04-22 02:18:41 +03:00
|
|
|
|
|
|
|
if (oldContext->IsTextCombined() != aNewContext->IsTextCombined()) {
|
|
|
|
LOG_RESTYLE_CONTINUE("NS_STYLE_IS_TEXT_COMBINED differs between "
|
|
|
|
"old and new style contexts");
|
2016-07-19 16:10:59 +03:00
|
|
|
aRestyleResult = RestyleResult::eContinue;
|
2016-04-22 02:18:41 +03:00
|
|
|
aCanStopWithStyleChange = false;
|
|
|
|
return;
|
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
2015-08-05 15:42:20 +03:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2015-08-05 15:42:21 +03:00
|
|
|
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)) &&
|
2016-02-24 10:01:10 +03:00
|
|
|
!StyleSet()->IsInRuleTreeReconstruct();
|
2015-08-05 15:42:21 +03:00
|
|
|
}
|
|
|
|
|
2015-11-17 07:09:55 +03:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2014-09-05 07:48:45 +04:00
|
|
|
ElementRestyler::RestyleResult
|
2014-09-05 07:48:47 +04:00
|
|
|
ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
|
|
|
nsRestyleHint aRestyleHint,
|
2015-08-28 23:13:48 +03:00
|
|
|
uint32_t* aSwappedStructs,
|
|
|
|
nsTArray<SwapInstruction>& aSwaps)
|
2013-07-31 04:36:11 +04:00
|
|
|
{
|
2014-06-19 04:07:26 +04:00
|
|
|
MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
|
|
|
|
"eRestyle_LaterSiblings must not be part of aRestyleHint");
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// 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.
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("RestyleSelf %s, aRestyleHint = %s",
|
|
|
|
FrameTagToString(aSelf).get(),
|
2016-07-23 01:27:05 +03:00
|
|
|
RestyleManagerBase::RestyleHintToString(aRestyleHint).get());
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_INDENT();
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
// Initially assume that it is safe to stop restyling.
|
|
|
|
//
|
|
|
|
// Throughout most of this function, we update the following two variables
|
2016-07-19 16:10:59 +03:00
|
|
|
// independently. |result| is set to RestyleResult::eContinue when we
|
|
|
|
// detect a condition that would not allow us to return RestyleResult::eStop.
|
2015-08-28 23:13:48 +03:00
|
|
|
// |canStopWithStyleChange| is set to false when we detect a condition
|
2016-07-19 16:10:59 +03:00
|
|
|
// that would not allow us to return RestyleResult::eStopWithStyleChange.
|
2015-08-28 23:13:48 +03:00
|
|
|
//
|
|
|
|
// Towards the end of this function, we reconcile these two variables --
|
|
|
|
// if |canStopWithStyleChange| is true, we convert |result| into
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eStopWithStyleChange.
|
|
|
|
RestyleResult result = RestyleResult::eStop;
|
2015-08-28 23:13:48 +03:00
|
|
|
bool canStopWithStyleChange = true;
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2015-08-05 15:42:20 +03:00
|
|
|
if (aRestyleHint & ~eRestyle_SomeDescendants) {
|
2015-08-28 23:13:48 +03:00
|
|
|
// If we are doing any restyling of the current element, or if we're
|
|
|
|
// forced to continue, we must.
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
|
|
|
|
// If we have to restyle children, we can't return
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eStopWithStyleChange.
|
2015-08-28 23:13:48 +03:00
|
|
|
if (aRestyleHint & (eRestyle_Subtree | eRestyle_Force |
|
|
|
|
eRestyle_ForceDescendants)) {
|
|
|
|
canStopWithStyleChange = false;
|
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
// We only consider returning RestyleResult::eStopWithStyleChange if this
|
2015-08-28 23:13:48 +03:00
|
|
|
// 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);
|
|
|
|
|
2016-07-17 17:20:21 +03:00
|
|
|
nsChangeHint assumeDifferenceHint = nsChangeHint(0);
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> oldContext = aSelf->StyleContext();
|
2016-02-24 10:01:10 +03:00
|
|
|
nsStyleSet* styleSet = StyleSet();
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:12 +04:00
|
|
|
mWasFrameVisible = nsIPresShell::IsAccessibilityActive() ?
|
|
|
|
oldContext->StyleVisibility()->IsVisible() : false;
|
2013-07-20 23:14:25 +04:00
|
|
|
#endif
|
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
nsIAtom* const pseudoTag = oldContext->GetPseudo();
|
2016-02-17 23:37:00 +03:00
|
|
|
const CSSPseudoElementType pseudoType = oldContext->GetPseudoType();
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
// Get the frame providing the parent style context. If it is a
|
|
|
|
// child, then resolve the provider first.
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIFrame* providerFrame;
|
|
|
|
nsStyleContext* parentContext = aSelf->GetParentStyleContext(&providerFrame);
|
2013-09-25 23:28:07 +04:00
|
|
|
bool isChild = providerFrame && providerFrame->GetParent() == aSelf;
|
2014-11-20 21:24:10 +03:00
|
|
|
if (isChild) {
|
2013-09-25 23:28:07 +04:00
|
|
|
MOZ_ASSERT(providerFrame->GetContent() == aSelf->GetContent(),
|
2014-11-20 21:24:10 +03:00
|
|
|
"Postcondition for GetParentStyleContext() violated. "
|
2013-07-31 04:36:12 +04:00
|
|
|
"That means we need to add the current element to the "
|
|
|
|
"ancestor filter.");
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
// resolve the provider here (before aSelf below).
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("resolving child provider frame");
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
// 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
|
2013-09-25 23:28:07 +04:00
|
|
|
// aSelf's context.
|
2013-07-31 04:36:12 +04:00
|
|
|
parentContext = providerFrame->StyleContext();
|
|
|
|
// Set |mResolvedChild| so we don't bother resolving the
|
|
|
|
// provider again.
|
|
|
|
mResolvedChild = providerFrame;
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("we had a provider frame");
|
2014-09-05 07:48:46 +04:00
|
|
|
// Continue restyling past the odd style context inheritance.
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
canStopWithStyleChange = false;
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
if (providerFrame != aSelf->GetParent()) {
|
2013-07-31 04:36:12 +04:00
|
|
|
// We don't actually know what the parent style context's
|
|
|
|
// non-inherited hints were, so assume the worst.
|
|
|
|
mParentFrameHintsNotHandledForDescendants =
|
|
|
|
nsChangeHint_Hints_NotHandledForDescendants;
|
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("parentContext = %p", parentContext);
|
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
// do primary context
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> newContext;
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIFrame* prevContinuation =
|
2013-09-25 23:28:07 +04:00
|
|
|
GetPrevContinuationWithPossiblySameStyle(aSelf);
|
2016-07-08 10:08:46 +03:00
|
|
|
nsStyleContext* prevContinuationContext;
|
2013-07-31 04:36:12 +04:00
|
|
|
bool copyFromContinuation =
|
|
|
|
prevContinuation &&
|
|
|
|
(prevContinuationContext = prevContinuation->StyleContext())
|
|
|
|
->GetPseudo() == oldContext->GetPseudo() &&
|
|
|
|
prevContinuationContext->GetParent() == parentContext;
|
|
|
|
if (copyFromContinuation) {
|
|
|
|
// Just use the style context from the frame's previous
|
2013-09-25 23:28:07 +04:00
|
|
|
// continuation.
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("using previous continuation's context");
|
2013-07-31 04:36:12 +04:00
|
|
|
newContext = prevContinuationContext;
|
2016-04-29 07:01:44 +03:00
|
|
|
} else if (pseudoTag == nsCSSAnonBoxes::mozText) {
|
|
|
|
MOZ_ASSERT(aSelf->GetType() == nsGkAtoms::textFrame);
|
|
|
|
newContext =
|
|
|
|
styleSet->ResolveStyleForText(aSelf->GetContent(), parentContext);
|
2016-04-22 02:18:41 +03:00
|
|
|
} else if (nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
|
2016-04-29 07:01:44 +03:00
|
|
|
newContext = styleSet->ResolveStyleForOtherNonElement(parentContext);
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-09-25 23:28:07 +04:00
|
|
|
Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
|
2015-08-05 15:42:20 +03:00
|
|
|
if (!MustRestyleSelf(aRestyleHint, element)) {
|
2015-08-05 15:42:21 +03:00
|
|
|
if (CanReparentStyleContext(aRestyleHint)) {
|
2015-08-05 15:42:20 +03:00
|
|
|
LOG_RESTYLE("reparenting style context");
|
|
|
|
newContext =
|
|
|
|
styleSet->ReparentStyleContext(oldContext, parentContext, element);
|
2013-07-31 04:36:12 +04:00
|
|
|
} else {
|
2015-08-05 15:42:20 +03:00
|
|
|
// 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,
|
2015-02-17 01:15:05 +03:00
|
|
|
"pseudo-element for selector matching should be "
|
|
|
|
"the anonymous content node that we create, "
|
|
|
|
"not the real element");
|
2015-08-05 15:42:20 +03:00
|
|
|
LOG_RESTYLE("resolving style with replacement");
|
|
|
|
nsRestyleHint rshint = aRestyleHint & ~eRestyle_SomeDescendants;
|
|
|
|
newContext =
|
|
|
|
styleSet->ResolveStyleWithReplacement(element, pseudoElement,
|
|
|
|
parentContext, oldContext,
|
|
|
|
rshint);
|
2015-08-04 10:27:52 +03:00
|
|
|
}
|
2016-02-17 01:07:00 +03:00
|
|
|
} else if (pseudoType == CSSPseudoElementType::AnonBox) {
|
2015-08-05 15:42:20 +03:00
|
|
|
newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag,
|
|
|
|
parentContext);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2015-08-04 13:20:20 +03:00
|
|
|
else {
|
2015-08-05 15:42:20 +03:00
|
|
|
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
|
2016-05-23 06:26:03 +03:00
|
|
|
mHintsHandled |= nsChangeHint_ReconstructFrame;
|
2015-08-05 15:42:20 +03:00
|
|
|
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.
|
2016-02-17 23:37:00 +03:00
|
|
|
NS_ASSERTION(pseudoType < CSSPseudoElementType::Count,
|
2015-08-05 15:42:20 +03:00
|
|
|
"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);
|
|
|
|
}
|
2015-08-04 13:20:20 +03:00
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
|
2013-08-03 08:11:06 +04:00
|
|
|
MOZ_ASSERT(newContext);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
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.
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("restyling root and keeping old context");
|
2016-07-19 16:10:59 +03:00
|
|
|
LOG_RESTYLE_IF(this, result != RestyleResult::eContinue,
|
2014-09-25 09:45:36 +04:00
|
|
|
"continuing restyle since this is the root");
|
2013-07-31 04:36:12 +04:00
|
|
|
newContext = oldContext;
|
2014-09-05 07:48:46 +04:00
|
|
|
// Never consider stopping restyling at the root.
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
canStopWithStyleChange = false;
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("oldContext = %p, newContext = %p%s",
|
|
|
|
oldContext.get(), newContext.get(),
|
|
|
|
oldContext == newContext ? (const char*) " (same)" :
|
|
|
|
(const char*) "");
|
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
if (newContext != oldContext) {
|
2015-08-28 23:13:48 +03:00
|
|
|
if (oldContext->IsShared()) {
|
|
|
|
// If the old style context was shared, then we can't return
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eStop and patch its parent to point to the
|
2015-08-28 23:13:48 +03:00
|
|
|
// 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");
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2015-11-08 03:06:14 +03:00
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
// It is not safe to return RestyleResult::eStopWithStyleChange
|
2015-11-17 07:09:55 +03:00
|
|
|
// 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
|
2016-07-19 16:10:59 +03:00
|
|
|
// we can continue assuming that RestyleResult::eStopWithStyleChange
|
2015-11-17 07:09:55 +03:00
|
|
|
// 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;
|
|
|
|
}
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
// 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);
|
|
|
|
|
2014-09-05 07:48:46 +04:00
|
|
|
uint32_t equalStructs = 0;
|
2015-08-28 23:13:47 +03:00
|
|
|
uint32_t samePointerStructs = 0;
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2014-09-05 07:48:46 +04:00
|
|
|
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.
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eStop) {
|
2014-09-05 07:48:46 +04:00
|
|
|
oldContext->CalcStyleDifference(newContext, nsChangeHint(0),
|
2015-08-28 23:13:47 +03:00
|
|
|
&equalStructs,
|
|
|
|
&samePointerStructs);
|
2014-09-05 07:48:46 +04:00
|
|
|
if (equalStructs != NS_STYLE_INHERIT_MASK) {
|
|
|
|
// At least one struct had different data in it, so we must
|
|
|
|
// continue restyling children.
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("there is different style data: %s",
|
|
|
|
RestyleManager::StructNamesToString(
|
|
|
|
~equalStructs & NS_STYLE_INHERIT_MASK).get());
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2015-03-04 08:08:00 +03:00
|
|
|
bool changedStyle =
|
2016-10-19 09:16:52 +03:00
|
|
|
RestyleManager::TryInitiatingTransition(mPresContext,
|
|
|
|
aSelf->GetContent(),
|
|
|
|
oldContext, &newContext);
|
2015-03-04 08:08:00 +03:00
|
|
|
if (changedStyle) {
|
2016-10-19 09:16:52 +03:00
|
|
|
LOG_RESTYLE_CONTINUE("TryInitiatingTransition changed the new style "
|
|
|
|
"context");
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2015-08-28 23:13:48 +03:00
|
|
|
canStopWithStyleChange = false;
|
2015-03-04 08:08:00 +03:00
|
|
|
}
|
2014-09-05 07:48:45 +04:00
|
|
|
CaptureChange(oldContext, newContext, assumeDifferenceHint,
|
2015-08-28 23:13:47 +03:00
|
|
|
&equalStructs, &samePointerStructs);
|
2014-09-05 07:48:46 +04:00
|
|
|
if (equalStructs != NS_STYLE_INHERIT_MASK) {
|
|
|
|
// At least one struct had different data in it, so we must
|
|
|
|
// continue restyling children.
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("there is different style data: %s",
|
|
|
|
RestyleManager::StructNamesToString(
|
|
|
|
~equalStructs & NS_STYLE_INHERIT_MASK).get());
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
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
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eStopWithStyleChange.
|
2015-08-28 23:13:48 +03:00
|
|
|
if ((samePointerStructs & NS_STYLE_INHERITED_STRUCT_MASK) !=
|
|
|
|
NS_STYLE_INHERITED_STRUCT_MASK) {
|
2016-07-19 16:10:59 +03:00
|
|
|
LOG_RESTYLE("can't return RestyleResult::eStopWithStyleChange since "
|
2015-08-28 23:13:48 +03:00
|
|
|
"there is different inherited data");
|
|
|
|
canStopWithStyleChange = false;
|
|
|
|
} else if ((samePointerStructs & NS_STYLE_RESET_STRUCT_MASK) !=
|
|
|
|
NS_STYLE_RESET_STRUCT_MASK &&
|
|
|
|
oldContext->HasChildThatUsesResetStyle()) {
|
2016-07-19 16:10:59 +03:00
|
|
|
LOG_RESTYLE("can't return RestyleResult::eStopWithStyleChange since "
|
2015-08-28 23:13:48 +03:00
|
|
|
"there is different reset data and descendants use it");
|
|
|
|
canStopWithStyleChange = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eStop) {
|
|
|
|
// Since we currently have RestyleResult::eStop, we know at this
|
2014-09-05 07:48:46 +04:00
|
|
|
// 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
|
2014-09-05 07:48:46 +04:00
|
|
|
// ancestors (later in this function), we've ensured that for structs
|
2014-09-05 07:48:46 +04:00
|
|
|
// that cannot be stored in the rule tree, we keep the old equal structs
|
2014-09-05 07:48:46 +04:00
|
|
|
// 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.
|
2015-08-28 23:13:47 +03:00
|
|
|
//
|
|
|
|
// FIXME This loop could be rewritten as bit operations on
|
|
|
|
// oldContext->mBits and samePointerStructs.
|
2014-09-05 07:48:46 +04:00
|
|
|
for (nsStyleStructID sid = nsStyleStructID(0);
|
|
|
|
sid < nsStyleStructID_Length;
|
|
|
|
sid = nsStyleStructID(sid + 1)) {
|
2015-10-20 06:42:28 +03:00
|
|
|
if (oldContext->HasCachedDependentStyleData(sid) &&
|
2015-08-28 23:13:47 +03:00
|
|
|
!(samePointerStructs & nsCachedStyleData::GetBitForSID(sid))) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE_CONTINUE("there are different struct pointers");
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinue;
|
2014-09-05 07:48:46 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
// From this point we no longer do any assignments of
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eContinue to |result|. If canStopWithStyleChange is true,
|
2015-08-28 23:13:48 +03:00
|
|
|
// it means that we can convert |result| (whether it is
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eContinue or RestyleResult::eStop) into
|
|
|
|
// RestyleResult::eStopWithStyleChange.
|
2015-08-28 23:13:48 +03:00
|
|
|
if (canStopWithStyleChange) {
|
2016-07-19 16:10:59 +03:00
|
|
|
LOG_RESTYLE("converting %s into RestyleResult::eStopWithStyleChange",
|
2015-08-28 23:13:48 +03:00
|
|
|
RestyleResultToString(result).get());
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eStopWithStyleChange;
|
2015-08-28 23:13:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aRestyleHint & eRestyle_ForceDescendants) {
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinueAndForceDescendants;
|
2015-08-28 23:13:48 +03:00
|
|
|
}
|
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
2013-09-25 23:28:08 +04:00
|
|
|
// 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.
|
2014-09-05 07:48:46 +04:00
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result != RestyleResult::eStop) {
|
2015-02-18 01:28:53 +03:00
|
|
|
if (copyFromContinuation) {
|
2014-09-25 09:51:43 +04:00
|
|
|
LOG_RESTYLE("not swapping style structs, since we copied from a "
|
|
|
|
"continuation");
|
|
|
|
} else if (oldContext->IsShared() && newContext->IsShared()) {
|
2014-09-25 09:45:36 +04:00
|
|
|
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 {
|
2016-07-19 16:10:59 +03:00
|
|
|
if (result == RestyleResult::eStopWithStyleChange) {
|
2015-08-28 23:13:48 +03:00
|
|
|
LOG_RESTYLE("recording a style struct swap between %p and %p to "
|
2016-07-19 16:10:59 +03:00
|
|
|
"do if RestyleResult::eStopWithStyleChange fails",
|
2015-08-28 23:13:48 +03:00
|
|
|
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;
|
|
|
|
}
|
2014-10-01 03:13:57 +04:00
|
|
|
#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
|
2014-09-05 07:48:46 +04:00
|
|
|
}
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("setting new style context");
|
2014-09-05 07:48:46 +04:00
|
|
|
aSelf->SetStyleContext(newContext);
|
|
|
|
}
|
2014-09-25 09:45:36 +04:00
|
|
|
} else {
|
|
|
|
LOG_RESTYLE("not setting new style context, since we'll reframe");
|
2015-04-15 01:13:45 +03:00
|
|
|
// 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());
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
2015-08-28 23:13:48 +03:00
|
|
|
} else {
|
|
|
|
if (aRestyleHint & eRestyle_ForceDescendants) {
|
2016-07-19 16:10:59 +03:00
|
|
|
result = RestyleResult::eContinueAndForceDescendants;
|
2015-08-28 23:13:48 +03:00
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
oldContext = nullptr;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
// 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;
|
2013-09-25 23:28:07 +04:00
|
|
|
(oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex));
|
2013-07-31 04:36:12 +04:00
|
|
|
++contextIndex) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("extra context %d", contextIndex);
|
|
|
|
LOG_RESTYLE_INDENT();
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> newExtraContext;
|
2013-07-31 04:36:12 +04:00
|
|
|
nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
|
2016-02-17 23:37:00 +03:00
|
|
|
const CSSPseudoElementType extraPseudoType =
|
2013-07-31 04:36:12 +04:00
|
|
|
oldExtraContext->GetPseudoType();
|
|
|
|
NS_ASSERTION(extraPseudoTag &&
|
2016-04-22 02:18:41 +03:00
|
|
|
!nsCSSAnonBoxes::IsNonElement(extraPseudoTag),
|
2013-07-31 04:36:12 +04:00
|
|
|
"extra style context is not pseudo element");
|
2016-02-17 01:07:00 +03:00
|
|
|
Element* element = extraPseudoType != CSSPseudoElementType::AnonBox
|
2015-08-05 15:42:20 +03:00
|
|
|
? mContent->AsElement() : nullptr;
|
|
|
|
if (!MustRestyleSelf(aRestyleHint, element)) {
|
2015-08-05 15:42:21 +03:00
|
|
|
if (CanReparentStyleContext(aRestyleHint)) {
|
|
|
|
newExtraContext =
|
|
|
|
styleSet->ReparentStyleContext(oldExtraContext, newContext, element);
|
|
|
|
} else {
|
2014-08-04 00:11:55 +04:00
|
|
|
// 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.
|
2015-02-17 01:15:05 +03:00
|
|
|
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");
|
2014-08-04 00:11:55 +04:00
|
|
|
newExtraContext =
|
2015-02-17 01:15:05 +03:00
|
|
|
styleSet->ResolveStyleWithReplacement(element, pseudoElement,
|
|
|
|
newContext, oldExtraContext,
|
2014-08-04 00:11:55 +04:00
|
|
|
nsRestyleHint(0));
|
|
|
|
}
|
2016-02-17 01:07:00 +03:00
|
|
|
} else if (extraPseudoType == CSSPseudoElementType::AnonBox) {
|
2013-07-31 04:36:12 +04:00
|
|
|
newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag,
|
|
|
|
newContext);
|
2014-08-04 00:11:55 +04:00
|
|
|
} else {
|
2013-07-31 04:36:12 +04:00
|
|
|
// Don't expect XUL tree stuff here, since it needs a comparator and
|
|
|
|
// all.
|
2016-02-17 01:07:00 +03:00
|
|
|
NS_ASSERTION(extraPseudoType < CSSPseudoElementType::Count,
|
2013-07-31 04:36:12 +04:00
|
|
|
"Unexpected type");
|
|
|
|
newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(),
|
|
|
|
extraPseudoType,
|
2013-11-28 10:46:38 +04:00
|
|
|
newContext,
|
|
|
|
nullptr);
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
2013-08-03 08:11:06 +04:00
|
|
|
|
|
|
|
MOZ_ASSERT(newExtraContext);
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("newExtraContext = %p", newExtraContext.get());
|
|
|
|
|
2013-08-03 08:11:06 +04:00
|
|
|
if (oldExtraContext != newExtraContext) {
|
2014-09-05 07:48:45 +04:00
|
|
|
uint32_t equalStructs;
|
2015-08-28 23:13:47 +03:00
|
|
|
uint32_t samePointerStructs;
|
2014-09-05 07:48:45 +04:00
|
|
|
CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint,
|
2015-08-28 23:13:47 +03:00
|
|
|
&equalStructs, &samePointerStructs);
|
2013-08-03 08:11:06 +04:00
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("setting new extra style context");
|
2013-09-25 23:28:07 +04:00
|
|
|
aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext);
|
2014-09-25 09:45:36 +04:00
|
|
|
} else {
|
|
|
|
LOG_RESTYLE("not setting new extra style context, since we'll reframe");
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
2014-09-05 07:48:45 +04:00
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("returning %s", RestyleResultToString(result).get());
|
|
|
|
|
2014-09-05 07:48:46 +04:00
|
|
|
return result;
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
|
|
|
|
{
|
2014-11-20 21:24:10 +03:00
|
|
|
MOZ_ASSERT(!(mHintsHandled & nsChangeHint_ReconstructFrame),
|
|
|
|
"No need to do this if we're planning to reframe already.");
|
|
|
|
|
2014-08-04 00:11:55 +04:00
|
|
|
// 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;
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
RestyleUndisplayedDescendants(aChildRestyleHint);
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
// 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) &&
|
2014-08-04 00:11:55 +04:00
|
|
|
mightReframePseudos) {
|
2014-08-25 08:48:21 +04:00
|
|
|
MaybeReframeForBeforePseudo();
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2016-07-08 10:08:46 +03:00
|
|
|
nsIFrame* lastContinuation;
|
2013-07-31 04:36:12 +04:00
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
2014-11-20 21:24:10 +03:00
|
|
|
InitializeAccessibilityNotifications(mFrame->StyleContext());
|
2013-07-31 04:36:12 +04:00
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
for (nsIFrame* f = mFrame; f;
|
2016-08-01 23:40:27 +03:00
|
|
|
f = RestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
|
2013-09-25 23:28:07 +04:00
|
|
|
lastContinuation = f;
|
|
|
|
RestyleContentChildren(f, aChildRestyleHint);
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
SendAccessibilityNotifications();
|
|
|
|
}
|
2013-09-25 23:28:07 +04:00
|
|
|
|
|
|
|
// Check whether we might need to create a new ::after frame.
|
|
|
|
// See comments above regarding :before.
|
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
|
2014-08-04 00:11:55 +04:00
|
|
|
mightReframePseudos) {
|
2014-08-25 08:48:21 +04:00
|
|
|
MaybeReframeForAfterPseudo(lastContinuation);
|
2013-09-25 23:28:07 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
void
|
|
|
|
ElementRestyler::RestyleChildrenOfDisplayContentsElement(
|
2015-08-05 15:42:20 +03:00
|
|
|
nsIFrame* aParentFrame,
|
|
|
|
nsStyleContext* aNewContext,
|
|
|
|
nsChangeHint aMinHint,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData)
|
2014-11-20 21:24:10 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!(mHintsHandled & nsChangeHint_ReconstructFrame), "why call me?");
|
|
|
|
|
|
|
|
const bool mightReframePseudos = aRestyleHint & eRestyle_Subtree;
|
|
|
|
DoRestyleUndisplayedDescendants(nsRestyleHint(0), mContent, aNewContext);
|
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) {
|
2016-02-17 01:07:00 +03:00
|
|
|
MaybeReframeForPseudo(CSSPseudoElementType::before,
|
2015-08-28 23:13:48 +03:00
|
|
|
aParentFrame, nullptr, mContent, aNewContext);
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) {
|
2016-02-17 01:07:00 +03:00
|
|
|
MaybeReframeForPseudo(CSSPseudoElementType::after,
|
2015-08-28 23:13:48 +03:00
|
|
|
aParentFrame, nullptr, mContent, aNewContext);
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
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()) {
|
2015-09-22 21:21:44 +03:00
|
|
|
for (nsIFrame* f : lists.CurrentList()) {
|
2014-11-20 21:24:10 +03:00
|
|
|
if (nsContentUtils::ContentIsDescendantOf(f->GetContent(), mContent) &&
|
|
|
|
!f->GetPrevContinuation()) {
|
|
|
|
if (!(f->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
|
|
|
|
ComputeStyleChangeFor(f, mChangeList, aMinHint, aRestyleTracker,
|
2015-08-05 15:42:20 +03:00
|
|
|
aRestyleHint, aRestyleHintData,
|
|
|
|
mContextsToClear, mSwappedStructOwners);
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
|
|
|
SendAccessibilityNotifications();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame,
|
|
|
|
nsStyleChangeList* aChangeList,
|
|
|
|
nsChangeHint aMinChange,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
2015-02-18 01:28:53 +03:00
|
|
|
nsRestyleHint aRestyleHint,
|
2015-08-05 15:42:20 +03:00
|
|
|
const RestyleHintData& aRestyleHintData,
|
2015-02-18 01:28:53 +03:00
|
|
|
nsTArray<ContextToClear>&
|
|
|
|
aContextsToClear,
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>>&
|
2015-02-18 01:28:53 +03:00
|
|
|
aSwappedStructOwners)
|
2014-11-20 21:24:10 +03:00
|
|
|
{
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
2015-10-07 03:14:00 +03:00
|
|
|
nsAutoCString localDescriptor;
|
2015-02-26 01:16:00 +03:00
|
|
|
if (profiler_is_active() && content) {
|
2015-10-07 03:14:00 +03:00
|
|
|
std::string elemDesc = ToString(*content);
|
|
|
|
localDescriptor.Assign(elemDesc.c_str());
|
2015-02-26 01:16:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
PROFILER_LABEL_PRINTF("ElementRestyler", "ComputeStyleChangeFor",
|
|
|
|
js::ProfileEntry::Category::CSS,
|
|
|
|
content ? "Element: %s" : "%s",
|
2015-10-07 03:14:00 +03:00
|
|
|
content ? localDescriptor.get() : "");
|
2014-11-20 21:24:10 +03:00
|
|
|
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);
|
2015-08-05 15:42:20 +03:00
|
|
|
nsTArray<nsCSSSelector*> selectorsForDescendants;
|
|
|
|
selectorsForDescendants.AppendElements(
|
|
|
|
aRestyleHintData.mSelectorsForDescendants);
|
2014-11-20 21:24:10 +03:00
|
|
|
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
|
2015-08-28 23:13:48 +03:00
|
|
|
nsIFrame* nextIBSibling;
|
|
|
|
for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) {
|
2016-08-01 23:31:57 +03:00
|
|
|
nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(propTable, ibSibling);
|
2015-08-28 23:13:48 +03:00
|
|
|
|
|
|
|
if (nextIBSibling) {
|
|
|
|
// Don't allow some ib-split siblings to be processed with
|
2016-07-19 16:10:59 +03:00
|
|
|
// RestyleResult::eStopWithStyleChange and others not.
|
2015-08-28 23:13:48 +03:00
|
|
|
aRestyleHint |= eRestyle_Force;
|
|
|
|
}
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
// 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,
|
2015-08-05 15:42:20 +03:00
|
|
|
selectorsForDescendants,
|
2014-11-20 21:24:10 +03:00
|
|
|
treeMatchContext,
|
2015-02-18 01:28:53 +03:00
|
|
|
visibleKidsOfHiddenElement,
|
|
|
|
aContextsToClear, aSwappedStructOwners);
|
2014-11-20 21:24:10 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
// The structure of this method parallels ConditionallyRestyleUndisplayedDescendants.
|
|
|
|
// If you update this method, you probably want to update that one too.
|
2013-07-31 04:36:11 +04:00
|
|
|
void
|
2014-11-20 21:24:10 +03:00
|
|
|
ElementRestyler::RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint)
|
2013-07-31 04:36:11 +04:00
|
|
|
{
|
2013-07-31 04:36:12 +04:00
|
|
|
nsIContent* undisplayedParent;
|
2015-09-04 03:00:14 +03:00
|
|
|
if (MustCheckUndisplayedContent(mFrame, undisplayedParent)) {
|
2014-11-20 21:24:10 +03:00
|
|
|
DoRestyleUndisplayedDescendants(aChildRestyleHint, undisplayedParent,
|
|
|
|
mFrame->StyleContext());
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
// The structure of this method parallels DoConditionallyRestyleUndisplayedDescendants.
|
|
|
|
// If you update this method, you probably want to update that one too.
|
2014-11-20 21:24:10 +03:00
|
|
|
void
|
|
|
|
ElementRestyler::DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIContent* aParent,
|
|
|
|
nsStyleContext* aParentContext)
|
2014-11-20 21:24:10 +03:00
|
|
|
{
|
|
|
|
nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
|
|
|
|
UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
|
|
|
|
RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
|
2016-09-03 21:46:58 +03:00
|
|
|
aParentContext, StyleDisplay::None);
|
2014-11-20 21:24:10 +03:00
|
|
|
nodes = fc->GetAllDisplayContentsIn(aParent);
|
|
|
|
RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
|
2016-08-28 05:31:50 +03:00
|
|
|
aParentContext, StyleDisplay::Contents);
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
// The structure of this method parallels ConditionallyRestyleUndisplayedNodes.
|
|
|
|
// If you update this method, you probably want to update that one too.
|
2014-11-20 21:24:10 +03:00
|
|
|
void
|
2016-08-28 05:31:50 +03:00
|
|
|
ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
|
|
|
|
UndisplayedNode* aUndisplayed,
|
|
|
|
nsIContent* aUndisplayedParent,
|
|
|
|
nsStyleContext* aParentContext,
|
|
|
|
const StyleDisplay aDisplay)
|
2014-11-20 21:24:10 +03:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> undisplayedContext;
|
2016-02-24 10:01:10 +03:00
|
|
|
nsStyleSet* styleSet = StyleSet();
|
2015-08-05 15:42:20 +03:00
|
|
|
if (MustRestyleSelf(thisChildHint, element)) {
|
2014-11-20 21:24:10 +03:00
|
|
|
undisplayedContext =
|
2014-11-20 21:24:10 +03:00
|
|
|
styleSet->ResolveStyleFor(element, aParentContext, mTreeMatchContext);
|
2015-08-06 02:16:00 +03:00
|
|
|
} else if (CanReparentStyleContext(thisChildHint)) {
|
|
|
|
undisplayedContext =
|
|
|
|
styleSet->ReparentStyleContext(undisplayed->mStyle,
|
|
|
|
aParentContext,
|
|
|
|
element);
|
|
|
|
} else {
|
2014-11-20 21:24:10 +03:00
|
|
|
// 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.
|
2015-08-05 15:42:20 +03:00
|
|
|
nsRestyleHint rshint = thisChildHint & ~eRestyle_SomeDescendants;
|
2014-11-20 21:24:10 +03:00
|
|
|
undisplayedContext =
|
2015-02-17 01:15:05 +03:00
|
|
|
styleSet->ResolveStyleWithReplacement(element, nullptr,
|
2014-11-20 21:24:10 +03:00
|
|
|
aParentContext,
|
2014-11-20 21:24:10 +03:00
|
|
|
undisplayed->mStyle,
|
2015-08-05 15:42:20 +03:00
|
|
|
rshint);
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
|
|
|
|
if (display->mDisplay != aDisplay) {
|
|
|
|
NS_ASSERTION(element, "Must have undisplayed content");
|
|
|
|
mChangeList->AppendChange(nullptr, element,
|
2016-07-06 08:06:14 +03:00
|
|
|
nsChangeHint_ReconstructFrame);
|
2014-11-20 21:24:10 +03:00
|
|
|
// 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;
|
|
|
|
|
2016-08-28 05:31:50 +03:00
|
|
|
if (aDisplay == StyleDisplay::Contents) {
|
2014-11-20 21:24:10 +03:00
|
|
|
DoRestyleUndisplayedDescendants(aChildRestyleHint, element,
|
|
|
|
undisplayed->mStyle);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
void
|
2014-08-25 08:48:21 +04:00
|
|
|
ElementRestyler::MaybeReframeForBeforePseudo()
|
2014-11-20 21:24:10 +03:00
|
|
|
{
|
2016-02-17 01:07:00 +03:00
|
|
|
MaybeReframeForPseudo(CSSPseudoElementType::before,
|
2015-08-28 23:13:48 +03:00
|
|
|
mFrame, mFrame, mFrame->GetContent(),
|
|
|
|
mFrame->StyleContext());
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
/**
|
|
|
|
* aFrame is the last continuation or block-in-inline sibling that this
|
|
|
|
* ElementRestyler is restyling.
|
|
|
|
*/
|
2013-07-31 04:36:11 +04:00
|
|
|
void
|
2014-08-25 08:48:21 +04:00
|
|
|
ElementRestyler::MaybeReframeForAfterPseudo(nsIFrame* aFrame)
|
2014-11-20 21:24:10 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aFrame);
|
2016-02-17 01:07:00 +03:00
|
|
|
MaybeReframeForPseudo(CSSPseudoElementType::after,
|
2015-08-28 23:13:48 +03:00
|
|
|
aFrame, aFrame, aFrame->GetContent(),
|
|
|
|
aFrame->StyleContext());
|
2014-11-20 21:24:10 +03:00
|
|
|
}
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
bool
|
|
|
|
ElementRestyler::MustReframeForBeforePseudo()
|
|
|
|
{
|
2016-02-17 01:07:00 +03:00
|
|
|
return MustReframeForPseudo(CSSPseudoElementType::before,
|
2015-08-28 23:13:48 +03:00
|
|
|
mFrame, mFrame, mFrame->GetContent(),
|
|
|
|
mFrame->StyleContext());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ElementRestyler::MustReframeForAfterPseudo(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aFrame);
|
2016-02-17 01:07:00 +03:00
|
|
|
return MustReframeForPseudo(CSSPseudoElementType::after,
|
2015-08-28 23:13:48 +03:00
|
|
|
aFrame, aFrame, aFrame->GetContent(),
|
|
|
|
aFrame->StyleContext());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
void
|
2016-02-17 23:37:00 +03:00
|
|
|
ElementRestyler::MaybeReframeForPseudo(CSSPseudoElementType aPseudoType,
|
2015-08-28 23:13:48 +03:00
|
|
|
nsIFrame* aGenConParentFrame,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aStyleContext)
|
2013-07-31 04:36:11 +04:00
|
|
|
{
|
2015-08-28 23:13:48 +03:00
|
|
|
if (MustReframeForPseudo(aPseudoType, aGenConParentFrame, aFrame, aContent,
|
|
|
|
aStyleContext)) {
|
|
|
|
// Have to create the new ::before/::after frame.
|
|
|
|
LOG_RESTYLE("MaybeReframeForPseudo, appending "
|
|
|
|
"nsChangeHint_ReconstructFrame");
|
2016-05-23 06:26:03 +03:00
|
|
|
mHintsHandled |= nsChangeHint_ReconstructFrame;
|
2015-08-28 23:13:48 +03:00
|
|
|
mChangeList->AppendChange(aFrame, aContent, nsChangeHint_ReconstructFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2016-02-17 23:37:00 +03:00
|
|
|
ElementRestyler::MustReframeForPseudo(CSSPseudoElementType aPseudoType,
|
2015-08-28 23:13:48 +03:00
|
|
|
nsIFrame* aGenConParentFrame,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aStyleContext)
|
|
|
|
{
|
2016-02-17 01:07:00 +03:00
|
|
|
MOZ_ASSERT(aPseudoType == CSSPseudoElementType::before ||
|
|
|
|
aPseudoType == CSSPseudoElementType::after);
|
2015-08-28 23:13:48 +03:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::before) {
|
2015-08-28 23:13:48 +03:00
|
|
|
// 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;
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
}
|
2015-08-28 23:13:48 +03:00
|
|
|
|
|
|
|
// 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);
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
void
|
2014-11-20 21:24:10 +03:00
|
|
|
ElementRestyler::InitializeAccessibilityNotifications(nsStyleContext* aNewContext)
|
2013-07-31 04:36:11 +04:00
|
|
|
{
|
2013-07-20 23:14:25 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:12 +04:00
|
|
|
// 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() &&
|
2014-11-20 21:24:10 +03:00
|
|
|
(!mFrame ||
|
|
|
|
(!mFrame->GetPrevContinuation() &&
|
|
|
|
!mFrame->FrameIsNonFirstInIBSplit()))) {
|
2013-07-31 04:36:12 +04:00
|
|
|
if (mDesiredA11yNotifications == eSendAllNotifications) {
|
2014-11-20 21:24:10 +03:00
|
|
|
bool isFrameVisible = aNewContext->StyleVisibility()->IsVisible();
|
2013-07-31 04:36:12 +04:00
|
|
|
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.
|
2013-07-31 04:36:10 +04:00
|
|
|
mKidsDesiredA11yNotifications = eSkipNotifications;
|
2013-07-31 04:36:12 +04:00
|
|
|
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;
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
} else if (mDesiredA11yNotifications == eNotifyIfShown &&
|
2014-11-20 21:24:10 +03:00
|
|
|
aNewContext->StyleVisibility()->IsVisible()) {
|
|
|
|
// Notify a11y that element stayed visible while its parent was hidden.
|
|
|
|
nsIContent* c = mFrame ? mFrame->GetContent() : mContent;
|
|
|
|
mVisibleKidsOfHiddenElement.AppendElement(c);
|
2013-07-31 04:36:12 +04:00
|
|
|
mKidsDesiredA11yNotifications = eSkipNotifications;
|
|
|
|
}
|
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
#endif
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
// The structure of this method parallels ConditionallyRestyleContentChildren.
|
|
|
|
// If you update this method, you probably want to update that one too.
|
2013-07-31 04:36:11 +04:00
|
|
|
void
|
2013-09-25 23:28:07 +04:00
|
|
|
ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
|
|
|
|
nsRestyleHint aChildRestyleHint)
|
2013-07-31 04:36:11 +04:00
|
|
|
{
|
2014-09-25 09:45:36 +04:00
|
|
|
LOG_RESTYLE("RestyleContentChildren");
|
|
|
|
|
2013-09-25 23:28:07 +04:00
|
|
|
nsIFrame::ChildListIterator lists(aParent);
|
2013-11-17 10:51:04 +04:00
|
|
|
TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext);
|
|
|
|
if (!lists.IsDone()) {
|
|
|
|
ancestorPusher.PushAncestorAndStyleScope(mContent);
|
|
|
|
}
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
2015-09-22 21:21:44 +03:00
|
|
|
for (nsIFrame* child : lists.CurrentList()) {
|
2013-09-25 23:28:07 +04:00
|
|
|
// 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)) {
|
2013-07-31 04:36:12 +04:00
|
|
|
// 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.
|
2013-07-31 04:36:12 +04:00
|
|
|
|
2013-07-31 04:36:12 +04:00
|
|
|
// Check if the frame has a content because |child| may be a
|
|
|
|
// nsPageFrame that does not have a content.
|
2013-07-31 04:36:12 +04:00
|
|
|
nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
|
2013-11-17 10:51:04 +04:00
|
|
|
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
|
2013-12-02 14:26:12 +04:00
|
|
|
if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
2013-11-17 10:51:04 +04:00
|
|
|
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
// 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");
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
// |nsFrame::GetParentStyleContext| checks being out
|
2013-07-31 04:36:12 +04:00
|
|
|
// of flow so that this works correctly.
|
|
|
|
do {
|
2013-09-25 23:28:07 +04:00
|
|
|
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;
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
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);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// XXX need to do overflow frames???
|
2013-07-31 04:36:11 +04:00
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
void
|
|
|
|
ElementRestyler::SendAccessibilityNotifications()
|
|
|
|
{
|
2013-07-20 23:14:25 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:12 +04:00
|
|
|
// Send notifications about visibility changes.
|
|
|
|
if (mOurA11yNotification == eNotifyShown) {
|
|
|
|
nsAccessibilityService* accService = nsIPresShell::AccService();
|
|
|
|
if (accService) {
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIPresShell* presShell = mPresContext->GetPresShell();
|
|
|
|
nsIContent* content = mFrame ? mFrame->GetContent() : mContent;
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
accService->ContentRangeInserted(presShell, content->GetParent(),
|
|
|
|
content,
|
|
|
|
content->GetNextSibling());
|
|
|
|
}
|
|
|
|
} else if (mOurA11yNotification == eNotifyHidden) {
|
|
|
|
nsAccessibilityService* accService = nsIPresShell::AccService();
|
|
|
|
if (accService) {
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIPresShell* presShell = mPresContext->GetPresShell();
|
|
|
|
nsIContent* content = mFrame ? mFrame->GetContent() : mContent;
|
2014-09-20 04:02:30 +04:00
|
|
|
accService->ContentRemoved(presShell, content);
|
2013-07-31 04:36:12 +04:00
|
|
|
|
|
|
|
// 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());
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
2013-07-31 04:36:12 +04:00
|
|
|
mVisibleKidsOfHiddenElement.Clear();
|
|
|
|
}
|
|
|
|
}
|
2013-07-20 23:14:25 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-02-18 01:28:53 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-14 02:39:00 +04:00
|
|
|
void
|
2015-08-05 15:42:20 +03:00
|
|
|
RestyleManager::ComputeAndProcessStyleChange(nsIFrame* aFrame,
|
|
|
|
nsChangeHint aMinChange,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData)
|
2014-08-14 02:39:00 +04:00
|
|
|
{
|
2015-01-14 08:03:13 +03:00
|
|
|
MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
|
2014-08-14 02:39:00 +04:00
|
|
|
nsStyleChangeList changeList;
|
2015-02-18 01:28:53 +03:00
|
|
|
nsTArray<ElementRestyler::ContextToClear> contextsToClear;
|
2015-04-15 01:13:45 +03:00
|
|
|
|
|
|
|
// swappedStructOwners needs to be kept alive until after
|
|
|
|
// ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
|
|
|
|
// calls; see comment in ElementRestyler::Restyle.
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
|
2015-04-15 01:13:45 +03:00
|
|
|
ElementRestyler::ComputeStyleChangeFor(aFrame, &changeList, aMinChange,
|
|
|
|
aRestyleTracker, aRestyleHint,
|
2015-08-05 15:42:20 +03:00
|
|
|
aRestyleHintData,
|
2015-04-15 01:13:45 +03:00
|
|
|
contextsToClear, swappedStructOwners);
|
|
|
|
ProcessRestyledFrames(changeList);
|
2015-02-18 01:28:53 +03:00
|
|
|
ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
|
2014-08-14 02:39:00 +04:00
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
void
|
2015-08-05 15:42:20 +03:00
|
|
|
RestyleManager::ComputeAndProcessStyleChange(nsStyleContext* aNewContext,
|
|
|
|
Element* aElement,
|
|
|
|
nsChangeHint aMinChange,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData)
|
2013-07-20 23:14:25 +04:00
|
|
|
{
|
2015-01-14 08:03:13 +03:00
|
|
|
MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
|
2016-08-28 05:31:50 +03:00
|
|
|
MOZ_ASSERT(aNewContext->StyleDisplay()->mDisplay == StyleDisplay::Contents);
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIFrame* frame = GetNearestAncestorFrame(aElement);
|
|
|
|
MOZ_ASSERT(frame, "display:contents node in map although it's a "
|
|
|
|
"display:none descendant?");
|
2013-07-20 23:14:25 +04:00
|
|
|
TreeMatchContext treeMatchContext(true,
|
|
|
|
nsRuleWalker::eRelevantLinkUnvisited,
|
2014-11-20 21:24:10 +03:00
|
|
|
frame->PresContext()->Document());
|
|
|
|
nsIContent* parent = aElement->GetParent();
|
|
|
|
Element* parentElement =
|
|
|
|
parent && parent->IsElement() ? parent->AsElement() : nullptr;
|
|
|
|
treeMatchContext.InitAncestors(parentElement);
|
2015-08-05 15:42:20 +03:00
|
|
|
|
|
|
|
nsTArray<nsCSSSelector*> selectorsForDescendants;
|
2013-07-20 23:14:25 +04:00
|
|
|
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
|
2015-02-18 01:28:53 +03:00
|
|
|
nsTArray<ElementRestyler::ContextToClear> contextsToClear;
|
2015-04-15 01:13:45 +03:00
|
|
|
|
|
|
|
// swappedStructOwners needs to be kept alive until after
|
|
|
|
// ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
|
|
|
|
// calls; see comment in ElementRestyler::Restyle.
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
|
2015-04-15 01:13:45 +03:00
|
|
|
nsStyleChangeList changeList;
|
|
|
|
ElementRestyler r(frame->PresContext(), aElement, &changeList, aMinChange,
|
2015-08-05 15:42:20 +03:00
|
|
|
aRestyleTracker, selectorsForDescendants, treeMatchContext,
|
2015-04-15 01:13:45 +03:00
|
|
|
visibleKidsOfHiddenElement, contextsToClear,
|
|
|
|
swappedStructOwners);
|
|
|
|
r.RestyleChildrenOfDisplayContentsElement(frame, aNewContext, aMinChange,
|
2015-08-05 15:42:20 +03:00
|
|
|
aRestyleTracker,
|
|
|
|
aRestyleHint, aRestyleHintData);
|
2015-04-15 01:13:45 +03:00
|
|
|
ProcessRestyledFrames(changeList);
|
2015-02-18 01:28:53 +03:00
|
|
|
ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
|
2013-07-20 23:14:25 +04:00
|
|
|
}
|
|
|
|
|
2016-02-24 10:01:10 +03:00
|
|
|
nsStyleSet*
|
|
|
|
ElementRestyler::StyleSet() const
|
|
|
|
{
|
2016-02-24 10:01:11 +03:00
|
|
|
MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(),
|
|
|
|
"ElementRestyler should only be used with a Gecko-flavored "
|
|
|
|
"style backend");
|
|
|
|
return mPresContext->StyleSet()->AsGecko();
|
2016-02-24 10:01:10 +03:00
|
|
|
}
|
|
|
|
|
2014-11-20 21:24:09 +03:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-01 03:13:57 +04:00
|
|
|
#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
|
|
|
|
|
2015-05-19 02:03:04 +03:00
|
|
|
#ifdef DEBUG
|
2014-09-25 09:45:36 +04:00
|
|
|
/* 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) {
|
2016-07-19 16:10:59 +03:00
|
|
|
case RestyleResult::eStop:
|
|
|
|
result.AssignLiteral("RestyleResult::eStop");
|
2014-09-25 09:45:36 +04:00
|
|
|
break;
|
2016-07-19 16:10:59 +03:00
|
|
|
case RestyleResult::eStopWithStyleChange:
|
|
|
|
result.AssignLiteral("RestyleResult::eStopWithStyleChange");
|
2015-08-28 23:13:48 +03:00
|
|
|
break;
|
2016-07-19 16:10:59 +03:00
|
|
|
case RestyleResult::eContinue:
|
|
|
|
result.AssignLiteral("RestyleResult::eContinue");
|
2014-09-25 09:45:36 +04:00
|
|
|
break;
|
2016-07-19 16:10:59 +03:00
|
|
|
case RestyleResult::eContinueAndForceDescendants:
|
|
|
|
result.AssignLiteral("RestyleResult::eContinueAndForceDescendants");
|
2014-09-25 09:45:36 +04:00
|
|
|
break;
|
|
|
|
default:
|
2016-07-19 16:10:59 +03:00
|
|
|
MOZ_ASSERT(aRestyleResult == RestyleResult::eNone,
|
2016-07-19 16:10:59 +03:00
|
|
|
"Unexpected RestyleResult");
|
2014-09-25 09:45:36 +04:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-20 23:14:24 +04:00
|
|
|
} // namespace mozilla
|