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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef mozilla_RestyleManager_h
|
|
|
|
#define mozilla_RestyleManager_h
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
#include "mozilla/RestyleLogging.h"
|
2016-07-08 10:08:46 +03:00
|
|
|
#include "mozilla/RestyleManagerBase.h"
|
2013-07-20 23:14:24 +04:00
|
|
|
#include "nsISupportsImpl.h"
|
2013-07-20 23:14:25 +04:00
|
|
|
#include "nsChangeHint.h"
|
|
|
|
#include "RestyleTracker.h"
|
|
|
|
#include "nsPresContext.h"
|
2014-07-25 08:35:34 +04:00
|
|
|
#include "nsRefreshDriver.h"
|
2014-08-14 02:39:01 +04:00
|
|
|
#include "nsRefPtrHashtable.h"
|
2015-02-17 01:15:04 +03:00
|
|
|
#include "nsTransitionManager.h"
|
2013-07-20 23:14:24 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
class nsIFrame;
|
2014-06-12 21:09:31 +04:00
|
|
|
class nsStyleChangeList;
|
2013-07-20 23:14:25 +04:00
|
|
|
struct TreeMatchContext;
|
2013-07-20 23:14:24 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
2016-02-17 23:37:00 +03:00
|
|
|
enum class CSSPseudoElementType : uint8_t;
|
2014-04-03 08:18:36 +04:00
|
|
|
class EventStates;
|
2014-11-20 21:24:10 +03:00
|
|
|
struct UndisplayedNode;
|
2013-07-20 23:14:24 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
namespace dom {
|
|
|
|
class Element;
|
|
|
|
} // namespace dom
|
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
class RestyleManager final : public RestyleManagerBase
|
2014-11-20 21:24:09 +03:00
|
|
|
{
|
2013-07-20 23:14:24 +04:00
|
|
|
public:
|
2016-08-01 23:31:57 +03:00
|
|
|
typedef RestyleManagerBase base_type;
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
friend class RestyleTracker;
|
2016-08-01 23:31:57 +03:00
|
|
|
friend class ElementRestyler;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2014-09-01 07:36:37 +04:00
|
|
|
explicit RestyleManager(nsPresContext* aPresContext);
|
2013-07-20 23:14:24 +04:00
|
|
|
|
2014-03-21 05:16:20 +04:00
|
|
|
private:
|
|
|
|
// Private destructor, to discourage deletion outside of Release():
|
|
|
|
~RestyleManager()
|
|
|
|
{
|
2014-08-14 02:39:01 +04:00
|
|
|
MOZ_ASSERT(!mReframingStyleContexts,
|
|
|
|
"temporary member should be nulled out before destruction");
|
2015-09-15 00:42:00 +03:00
|
|
|
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
|
|
|
|
"leaving dangling pointers from AnimationsWithDestroyedFrame");
|
2014-03-21 05:16:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2013-07-20 23:14:24 +04:00
|
|
|
NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// Forwarded nsIDocumentObserver method, to handle restyling (and
|
|
|
|
// passing the notification to the frame).
|
|
|
|
nsresult ContentStateChanged(nsIContent* aContent,
|
2014-04-03 08:18:36 +04:00
|
|
|
EventStates aStateMask);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// Forwarded nsIMutationObserver method, to handle restyling.
|
|
|
|
void 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
|
|
|
// Forwarded nsIMutationObserver method, to handle restyling (and
|
|
|
|
// passing the notification to the frame).
|
|
|
|
void 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
|
|
|
|
|
|
|
// Get a counter that increments on every style change, that we use to
|
|
|
|
// track whether off-main-thread animations are up-to-date.
|
|
|
|
uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
|
|
|
|
|
2016-01-06 05:04:05 +03:00
|
|
|
static uint64_t GetAnimationGenerationForFrame(nsIFrame* aFrame);
|
2014-11-17 07:46:00 +03:00
|
|
|
|
2014-11-17 07:45:59 +03:00
|
|
|
// Update the animation generation count to mark that animation state
|
|
|
|
// has changed.
|
|
|
|
//
|
|
|
|
// This is normally performed automatically by ProcessPendingRestyles
|
|
|
|
// but it is also called when we have out-of-band changes to animations
|
|
|
|
// such as changes made through the Web Animations API.
|
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
|
|
|
void IncrementAnimationGeneration() {
|
|
|
|
// We update the animation generation at start of each call to
|
|
|
|
// ProcessPendingRestyles so we should ignore any subsequent (redundant)
|
|
|
|
// calls that occur while we are still processing restyles.
|
|
|
|
if (!mIsProcessingRestyles) {
|
|
|
|
++mAnimationGeneration;
|
|
|
|
}
|
|
|
|
}
|
2014-11-17 07:45:59 +03:00
|
|
|
|
2014-10-03 08:53:23 +04:00
|
|
|
// Whether rule matching should skip styles associated with animation
|
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
|
|
|
bool SkipAnimationRules() const { return mSkipAnimationRules; }
|
2014-10-03 08:53:23 +04:00
|
|
|
|
2015-02-17 01:15:01 +03:00
|
|
|
void SetSkipAnimationRules(bool aSkipAnimationRules) {
|
|
|
|
mSkipAnimationRules = aSkipAnimationRules;
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
/**
|
|
|
|
* Reparent the style contexts of this frame subtree. The parent frame of
|
|
|
|
* aFrame must be changed to the new parent before this function is called;
|
|
|
|
* the new parent style context will be automatically computed based on the
|
|
|
|
* new position in the frame tree.
|
|
|
|
*
|
|
|
|
* @param aFrame the root of the subtree to reparent. Must not be null.
|
|
|
|
*/
|
2014-06-02 16:08:21 +04:00
|
|
|
nsresult ReparentStyleContext(nsIFrame* aFrame);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-08-05 15:42:21 +03:00
|
|
|
void ClearSelectors() {
|
|
|
|
mPendingRestyles.ClearSelectors();
|
|
|
|
}
|
|
|
|
|
2014-08-14 02:39:00 +04:00
|
|
|
private:
|
2014-11-20 21:24:10 +03:00
|
|
|
// Used when restyling an element with a frame.
|
2015-08-05 15:42:20 +03:00
|
|
|
void ComputeAndProcessStyleChange(nsIFrame* aFrame,
|
|
|
|
nsChangeHint aMinChange,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData);
|
2016-07-08 10:08:46 +03:00
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
// Used when restyling a display:contents element.
|
2015-08-05 15:42:20 +03:00
|
|
|
void ComputeAndProcessStyleChange(nsStyleContext* aNewContext,
|
|
|
|
Element* aElement,
|
|
|
|
nsChangeHint aMinChange,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2014-08-14 02:39:00 +04:00
|
|
|
public:
|
|
|
|
|
2014-08-14 02:39:01 +04:00
|
|
|
/**
|
|
|
|
* In order to start CSS transitions on elements that are being
|
|
|
|
* reframed, we need to stash their style contexts somewhere during
|
|
|
|
* the reframing process.
|
|
|
|
*
|
|
|
|
* In all cases, the content node in the hash table is the real
|
|
|
|
* content node, not the anonymous content node we create for ::before
|
2014-08-14 02:39:01 +04:00
|
|
|
* or ::after. The content node passed to the Get and Put methods is,
|
|
|
|
* however, the content node to be associate with the frame's style
|
|
|
|
* context.
|
2014-08-14 02:39:01 +04:00
|
|
|
*/
|
|
|
|
typedef nsRefPtrHashtable<nsRefPtrHashKey<nsIContent>, nsStyleContext>
|
|
|
|
ReframingStyleContextTable;
|
2015-03-21 19:28:04 +03:00
|
|
|
class MOZ_STACK_CLASS ReframingStyleContexts final {
|
2014-08-14 02:39:01 +04:00
|
|
|
public:
|
2015-01-14 08:03:13 +03:00
|
|
|
/**
|
|
|
|
* Construct a ReframingStyleContexts object. The caller must
|
|
|
|
* ensure that aRestyleManager lives at least as long as the
|
|
|
|
* object. (This is generally easy since the caller is typically a
|
|
|
|
* method of RestyleManager.)
|
|
|
|
*/
|
|
|
|
explicit ReframingStyleContexts(RestyleManager* aRestyleManager);
|
2015-01-14 08:03:13 +03:00
|
|
|
~ReframingStyleContexts();
|
2015-01-14 08:03:13 +03:00
|
|
|
|
2014-08-14 02:39:01 +04:00
|
|
|
void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
|
|
|
|
MOZ_ASSERT(aContent);
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
|
2016-02-17 01:07:00 +03:00
|
|
|
if (pseudoType == CSSPseudoElementType::NotPseudo) {
|
2014-08-14 02:39:01 +04:00
|
|
|
mElementContexts.Put(aContent, aStyleContext);
|
2016-02-17 01:07:00 +03:00
|
|
|
} else if (pseudoType == CSSPseudoElementType::before) {
|
2015-03-03 14:09:00 +03:00
|
|
|
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
|
2014-08-14 02:39:01 +04:00
|
|
|
mBeforePseudoContexts.Put(aContent->GetParent(), aStyleContext);
|
2016-02-17 01:07:00 +03:00
|
|
|
} else if (pseudoType == CSSPseudoElementType::after) {
|
2015-03-03 14:09:00 +03:00
|
|
|
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
|
2014-08-14 02:39:01 +04:00
|
|
|
mAfterPseudoContexts.Put(aContent->GetParent(), aStyleContext);
|
|
|
|
}
|
|
|
|
}
|
2014-08-14 02:39:02 +04:00
|
|
|
|
|
|
|
nsStyleContext* Get(nsIContent* aContent,
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType aPseudoType) {
|
2014-08-14 02:39:02 +04:00
|
|
|
MOZ_ASSERT(aContent);
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
|
2014-08-14 02:39:02 +04:00
|
|
|
return mElementContexts.GetWeak(aContent);
|
|
|
|
}
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::before) {
|
2015-03-03 14:09:00 +03:00
|
|
|
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
|
2014-08-14 02:39:02 +04:00
|
|
|
return mBeforePseudoContexts.GetWeak(aContent->GetParent());
|
|
|
|
}
|
2016-02-17 01:07:00 +03:00
|
|
|
if (aPseudoType == CSSPseudoElementType::after) {
|
2015-03-03 14:09:00 +03:00
|
|
|
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
|
2014-08-14 02:39:02 +04:00
|
|
|
return mAfterPseudoContexts.GetWeak(aContent->GetParent());
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(false, "unexpected aPseudoType");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-08-14 02:39:01 +04:00
|
|
|
private:
|
2015-01-14 08:03:13 +03:00
|
|
|
RestyleManager* mRestyleManager;
|
2015-01-14 08:03:13 +03:00
|
|
|
AutoRestore<ReframingStyleContexts*> mRestorePointer;
|
2014-08-14 02:39:01 +04:00
|
|
|
ReframingStyleContextTable mElementContexts;
|
|
|
|
ReframingStyleContextTable mBeforePseudoContexts;
|
|
|
|
ReframingStyleContextTable mAfterPseudoContexts;
|
|
|
|
};
|
|
|
|
|
2014-08-14 02:39:01 +04:00
|
|
|
/**
|
|
|
|
* Return the current ReframingStyleContexts struct, or null if we're
|
|
|
|
* not currently in a restyling operation.
|
|
|
|
*/
|
|
|
|
ReframingStyleContexts* GetReframingStyleContexts() {
|
|
|
|
return mReframingStyleContexts;
|
|
|
|
}
|
|
|
|
|
2014-08-14 02:39:01 +04:00
|
|
|
/**
|
|
|
|
* Try starting a transition for an element or a ::before or ::after
|
|
|
|
* pseudo-element, given an old and new style context. This may
|
2015-03-04 08:08:00 +03:00
|
|
|
* change the new style context if a transition is started. Returns
|
|
|
|
* true iff it does change aNewStyleContext.
|
2014-08-14 02:39:01 +04:00
|
|
|
*
|
|
|
|
* For the pseudo-elements, aContent must be the anonymous content
|
|
|
|
* that we're creating for that pseudo-element, not the real element.
|
|
|
|
*/
|
2015-03-04 08:08:00 +03:00
|
|
|
static bool
|
2014-08-14 02:39:01 +04:00
|
|
|
TryStartingTransition(nsPresContext* aPresContext, nsIContent* aContent,
|
|
|
|
nsStyleContext* aOldStyleContext,
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext>* aNewStyleContext /* inout */);
|
2014-08-14 02:39:01 +04:00
|
|
|
|
2016-04-10 22:28:00 +03:00
|
|
|
// AnimationsWithDestroyedFrame is used to stop animations and transitions
|
|
|
|
// on elements that have no frame at the end of the restyling process.
|
2015-09-15 00:42:00 +03:00
|
|
|
// It only lives during the restyling process.
|
|
|
|
class MOZ_STACK_CLASS AnimationsWithDestroyedFrame final {
|
|
|
|
public:
|
|
|
|
// Construct a AnimationsWithDestroyedFrame object. The caller must
|
|
|
|
// ensure that aRestyleManager lives at least as long as the
|
|
|
|
// object. (This is generally easy since the caller is typically a
|
|
|
|
// method of RestyleManager.)
|
|
|
|
explicit AnimationsWithDestroyedFrame(RestyleManager* aRestyleManager);
|
|
|
|
|
|
|
|
// This method takes the content node for the generated content for
|
2016-04-10 22:28:00 +03:00
|
|
|
// animation/transition on ::before and ::after, rather than the
|
|
|
|
// content node for the real element.
|
2015-09-15 00:42:00 +03:00
|
|
|
void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
|
|
|
|
MOZ_ASSERT(aContent);
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
|
2016-02-17 01:07:00 +03:00
|
|
|
if (pseudoType == CSSPseudoElementType::NotPseudo) {
|
2015-09-15 00:42:00 +03:00
|
|
|
mContents.AppendElement(aContent);
|
2016-02-17 01:07:00 +03:00
|
|
|
} else if (pseudoType == CSSPseudoElementType::before) {
|
2015-09-15 00:42:00 +03:00
|
|
|
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
|
|
|
|
mBeforeContents.AppendElement(aContent->GetParent());
|
2016-02-17 01:07:00 +03:00
|
|
|
} else if (pseudoType == CSSPseudoElementType::after) {
|
2015-09-15 00:42:00 +03:00
|
|
|
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
|
|
|
|
mAfterContents.AppendElement(aContent->GetParent());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void StopAnimationsForElementsWithoutFrames();
|
|
|
|
|
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
void StopAnimationsWithoutFrame(nsTArray<RefPtr<nsIContent>>& aArray,
|
2016-02-17 23:37:00 +03:00
|
|
|
CSSPseudoElementType aPseudoType);
|
2015-09-15 00:42:00 +03:00
|
|
|
|
|
|
|
RestyleManager* mRestyleManager;
|
|
|
|
AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
|
|
|
|
|
|
|
|
// Below three arrays might include elements that have already had their
|
2016-04-10 22:28:00 +03:00
|
|
|
// animations or transitions stopped.
|
2015-09-15 00:42:00 +03:00
|
|
|
//
|
|
|
|
// mBeforeContents and mAfterContents hold the real element rather than
|
|
|
|
// the content node for the generated content (which might change during
|
|
|
|
// a reframe)
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsIContent>> mContents;
|
|
|
|
nsTArray<RefPtr<nsIContent>> mBeforeContents;
|
|
|
|
nsTArray<RefPtr<nsIContent>> mAfterContents;
|
2015-09-15 00:42:00 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the current AnimationsWithDestroyedFrame struct, or null if we're
|
|
|
|
* not currently in a restyling operation.
|
|
|
|
*/
|
|
|
|
AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
|
|
|
|
return mAnimationsWithDestroyedFrame;
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
private:
|
|
|
|
void RestyleForEmptyChange(Element* aContainer);
|
|
|
|
|
|
|
|
public:
|
|
|
|
// Restyling for a ContentInserted (notification after insertion) or
|
|
|
|
// for a CharacterDataChanged. |aContainer| must be non-null; when
|
|
|
|
// the container is null, no work is needed.
|
|
|
|
void RestyleForInsertOrChange(Element* aContainer, nsIContent* aChild);
|
|
|
|
|
|
|
|
// This would be the same as RestyleForInsertOrChange if we got the
|
|
|
|
// notification before the removal. However, we get it after, so we need the
|
|
|
|
// following sibling in addition to the old child. |aContainer| must be
|
|
|
|
// non-null; when the container is null, no work is needed. aFollowingSibling
|
|
|
|
// is the sibling that used to come after aOldChild before the removal.
|
|
|
|
void RestyleForRemove(Element* aContainer,
|
|
|
|
nsIContent* aOldChild,
|
|
|
|
nsIContent* aFollowingSibling);
|
|
|
|
|
|
|
|
// Same for a ContentAppended. |aContainer| must be non-null; when
|
|
|
|
// the container is null, no work is needed.
|
|
|
|
void RestyleForAppend(Element* aContainer, nsIContent* aFirstNewContent);
|
|
|
|
|
|
|
|
// Process any pending restyles. This should be called after
|
|
|
|
// CreateNeededFrames.
|
|
|
|
// Note: It's the caller's responsibility to make sure to wrap a
|
|
|
|
// ProcessPendingRestyles call in a view update batch and a script blocker.
|
|
|
|
// This function does not call ProcessAttachedQueue() on the binding manager.
|
|
|
|
// If the caller wants that to happen synchronously, it needs to handle that
|
|
|
|
// itself.
|
|
|
|
void ProcessPendingRestyles();
|
|
|
|
|
2014-10-02 06:32:09 +04:00
|
|
|
// Returns whether there are any pending restyles.
|
|
|
|
bool HasPendingRestyles() { return mPendingRestyles.Count() != 0; }
|
|
|
|
|
2015-10-30 02:57:47 +03:00
|
|
|
private:
|
2013-07-31 04:36:08 +04:00
|
|
|
// ProcessPendingRestyles calls into one of our RestyleTracker
|
|
|
|
// objects. It then calls back to these functions at the beginning
|
|
|
|
// and end of its work.
|
2015-01-14 08:03:12 +03:00
|
|
|
void BeginProcessingRestyles(RestyleTracker& aRestyleTracker);
|
2013-07-31 04:36:08 +04:00
|
|
|
void EndProcessingRestyles();
|
|
|
|
|
2015-10-30 02:57:47 +03:00
|
|
|
public:
|
2014-07-25 08:35:34 +04:00
|
|
|
// Update styles for animations that are running on the compositor and
|
|
|
|
// whose updating is suppressed on the main thread (to save
|
|
|
|
// unnecessary work), while leaving all other aspects of style
|
|
|
|
// out-of-date.
|
2014-08-07 09:58:44 +04:00
|
|
|
//
|
|
|
|
// Performs an animation-only style flush to make styles from
|
|
|
|
// throttled transitions up-to-date prior to processing an unrelated
|
|
|
|
// style change, so that any transitions triggered by that style
|
|
|
|
// change produce correct results.
|
|
|
|
//
|
|
|
|
// In more detail: when we're able to run animations on the
|
|
|
|
// compositor, we sometimes "throttle" these animations by skipping
|
|
|
|
// updating style data on the main thread. However, whenever we
|
|
|
|
// process a normal (non-animation) style change, any changes in
|
|
|
|
// computed style on elements that have transition-* properties set
|
|
|
|
// may need to trigger new transitions; this process requires knowing
|
|
|
|
// both the old and new values of the property. To do this correctly,
|
|
|
|
// we need to have an up-to-date *old* value of the property on the
|
|
|
|
// primary frame. So the purpose of the mini-flush is to update the
|
|
|
|
// style for all throttled transitions and animations to the current
|
|
|
|
// animation state without making any other updates, so that when we
|
|
|
|
// process the queued style updates we'll have correct old data to
|
|
|
|
// compare against. When we do this, we don't bother touching frames
|
|
|
|
// other than primary frames.
|
2014-07-25 08:35:34 +04:00
|
|
|
void UpdateOnlyAnimationStyles();
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
// Rebuilds all style data by throwing out the old rule tree and
|
|
|
|
// building a new one, and additionally applying aExtraHint (which
|
|
|
|
// must not contain nsChangeHint_ReconstructFrame) to the root frame.
|
2014-10-09 01:26:57 +04:00
|
|
|
//
|
|
|
|
// aRestyleHint says which restyle hint to use for the computation;
|
|
|
|
// the only sensible values to use are eRestyle_Subtree (which says
|
|
|
|
// that the rebuild must run selector matching) and nsRestyleHint(0)
|
|
|
|
// (which says that rerunning selector matching is not required. (The
|
|
|
|
// method adds eRestyle_ForceDescendants internally, and including it
|
|
|
|
// in the restyle hint is harmless; some callers (e.g.,
|
|
|
|
// nsPresContext::MediaFeatureValuesChanged) might do this for their
|
|
|
|
// own reasons.)
|
|
|
|
void RebuildAllStyleData(nsChangeHint aExtraHint,
|
|
|
|
nsRestyleHint aRestyleHint);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
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
|
|
|
/**
|
|
|
|
* Notify the frame constructor that an element needs to have its
|
|
|
|
* style recomputed.
|
|
|
|
* @param aElement: The element to be restyled.
|
|
|
|
* @param aRestyleHint: Which nodes need to have selector matching run
|
|
|
|
* on them.
|
|
|
|
* @param aMinChangeHint: A minimum change hint for aContent and its
|
|
|
|
* descendants.
|
2015-08-05 15:42:20 +03:00
|
|
|
* @param aRestyleHintData: Additional data to go with aRestyleHint.
|
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
|
|
|
*/
|
2013-07-20 23:14:25 +04:00
|
|
|
void PostRestyleEvent(Element* aElement,
|
|
|
|
nsRestyleHint aRestyleHint,
|
2015-08-05 15:42:20 +03:00
|
|
|
nsChangeHint aMinChangeHint,
|
|
|
|
const RestyleHintData* aRestyleHintData = nullptr);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
void PostRestyleEventForLazyConstruction()
|
|
|
|
{
|
|
|
|
PostRestyleEventInternal(true);
|
|
|
|
}
|
|
|
|
|
2015-05-19 02:03:04 +03:00
|
|
|
#ifdef DEBUG
|
2014-09-25 09:45:36 +04:00
|
|
|
static nsCString ChangeHintToString(nsChangeHint aHint);
|
|
|
|
#endif
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Asynchronously clear style data from the root frame downwards and ensure
|
|
|
|
* it will all be rebuilt. This is safe to call anytime; it will schedule
|
|
|
|
* a restyle and take effect next time style changes are flushed.
|
|
|
|
* This method is used to recompute the style data when some change happens
|
|
|
|
* outside of any style rules, like a color preference change or a change
|
|
|
|
* in a system font size, or to fix things up when an optimization in the
|
|
|
|
* style data has become invalid. We assume that the root frame will not
|
|
|
|
* need to be reframed.
|
2014-10-09 01:27:02 +04:00
|
|
|
*
|
|
|
|
* For parameters, see RebuildAllStyleData.
|
2013-07-20 23:14:25 +04:00
|
|
|
*/
|
2014-10-09 01:27:02 +04:00
|
|
|
void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
|
|
|
nsRestyleHint aRestyleHint);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2016-02-20 05:20:24 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
bool InRebuildAllStyleData() const { return mInRebuildAllStyleData; }
|
|
|
|
#endif
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
/**
|
|
|
|
* Returns whether a restyle event currently being processed by this
|
|
|
|
* RestyleManager should be logged.
|
|
|
|
*/
|
|
|
|
bool ShouldLogRestyle() {
|
2016-07-08 10:08:46 +03:00
|
|
|
return ShouldLogRestyle(PresContext());
|
2014-09-25 09:45:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether a restyle event currently being processed for the
|
|
|
|
* document with the specified nsPresContext should be logged.
|
|
|
|
*/
|
|
|
|
static bool ShouldLogRestyle(nsPresContext* aPresContext) {
|
|
|
|
return aPresContext->RestyleLoggingEnabled() &&
|
2015-02-17 01:15:04 +03:00
|
|
|
(!aPresContext->TransitionManager()->
|
|
|
|
InAnimationOnlyStyleUpdate() ||
|
2014-09-25 09:45:36 +04:00
|
|
|
AnimationRestyleLoggingEnabled());
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool RestyleLoggingInitiallyEnabled() {
|
|
|
|
static bool enabled = getenv("MOZ_DEBUG_RESTYLE") != 0;
|
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool AnimationRestyleLoggingEnabled() {
|
|
|
|
static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0;
|
|
|
|
return animations;
|
|
|
|
}
|
|
|
|
|
2014-10-01 03:13:57 +04:00
|
|
|
// Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of
|
|
|
|
// style struct names -- such as "Font,SVGReset" -- to log the style context
|
|
|
|
// tree and those cached struct pointers before each restyle. This
|
|
|
|
// function returns a bitfield of the structs named in the
|
|
|
|
// environment variable.
|
|
|
|
static uint32_t StructsToLog();
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
static nsCString StructNamesToString(uint32_t aSIDs);
|
|
|
|
int32_t& LoggingDepth() { return mLoggingDepth; }
|
|
|
|
#endif
|
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
private:
|
2016-07-08 10:08:46 +03:00
|
|
|
inline nsStyleSet* StyleSet() const {
|
|
|
|
MOZ_ASSERT(PresContext()->StyleSet()->IsGecko(),
|
|
|
|
"RestyleManager should only be used with a Gecko-flavored "
|
|
|
|
"style backend");
|
|
|
|
return PresContext()->StyleSet()->AsGecko();
|
|
|
|
}
|
2016-02-24 10:01:10 +03:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
/* aMinHint is the minimal change that should be made to the element */
|
|
|
|
// XXXbz do we really need the aPrimaryFrame argument here?
|
2013-07-20 23:14:25 +04:00
|
|
|
void RestyleElement(Element* aElement,
|
2013-07-20 23:14:25 +04:00
|
|
|
nsIFrame* aPrimaryFrame,
|
|
|
|
nsChangeHint aMinHint,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
2015-08-05 15:42:20 +03:00
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData& aRestyleHintData);
|
2013-07-20 23:14:25 +04:00
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
void StartRebuildAllStyleData(RestyleTracker& aRestyleTracker);
|
2015-01-14 08:03:12 +03:00
|
|
|
void FinishRebuildAllStyleData();
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
bool ShouldStartRebuildAllFor(RestyleTracker& aRestyleTracker) {
|
|
|
|
// When we process our primary restyle tracker and we have a pending
|
|
|
|
// rebuild-all, we need to process it.
|
|
|
|
return mDoRebuildAllStyleData &&
|
|
|
|
&aRestyleTracker == &mPendingRestyles;
|
|
|
|
}
|
|
|
|
|
2015-01-14 08:03:12 +03:00
|
|
|
void ProcessRestyles(RestyleTracker& aRestyleTracker) {
|
|
|
|
// Fast-path the common case (esp. for the animation restyle
|
|
|
|
// tracker) of not having anything to do.
|
2015-01-14 08:03:12 +03:00
|
|
|
if (aRestyleTracker.Count() || ShouldStartRebuildAllFor(aRestyleTracker)) {
|
2016-07-08 10:08:46 +03:00
|
|
|
IncrementRestyleGeneration();
|
2015-01-14 08:03:12 +03:00
|
|
|
aRestyleTracker.DoProcessRestyles();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-20 23:14:24 +04:00
|
|
|
private:
|
2015-01-14 08:03:11 +03:00
|
|
|
// True if we need to reconstruct the rule tree the next time we
|
|
|
|
// process restyles.
|
|
|
|
bool mDoRebuildAllStyleData : 1;
|
2015-01-14 08:03:12 +03:00
|
|
|
// True if we're currently in the process of reconstructing the rule tree.
|
|
|
|
bool mInRebuildAllStyleData : 1;
|
2014-10-03 08:53:23 +04:00
|
|
|
// Whether rule matching should skip styles associated with animation
|
|
|
|
bool mSkipAnimationRules : 1;
|
2015-02-17 01:15:02 +03:00
|
|
|
bool mHavePendingNonAnimationRestyles : 1;
|
2014-10-03 08:53:23 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
nsChangeHint mRebuildAllExtraHint;
|
2014-10-09 01:26:57 +04:00
|
|
|
nsRestyleHint mRebuildAllRestyleHint;
|
2013-07-20 23:14:25 +04:00
|
|
|
|
|
|
|
// The total number of animation flushes by this frame constructor.
|
|
|
|
// Used to keep the layer and animation manager in sync.
|
|
|
|
uint64_t mAnimationGeneration;
|
|
|
|
|
2014-08-14 02:39:01 +04:00
|
|
|
ReframingStyleContexts* mReframingStyleContexts;
|
2015-09-15 00:42:00 +03:00
|
|
|
AnimationsWithDestroyedFrame* mAnimationsWithDestroyedFrame;
|
2014-08-14 02:39:01 +04:00
|
|
|
|
2013-07-20 23:14:25 +04:00
|
|
|
RestyleTracker mPendingRestyles;
|
2014-09-25 09:45:36 +04:00
|
|
|
|
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
|
|
|
// Are we currently in the middle of a call to ProcessRestyles?
|
|
|
|
// This flag is used both as a debugging aid to assert that we are not
|
|
|
|
// performing nested calls to ProcessPendingRestyles, as well as to ignore
|
|
|
|
// redundant calls to IncrementAnimationGeneration.
|
2014-10-03 08:53:23 +04:00
|
|
|
bool mIsProcessingRestyles;
|
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
int32_t mLoggingDepth;
|
|
|
|
#endif
|
2013-07-20 23:14:24 +04:00
|
|
|
};
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
/**
|
|
|
|
* An ElementRestyler is created for *each* element in a subtree that we
|
|
|
|
* recompute styles for.
|
|
|
|
*/
|
2015-03-21 19:28:04 +03:00
|
|
|
class ElementRestyler final
|
2014-11-20 21:24:09 +03:00
|
|
|
{
|
2013-07-31 04:36:09 +04:00
|
|
|
public:
|
|
|
|
typedef mozilla::dom::Element Element;
|
|
|
|
|
2015-02-18 01:28:53 +03:00
|
|
|
struct ContextToClear {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> mStyleContext;
|
2015-02-18 01:28:53 +03:00
|
|
|
uint32_t mStructs;
|
|
|
|
};
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
// Construct for the root of the subtree that we're restyling.
|
2013-07-31 04:36:09 +04:00
|
|
|
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,
|
2015-02-18 01:28:53 +03:00
|
|
|
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement,
|
|
|
|
nsTArray<ContextToClear>& aContextsToClear,
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>>& aSwappedStructOwners);
|
2013-07-31 04:36:09 +04:00
|
|
|
|
|
|
|
// Construct for an element whose parent is being restyled.
|
2013-07-31 04:36:10 +04:00
|
|
|
enum ConstructorFlags {
|
|
|
|
FOR_OUT_OF_FLOW_CHILD = 1<<0
|
|
|
|
};
|
2013-07-31 04:36:09 +04:00
|
|
|
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
|
|
|
|
|
|
|
// Construct for a frame whose parent is being restyled, but whose
|
|
|
|
// style context is the parent style context for its parent frame.
|
|
|
|
// (This is only used for table frames, whose style contexts are used
|
2016-06-16 15:14:08 +03:00
|
|
|
// as the parent style context for their table wrapper frame. We should
|
|
|
|
// probably try to get rid of this exception and have the inheritance go
|
|
|
|
// the other way.)
|
2013-07-31 04:36:09 +04:00
|
|
|
enum ParentContextFromChildFrame { PARENT_CONTEXT_FROM_CHILD_FRAME };
|
|
|
|
ElementRestyler(ParentContextFromChildFrame,
|
2013-07-31 04:36:09 +04:00
|
|
|
const ElementRestyler& aParentFrameRestyler,
|
|
|
|
nsIFrame* aFrame);
|
2013-07-31 04:36:09 +04:00
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
// For restyling undisplayed content only (mFrame==null).
|
|
|
|
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,
|
2015-02-18 01:28:53 +03:00
|
|
|
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement,
|
|
|
|
nsTArray<ContextToClear>& aContextsToClear,
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>>& aSwappedStructOwners);
|
2014-11-20 21:24:10 +03:00
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
/**
|
|
|
|
* Restyle our frame's element and its subtree.
|
|
|
|
*
|
|
|
|
* Use eRestyle_Self for the aRestyleHint argument to mean
|
|
|
|
* "reresolve our style context but not kids", use eRestyle_Subtree
|
|
|
|
* to mean "reresolve our style context and kids", and use
|
|
|
|
* nsRestyleHint(0) to mean recompute a new style context for our
|
|
|
|
* current parent and existing rulenode, and the same for kids.
|
|
|
|
*/
|
2013-07-31 04:36:10 +04:00
|
|
|
void Restyle(nsRestyleHint aRestyleHint);
|
2013-07-31 04:36:09 +04:00
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
/**
|
|
|
|
* mHintsHandled changes over time; it starts off as the hints that
|
|
|
|
* have been handled by ancestors, and by the end of Restyle it
|
|
|
|
* represents the hints that have been handled for this frame. This
|
|
|
|
* method is intended to be called after Restyle, to find out what
|
|
|
|
* hints have been handled for this frame.
|
|
|
|
*/
|
|
|
|
nsChangeHint HintsHandledForFrame() { return mHintsHandled; }
|
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
/**
|
|
|
|
* Called from RestyleManager::ComputeAndProcessStyleChange to restyle
|
|
|
|
* children of a display:contents element.
|
|
|
|
*/
|
|
|
|
void RestyleChildrenOfDisplayContentsElement(nsIFrame* aParentFrame,
|
|
|
|
nsStyleContext* aNewContext,
|
|
|
|
nsChangeHint aMinHint,
|
|
|
|
RestyleTracker& aRestyleTracker,
|
2015-08-05 15:42:20 +03:00
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
const RestyleHintData&
|
|
|
|
aRestyleHintData);
|
2014-11-20 21:24:10 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Re-resolve the style contexts for a frame tree, building aChangeList
|
|
|
|
* based on the resulting style changes, plus aMinChange applied to aFrame.
|
|
|
|
*/
|
|
|
|
static void 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
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
bool ShouldLogRestyle() {
|
|
|
|
return RestyleManager::ShouldLogRestyle(mPresContext);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
private:
|
2016-02-24 10:01:10 +03:00
|
|
|
inline nsStyleSet* StyleSet() const;
|
|
|
|
|
2016-07-19 16:10:59 +03:00
|
|
|
// Enum class for the result of RestyleSelf, which indicates whether the
|
2014-09-05 07:48:45 +04:00
|
|
|
// restyle procedure should continue to the children, and how.
|
|
|
|
//
|
|
|
|
// These values must be ordered so that later values imply that all
|
|
|
|
// the work of the earlier values is also done.
|
2016-07-19 16:10:59 +03:00
|
|
|
enum class RestyleResult : uint8_t {
|
2016-07-19 16:10:59 +03:00
|
|
|
// default initial value
|
2016-07-19 16:10:59 +03:00
|
|
|
eNone,
|
2014-09-05 07:48:45 +04:00
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
// we left the old style context on the frame; do not restyle children
|
2016-07-19 16:10:59 +03:00
|
|
|
eStop,
|
2014-09-05 07:48:45 +04:00
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
// we got a new style context on this frame, but we know that children
|
|
|
|
// do not depend on the changed values; do not restyle children
|
2016-07-19 16:10:59 +03:00
|
|
|
eStopWithStyleChange,
|
2015-08-28 23:13:48 +03:00
|
|
|
|
2014-09-05 07:48:45 +04:00
|
|
|
// continue restyling children
|
2016-07-19 16:10:59 +03:00
|
|
|
eContinue,
|
2014-09-05 07:48:45 +04:00
|
|
|
|
|
|
|
// continue restyling children with eRestyle_ForceDescendants set
|
2016-07-19 16:10:59 +03:00
|
|
|
eContinueAndForceDescendants
|
2014-09-05 07:48:45 +04:00
|
|
|
};
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
struct SwapInstruction
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsStyleContext> mOldContext;
|
|
|
|
RefPtr<nsStyleContext> mNewContext;
|
2015-08-28 23:13:48 +03:00
|
|
|
uint32_t mStructsToSwap;
|
|
|
|
};
|
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
/**
|
|
|
|
* First half of Restyle().
|
|
|
|
*/
|
2014-09-05 07:48:47 +04:00
|
|
|
RestyleResult 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
|
|
|
|
|
|
|
/**
|
|
|
|
* Restyle the children of this frame (and, in turn, their children).
|
|
|
|
*
|
|
|
|
* Second half of Restyle().
|
|
|
|
*/
|
|
|
|
void RestyleChildren(nsRestyleHint aChildRestyleHint);
|
|
|
|
|
2015-08-05 15:42:20 +03:00
|
|
|
/**
|
|
|
|
* Returns true iff a selector in mSelectorsForDescendants matches aElement.
|
|
|
|
* This is called when processing a eRestyle_SomeDescendants restyle hint.
|
|
|
|
*/
|
|
|
|
bool SelectorMatchesForRestyle(Element* aElement);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true iff aRestyleHint indicates that we should be restyling.
|
|
|
|
* Specifically, this will return true when eRestyle_Self or
|
|
|
|
* eRestyle_Subtree is present, or if eRestyle_SomeDescendants is
|
|
|
|
* present and the specified element matches one of the selectors in
|
|
|
|
* mSelectorsForDescendants.
|
|
|
|
*/
|
|
|
|
bool MustRestyleSelf(nsRestyleHint aRestyleHint, Element* aElement);
|
|
|
|
|
2015-08-05 15:42:21 +03:00
|
|
|
/**
|
|
|
|
* Returns true iff aRestyleHint indicates that we can call
|
|
|
|
* ReparentStyleContext rather than any other restyling method of
|
|
|
|
* nsStyleSet that looks up a new rule node, and if we are
|
|
|
|
* not in the process of reconstructing the whole rule tree.
|
|
|
|
* This is used to check whether it is appropriate to call
|
|
|
|
* ReparentStyleContext.
|
|
|
|
*/
|
|
|
|
bool CanReparentStyleContext(nsRestyleHint aRestyleHint);
|
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
/**
|
|
|
|
* Helpers for Restyle().
|
|
|
|
*/
|
|
|
|
void AddLayerChangesForAnimation();
|
|
|
|
|
2015-08-28 23:13:48 +03:00
|
|
|
bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
|
|
|
|
nsStyleContext* aOldContext,
|
|
|
|
nsTArray<nsStyleContext*>& aContextsToMove);
|
|
|
|
bool MoveStyleContextsForChildren(nsStyleContext* aOldContext);
|
|
|
|
|
2013-07-31 04:36:11 +04:00
|
|
|
/**
|
2014-09-05 07:48:46 +04:00
|
|
|
* Helpers for RestyleSelf().
|
2013-07-31 04:36:11 +04:00
|
|
|
*/
|
2013-07-31 04:36:09 +04:00
|
|
|
void 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);
|
2015-08-28 23:13:48 +03:00
|
|
|
void ComputeRestyleResultFromFrame(nsIFrame* aSelf,
|
|
|
|
RestyleResult& aRestyleResult,
|
|
|
|
bool& aCanStopWithStyleChange);
|
|
|
|
void ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
|
|
|
nsStyleContext* aNewContext,
|
|
|
|
RestyleResult& aRestyleResult,
|
|
|
|
bool& aCanStopWithStyleChange);
|
2013-07-31 04:36:09 +04:00
|
|
|
|
2015-08-28 23:13:47 +03:00
|
|
|
// Helpers for RestyleChildren().
|
2014-11-20 21:24:10 +03:00
|
|
|
void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint);
|
2015-09-04 03:00:14 +03:00
|
|
|
bool MustCheckUndisplayedContent(nsIFrame* aFrame,
|
|
|
|
nsIContent*& aUndisplayedParent);
|
2015-08-28 23:13:47 +03:00
|
|
|
|
2014-11-20 21:24:10 +03:00
|
|
|
/**
|
|
|
|
* In the following two methods, aParentStyleContext is either
|
|
|
|
* mFrame->StyleContext() if we have a frame, or a display:contents
|
|
|
|
* style context if we don't.
|
|
|
|
*/
|
2014-11-20 21:24:10 +03:00
|
|
|
void DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
|
2014-11-20 21:24:10 +03:00
|
|
|
nsIContent* aParent,
|
|
|
|
nsStyleContext* aParentStyleContext);
|
2014-11-20 21:24:10 +03:00
|
|
|
void RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
|
|
|
|
UndisplayedNode* aUndisplayed,
|
|
|
|
nsIContent* aUndisplayedParent,
|
2014-11-20 21:24:10 +03:00
|
|
|
nsStyleContext* aParentStyleContext,
|
2014-11-20 21:24:10 +03:00
|
|
|
const uint8_t aDisplay);
|
2014-08-25 08:48:21 +04:00
|
|
|
void MaybeReframeForBeforePseudo();
|
|
|
|
void MaybeReframeForAfterPseudo(nsIFrame* aFrame);
|
2016-02-17 23:37:00 +03:00
|
|
|
void MaybeReframeForPseudo(CSSPseudoElementType aPseudoType,
|
2015-08-28 23:13:48 +03:00
|
|
|
nsIFrame* aGenConParentFrame,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aStyleContext);
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool MustReframeForBeforePseudo();
|
|
|
|
bool MustReframeForAfterPseudo(nsIFrame* aFrame);
|
|
|
|
#endif
|
2016-02-17 23:37:00 +03:00
|
|
|
bool MustReframeForPseudo(CSSPseudoElementType aPseudoType,
|
2015-08-28 23:13:48 +03:00
|
|
|
nsIFrame* aGenConParentFrame,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aStyleContext);
|
2013-09-25 23:28:07 +04:00
|
|
|
void RestyleContentChildren(nsIFrame* aParent,
|
|
|
|
nsRestyleHint aChildRestyleHint);
|
2014-11-20 21:24:10 +03:00
|
|
|
void InitializeAccessibilityNotifications(nsStyleContext* aNewContext);
|
2013-07-31 04:36:11 +04:00
|
|
|
void SendAccessibilityNotifications();
|
|
|
|
|
2013-07-31 04:36:10 +04:00
|
|
|
enum DesiredA11yNotifications {
|
|
|
|
eSkipNotifications,
|
|
|
|
eSendAllNotifications,
|
|
|
|
eNotifyIfShown
|
|
|
|
};
|
|
|
|
|
|
|
|
enum A11yNotificationType {
|
|
|
|
eDontNotify,
|
|
|
|
eNotifyShown,
|
|
|
|
eNotifyHidden
|
|
|
|
};
|
|
|
|
|
2015-09-04 03:00:14 +03:00
|
|
|
// These methods handle the eRestyle_SomeDescendants hint by traversing
|
|
|
|
// down the frame tree (and then when reaching undisplayed content,
|
|
|
|
// the flattened content tree) find elements that match a selector
|
|
|
|
// in mSelectorsForDescendants and call AddPendingRestyle for them.
|
|
|
|
void ConditionallyRestyleChildren();
|
|
|
|
void ConditionallyRestyleChildren(nsIFrame* aFrame,
|
|
|
|
Element* aRestyleRoot);
|
|
|
|
void ConditionallyRestyleContentChildren(nsIFrame* aFrame,
|
|
|
|
Element* aRestyleRoot);
|
|
|
|
void ConditionallyRestyleUndisplayedDescendants(nsIFrame* aFrame,
|
|
|
|
Element* aRestyleRoot);
|
|
|
|
void DoConditionallyRestyleUndisplayedDescendants(nsIContent* aParent,
|
|
|
|
Element* aRestyleRoot);
|
|
|
|
void ConditionallyRestyleUndisplayedNodes(UndisplayedNode* aUndisplayed,
|
|
|
|
nsIContent* aUndisplayedParent,
|
|
|
|
const uint8_t aDisplay,
|
|
|
|
Element* aRestyleRoot);
|
|
|
|
void ConditionallyRestyleContentDescendants(Element* aElement,
|
|
|
|
Element* aRestyleRoot);
|
|
|
|
bool ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot);
|
|
|
|
bool ConditionallyRestyle(Element* aElement, Element* aRestyleRoot);
|
2015-08-05 15:42:20 +03:00
|
|
|
|
2014-09-25 09:45:36 +04:00
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
int32_t& LoggingDepth() { return mLoggingDepth; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
static nsCString RestyleResultToString(RestyleResult aRestyleResult);
|
|
|
|
#endif
|
|
|
|
|
2013-07-31 04:36:09 +04:00
|
|
|
private:
|
|
|
|
nsPresContext* const mPresContext;
|
2013-07-31 04:36:09 +04:00
|
|
|
nsIFrame* const mFrame;
|
2013-07-31 04:36:09 +04:00
|
|
|
nsIContent* const mParentContent;
|
|
|
|
// |mContent| is the node that we used for rule matching of
|
|
|
|
// normal elements (not pseudo-elements) and for which we generate
|
|
|
|
// framechange hints if we need them.
|
|
|
|
nsIContent* const mContent;
|
2013-07-31 04:36:10 +04:00
|
|
|
nsStyleChangeList* const mChangeList;
|
2013-07-31 04:36:09 +04:00
|
|
|
// We have already generated change list entries for hints listed in
|
|
|
|
// mHintsHandled (initially it's those handled by ancestors, but by
|
|
|
|
// the end of Restyle it is those handled for this frame as well). We
|
|
|
|
// need to generate a new change list entry for the frame when its
|
|
|
|
// style comparision returns a hint other than one of these hints.
|
|
|
|
nsChangeHint mHintsHandled;
|
2013-07-31 04:36:10 +04:00
|
|
|
// See nsStyleContext::CalcStyleDifference
|
|
|
|
nsChangeHint mParentFrameHintsNotHandledForDescendants;
|
|
|
|
nsChangeHint mHintsNotHandledForDescendants;
|
2013-07-31 04:36:10 +04:00
|
|
|
RestyleTracker& mRestyleTracker;
|
2015-08-05 15:42:20 +03:00
|
|
|
nsTArray<nsCSSSelector*>& mSelectorsForDescendants;
|
2013-07-31 04:36:10 +04:00
|
|
|
TreeMatchContext& mTreeMatchContext;
|
2013-07-31 04:36:11 +04:00
|
|
|
nsIFrame* mResolvedChild; // child that provides our parent style context
|
2015-02-18 01:28:53 +03:00
|
|
|
// Array of style context subtrees in which we need to clear out cached
|
|
|
|
// structs at the end of the restyle (after change hints have been
|
|
|
|
// processed).
|
|
|
|
nsTArray<ContextToClear>& mContextsToClear;
|
|
|
|
// Style contexts that had old structs swapped into it and which should
|
|
|
|
// stay alive until the end of the restyle. (See comment in
|
|
|
|
// ElementRestyler::Restyle.)
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<nsStyleContext>>& mSwappedStructOwners;
|
2015-08-28 23:13:47 +03:00
|
|
|
// Whether this is the root of the restyle.
|
|
|
|
bool mIsRootOfRestyle;
|
2013-07-31 04:36:10 +04:00
|
|
|
|
2013-08-01 06:15:19 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
2013-07-31 04:36:10 +04:00
|
|
|
const DesiredA11yNotifications mDesiredA11yNotifications;
|
|
|
|
DesiredA11yNotifications mKidsDesiredA11yNotifications;
|
|
|
|
A11yNotificationType mOurA11yNotification;
|
2013-07-31 04:36:10 +04:00
|
|
|
nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement;
|
2013-07-31 04:36:11 +04:00
|
|
|
bool mWasFrameVisible;
|
2013-08-01 06:15:19 +04:00
|
|
|
#endif
|
2014-09-25 09:45:36 +04:00
|
|
|
|
|
|
|
#ifdef RESTYLE_LOGGING
|
|
|
|
int32_t mLoggingDepth;
|
|
|
|
#endif
|
2013-07-31 04:36:09 +04:00
|
|
|
};
|
|
|
|
|
2014-11-20 21:24:09 +03:00
|
|
|
/**
|
|
|
|
* This pushes any display:contents nodes onto a TreeMatchContext.
|
|
|
|
* Use it before resolving style for kids of aParent where aParent
|
|
|
|
* (and further ancestors) may be display:contents nodes which have
|
|
|
|
* not yet been pushed onto TreeMatchContext.
|
|
|
|
*/
|
2016-03-28 15:34:26 +03:00
|
|
|
class MOZ_RAII AutoDisplayContentsAncestorPusher final
|
2014-11-20 21:24:09 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef mozilla::dom::Element Element;
|
|
|
|
AutoDisplayContentsAncestorPusher(TreeMatchContext& aTreeMatchContext,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
nsIContent* aParent);
|
|
|
|
~AutoDisplayContentsAncestorPusher();
|
|
|
|
bool IsEmpty() const { return mAncestors.Length() == 0; }
|
|
|
|
private:
|
|
|
|
TreeMatchContext& mTreeMatchContext;
|
|
|
|
nsPresContext* const mPresContext;
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<mozilla::dom::Element*, 4> mAncestors;
|
2014-11-20 21:24:09 +03:00
|
|
|
};
|
|
|
|
|
2013-07-20 23:14:24 +04:00
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif /* mozilla_RestyleManager_h */
|