LCOV - code coverage report
Current view: top level - layout/base - RestyleManager.h (source / functions) Hit Total Coverage
Test: output.info Lines: 41 54 75.9 %
Date: 2017-07-14 16:53:18 Functions: 19 23 82.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_RestyleManager_h
       8             : #define mozilla_RestyleManager_h
       9             : 
      10             : #include "mozilla/OverflowChangedTracker.h"
      11             : #include "nsChangeHint.h"
      12             : #include "nsPresContext.h"
      13             : 
      14             : class nsCString;
      15             : class nsCSSFrameConstructor;
      16             : class nsStyleChangeList;
      17             : 
      18             : namespace mozilla {
      19             : 
      20             : class EventStates;
      21             : class GeckoRestyleManager;
      22             : class ServoRestyleManager;
      23             : 
      24             : namespace dom {
      25             : class Element;
      26             : }
      27             : 
      28             : /**
      29             :  * Class for sharing data and logic common to both GeckoRestyleManager and
      30             :  * ServoRestyleManager.
      31             :  */
      32             : class RestyleManager
      33             : {
      34             : public:
      35             :   typedef mozilla::dom::Element Element;
      36             : 
      37          32 :   NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
      38             : 
      39             :   // Get an integer that increments every time we process pending restyles.
      40             :   // The value is never 0.
      41           0 :   uint32_t GetRestyleGeneration() const { return mRestyleGeneration; }
      42             :   // Unlike GetRestyleGeneration, which means the actual restyling count,
      43             :   // GetUndisplayedRestyleGeneration represents any possible DOM changes that
      44             :   // can cause restyling. This is needed for getComputedStyle to work with
      45             :   // non-styled (e.g. display: none) elements.
      46           4 :   uint32_t GetUndisplayedRestyleGeneration() const {
      47           4 :     return mUndisplayedRestyleGeneration;
      48             :   }
      49             : 
      50             :   // Get an integer that increments every time there is a style change
      51             :   // as a result of a change to the :hover content state.
      52           0 :   uint32_t GetHoverGeneration() const { return mHoverGeneration; }
      53             : 
      54           4 :   void Disconnect() { mPresContext = nullptr; }
      55             : 
      56             :   static nsCString RestyleHintToString(nsRestyleHint aHint);
      57             : 
      58             : #ifdef DEBUG
      59             :   static nsCString ChangeHintToString(nsChangeHint aHint);
      60             : 
      61             :   /**
      62             :    * DEBUG ONLY method to verify integrity of style tree versus frame tree
      63             :    */
      64             :   void DebugVerifyStyleTree(nsIFrame* aFrame);
      65             : #endif
      66             : 
      67          25 :   void FlushOverflowChangedTracker() {
      68          25 :     mOverflowChangedTracker.Flush();
      69          25 :   }
      70             : 
      71             :   // Should be called when a frame is going to be destroyed and
      72             :   // WillDestroyFrameTree hasn't been called yet.
      73         126 :   void NotifyDestroyingFrame(nsIFrame* aFrame) {
      74         126 :     mOverflowChangedTracker.RemoveFrame(aFrame);
      75             :     // If ProcessRestyledFrames is tracking frames which have been
      76             :     // destroyed (to avoid re-visiting them), add this one to its set.
      77         126 :     if (mDestroyedFrames) {
      78         121 :       mDestroyedFrames->PutEntry(aFrame);
      79             :     }
      80         126 :   }
      81             : 
      82             :   // Note: It's the caller's responsibility to make sure to wrap a
      83             :   // ProcessRestyledFrames call in a view update batch and a script blocker.
      84             :   // This function does not call ProcessAttachedQueue() on the binding manager.
      85             :   // If the caller wants that to happen synchronously, it needs to handle that
      86             :   // itself.
      87             :   void ProcessRestyledFrames(nsStyleChangeList& aChangeList);
      88             : 
      89          80 :   bool IsInStyleRefresh() const { return mInStyleRefresh; }
      90             : 
      91             :   // AnimationsWithDestroyedFrame is used to stop animations and transitions
      92             :   // on elements that have no frame at the end of the restyling process.
      93             :   // It only lives during the restyling process.
      94          25 :   class MOZ_STACK_CLASS AnimationsWithDestroyedFrame final {
      95             :   public:
      96             :     // Construct a AnimationsWithDestroyedFrame object.  The caller must
      97             :     // ensure that aRestyleManager lives at least as long as the
      98             :     // object.  (This is generally easy since the caller is typically a
      99             :     // method of RestyleManager.)
     100             :     explicit AnimationsWithDestroyedFrame(RestyleManager* aRestyleManager);
     101             : 
     102             :     // This method takes the content node for the generated content for
     103             :     // animation/transition on ::before and ::after, rather than the
     104             :     // content node for the real element.
     105           2 :     void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
     106           2 :       MOZ_ASSERT(aContent);
     107           2 :       CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
     108           2 :       if (pseudoType == CSSPseudoElementType::NotPseudo) {
     109           2 :         mContents.AppendElement(aContent);
     110           0 :       } else if (pseudoType == CSSPseudoElementType::before) {
     111           0 :         MOZ_ASSERT(aContent->NodeInfo()->NameAtom() ==
     112             :                      nsGkAtoms::mozgeneratedcontentbefore);
     113           0 :         mBeforeContents.AppendElement(aContent->GetParent());
     114           0 :       } else if (pseudoType == CSSPseudoElementType::after) {
     115           0 :         MOZ_ASSERT(aContent->NodeInfo()->NameAtom() ==
     116             :                      nsGkAtoms::mozgeneratedcontentafter);
     117           0 :         mAfterContents.AppendElement(aContent->GetParent());
     118             :       }
     119           2 :     }
     120             : 
     121             :     void StopAnimationsForElementsWithoutFrames();
     122             : 
     123             :   private:
     124             :     void StopAnimationsWithoutFrame(nsTArray<RefPtr<nsIContent>>& aArray,
     125             :                                     CSSPseudoElementType aPseudoType);
     126             : 
     127             :     RestyleManager* mRestyleManager;
     128             :     AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
     129             : 
     130             :     // Below three arrays might include elements that have already had their
     131             :     // animations or transitions stopped.
     132             :     //
     133             :     // mBeforeContents and mAfterContents hold the real element rather than
     134             :     // the content node for the generated content (which might change during
     135             :     // a reframe)
     136             :     nsTArray<RefPtr<nsIContent>> mContents;
     137             :     nsTArray<RefPtr<nsIContent>> mBeforeContents;
     138             :     nsTArray<RefPtr<nsIContent>> mAfterContents;
     139             :   };
     140             : 
     141             :   /**
     142             :    * Return the current AnimationsWithDestroyedFrame struct, or null if we're
     143             :    * not currently in a restyling operation.
     144             :    */
     145           2 :   AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
     146           2 :     return mAnimationsWithDestroyedFrame;
     147             :   }
     148             : 
     149             :   void ContentInserted(nsINode* aContainer, nsIContent* aChild);
     150             :   void ContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent);
     151             : 
     152             :   // This would be have the same logic as RestyleForInsertOrChange if we got the
     153             :   // notification before the removal.  However, we get it after, so we need the
     154             :   // following sibling in addition to the old child.  |aContainer| must be
     155             :   // non-null; when the container is null, no work is needed.  aFollowingSibling
     156             :   // is the sibling that used to come after aOldChild before the removal.
     157             :   void ContentRemoved(nsINode* aContainer,
     158             :                       nsIContent* aOldChild,
     159             :                       nsIContent* aFollowingSibling);
     160             : 
     161             :   // Restyling for a ContentInserted (notification after insertion) or
     162             :   // for a CharacterDataChanged.  |aContainer| must be non-null; when
     163             :   // the container is null, no work is needed.
     164             :   void RestyleForInsertOrChange(nsINode* aContainer, nsIContent* aChild);
     165             : 
     166             :   // Restyling for a ContentAppended (notification after insertion) or
     167             :   // for a CharacterDataChanged.  |aContainer| must be non-null; when
     168             :   // the container is null, no work is needed.
     169             :   void RestyleForAppend(nsIContent* aContainer, nsIContent* aFirstNewContent);
     170             : 
     171       25939 :   MOZ_DECL_STYLO_METHODS(GeckoRestyleManager, ServoRestyleManager)
     172             : 
     173             :   inline void PostRestyleEvent(dom::Element* aElement,
     174             :                                nsRestyleHint aRestyleHint,
     175             :                                nsChangeHint aMinChangeHint);
     176             :   inline void RebuildAllStyleData(nsChangeHint aExtraHint,
     177             :                                   nsRestyleHint aRestyleHint);
     178             :   inline void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
     179             :                                            nsRestyleHint aRestyleHint);
     180             :   inline void ProcessPendingRestyles();
     181             :   inline void ContentStateChanged(nsIContent* aContent,
     182             :                                   EventStates aStateMask);
     183             :   inline void AttributeWillChange(dom::Element* aElement,
     184             :                                   int32_t aNameSpaceID,
     185             :                                   nsIAtom* aAttribute,
     186             :                                   int32_t aModType,
     187             :                                   const nsAttrValue* aNewValue);
     188             :   inline void AttributeChanged(dom::Element* aElement,
     189             :                                int32_t aNameSpaceID,
     190             :                                nsIAtom* aAttribute,
     191             :                                int32_t aModType,
     192             :                                const nsAttrValue* aOldValue);
     193             :   inline nsresult ReparentStyleContext(nsIFrame* aFrame);
     194             : 
     195             :   inline void UpdateOnlyAnimationStyles();
     196             : 
     197             :   // Get a counter that increments on every style change, that we use to
     198             :   // track whether off-main-thread animations are up-to-date.
     199          28 :   uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
     200             : 
     201             :   static uint64_t GetAnimationGenerationForFrame(nsIFrame* aFrame);
     202             : 
     203             :   // Update the animation generation count to mark that animation state
     204             :   // has changed.
     205             :   //
     206             :   // This is normally performed automatically by ProcessPendingRestyles
     207             :   // but it is also called when we have out-of-band changes to animations
     208             :   // such as changes made through the Web Animations API.
     209             :   void IncrementAnimationGeneration();
     210             : 
     211             :   static void AddLayerChangesForAnimation(nsIFrame* aFrame,
     212             :                                           nsIContent* aContent,
     213             :                                           nsStyleChangeList&
     214             :                                             aChangeListToProcess);
     215             : 
     216             : protected:
     217             :   RestyleManager(StyleBackendType aType, nsPresContext* aPresContext);
     218             : 
     219           4 :   virtual ~RestyleManager()
     220           8 :   {
     221           4 :     MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
     222             :                "leaving dangling pointers from AnimationsWithDestroyedFrame");
     223           4 :   }
     224             : 
     225             :   void RestyleForEmptyChange(Element* aContainer);
     226             : 
     227             :   void ContentStateChangedInternal(Element* aElement,
     228             :                                    EventStates aStateMask,
     229             :                                    nsChangeHint* aOutChangeHint,
     230             :                                    nsRestyleHint* aOutRestyleHint);
     231             : 
     232         767 :   bool IsDisconnected() { return mPresContext == nullptr; }
     233             : 
     234           0 :   void IncrementHoverGeneration() {
     235           0 :     ++mHoverGeneration;
     236           0 :   }
     237             : 
     238          25 :   void IncrementRestyleGeneration() {
     239          25 :     if (++mRestyleGeneration == 0) {
     240             :       // Keep mRestyleGeneration from being 0, since that's what
     241             :       // nsPresContext::GetRestyleGeneration returns when it no
     242             :       // longer has a RestyleManager.
     243           0 :       ++mRestyleGeneration;
     244             :     }
     245          25 :     IncrementUndisplayedRestyleGeneration();
     246          25 :   }
     247             : 
     248          25 :   void IncrementUndisplayedRestyleGeneration() {
     249          25 :     if (++mUndisplayedRestyleGeneration == 0) {
     250             :       // Ensure mUndisplayedRestyleGeneration > 0, for the same reason as
     251             :       // IncrementRestyleGeneration.
     252           0 :       ++mUndisplayedRestyleGeneration;
     253             :     }
     254          25 :   }
     255             : 
     256        7178 :   nsPresContext* PresContext() const {
     257        7178 :     MOZ_ASSERT(mPresContext);
     258        7178 :     return mPresContext;
     259             :   }
     260             : 
     261          50 :   nsCSSFrameConstructor* FrameConstructor() const {
     262          50 :     return PresContext()->FrameConstructor();
     263             :   }
     264             : 
     265             : private:
     266             :   nsPresContext* mPresContext; // weak, can be null after Disconnect().
     267             :   uint32_t mRestyleGeneration;
     268             :   uint32_t mUndisplayedRestyleGeneration;
     269             :   uint32_t mHoverGeneration;
     270             : 
     271             :   // Used to keep track of frames that have been destroyed during
     272             :   // ProcessRestyledFrames, so we don't try to touch them again even if
     273             :   // they're referenced again later in the changelist.
     274             :   mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<const nsIFrame>>> mDestroyedFrames;
     275             : 
     276             : protected:
     277             :   const StyleBackendType mType;
     278             : 
     279             :   // True if we're in the middle of a nsRefreshDriver refresh
     280             :   bool mInStyleRefresh;
     281             : 
     282             :   // The total number of animation flushes by this frame constructor.
     283             :   // Used to keep the layer and animation manager in sync.
     284             :   uint64_t mAnimationGeneration;
     285             : 
     286             :   OverflowChangedTracker mOverflowChangedTracker;
     287             : 
     288             :   /**
     289             :    * These are protected static methods that help with the change hint
     290             :    * processing bits of the restyle managers.
     291             :    */
     292             :   static nsIFrame*
     293             :   GetNearestAncestorFrame(nsIContent* aContent);
     294             : 
     295             :   static nsIFrame*
     296             :   GetNextBlockInInlineSibling(nsIFrame* aFrame);
     297             : 
     298             :   /**
     299             :    * Get the next continuation or similar ib-split sibling (assuming
     300             :    * block/inline alternation), conditionally on it having the same style.
     301             :    *
     302             :    * Since this is used when deciding to copy the new style context, it
     303             :    * takes as an argument the old style context to check if the style is
     304             :    * the same.  When it is used in other contexts (i.e., where the next
     305             :    * continuation would already have the new style context), the current
     306             :    * style context should be passed.
     307             :    */
     308             :   static nsIFrame*
     309             :   GetNextContinuationWithSameStyle(nsIFrame* aFrame,
     310             :                                    nsStyleContext* aOldStyleContext,
     311             :                                    bool* aHaveMoreContinuations = nullptr);
     312             : 
     313             :   AnimationsWithDestroyedFrame* mAnimationsWithDestroyedFrame = nullptr;
     314             : 
     315             :   friend class mozilla::GeckoRestyleManager;
     316             :   friend class mozilla::ServoRestyleManager;
     317             : };
     318             : 
     319             : } // namespace mozilla
     320             : 
     321             : #endif

Generated by: LCOV version 1.13