layout/base/RestyleManager.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /**
     7  * Code responsible for managing style changes: tracking what style
     8  * changes need to happen, scheduling them, and doing them.
     9  */
    11 #ifndef mozilla_RestyleManager_h
    12 #define mozilla_RestyleManager_h
    14 #include "nsISupportsImpl.h"
    15 #include "nsChangeHint.h"
    16 #include "RestyleTracker.h"
    17 #include "nsPresContext.h"
    19 class nsRefreshDriver;
    20 class nsIFrame;
    21 struct TreeMatchContext;
    23 namespace mozilla {
    24   class EventStates;
    26 namespace dom {
    27   class Element;
    28 } // namespace dom
    30 class RestyleManager MOZ_FINAL {
    31 public:
    32   friend class ::nsRefreshDriver;
    33   friend class RestyleTracker;
    35   typedef mozilla::dom::Element Element;
    37   RestyleManager(nsPresContext* aPresContext);
    39 private:
    40   // Private destructor, to discourage deletion outside of Release():
    41   ~RestyleManager()
    42   {
    43   }
    45 public:
    46   NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
    48   void Disconnect() {
    49     mPresContext = nullptr;
    50   }
    52   nsPresContext* PresContext() const {
    53     MOZ_ASSERT(mPresContext);
    54     return mPresContext;
    55   }
    57   nsCSSFrameConstructor* FrameConstructor() const
    58     { return PresContext()->FrameConstructor(); }
    60   // Should be called when a frame is going to be destroyed and
    61   // WillDestroyFrameTree hasn't been called yet.
    62   void NotifyDestroyingFrame(nsIFrame* aFrame);
    64   // Forwarded nsIDocumentObserver method, to handle restyling (and
    65   // passing the notification to the frame).
    66   nsresult ContentStateChanged(nsIContent*   aContent,
    67                                EventStates aStateMask);
    69   // Forwarded nsIMutationObserver method, to handle restyling.
    70   void AttributeWillChange(Element* aElement,
    71                            int32_t  aNameSpaceID,
    72                            nsIAtom* aAttribute,
    73                            int32_t  aModType);
    74   // Forwarded nsIMutationObserver method, to handle restyling (and
    75   // passing the notification to the frame).
    76   void AttributeChanged(Element* aElement,
    77                         int32_t  aNameSpaceID,
    78                         nsIAtom* aAttribute,
    79                         int32_t  aModType);
    81   // Get an integer that increments every time there is a style change
    82   // as a result of a change to the :hover content state.
    83   uint32_t GetHoverGeneration() const { return mHoverGeneration; }
    85   // Get a counter that increments on every style change, that we use to
    86   // track whether off-main-thread animations are up-to-date.
    87   uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
    89   /**
    90    * Reparent the style contexts of this frame subtree.  The parent frame of
    91    * aFrame must be changed to the new parent before this function is called;
    92    * the new parent style context will be automatically computed based on the
    93    * new position in the frame tree.
    94    *
    95    * @param aFrame the root of the subtree to reparent.  Must not be null.
    96    */
    97   NS_HIDDEN_(nsresult) ReparentStyleContext(nsIFrame* aFrame);
    99   /**
   100    * Re-resolve the style contexts for a frame tree, building
   101    * aChangeList based on the resulting style changes, plus aMinChange
   102    * applied to aFrame.
   103    */
   104   NS_HIDDEN_(void)
   105     ComputeStyleChangeFor(nsIFrame* aFrame,
   106                           nsStyleChangeList* aChangeList,
   107                           nsChangeHint aMinChange,
   108                           RestyleTracker& aRestyleTracker,
   109                           bool aRestyleDescendants);
   111 #ifdef DEBUG
   112   /**
   113    * DEBUG ONLY method to verify integrity of style tree versus frame tree
   114    */
   115   NS_HIDDEN_(void) DebugVerifyStyleTree(nsIFrame* aFrame);
   116 #endif
   118   // Note: It's the caller's responsibility to make sure to wrap a
   119   // ProcessRestyledFrames call in a view update batch and a script blocker.
   120   // This function does not call ProcessAttachedQueue() on the binding manager.
   121   // If the caller wants that to happen synchronously, it needs to handle that
   122   // itself.
   123   nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray);
   125 private:
   126   void RestyleForEmptyChange(Element* aContainer);
   128 public:
   129   // Restyling for a ContentInserted (notification after insertion) or
   130   // for a CharacterDataChanged.  |aContainer| must be non-null; when
   131   // the container is null, no work is needed.
   132   void RestyleForInsertOrChange(Element* aContainer, nsIContent* aChild);
   134   // This would be the same as RestyleForInsertOrChange if we got the
   135   // notification before the removal.  However, we get it after, so we need the
   136   // following sibling in addition to the old child.  |aContainer| must be
   137   // non-null; when the container is null, no work is needed.  aFollowingSibling
   138   // is the sibling that used to come after aOldChild before the removal.
   139   void RestyleForRemove(Element* aContainer,
   140                         nsIContent* aOldChild,
   141                         nsIContent* aFollowingSibling);
   143   // Same for a ContentAppended.  |aContainer| must be non-null; when
   144   // the container is null, no work is needed.
   145   void RestyleForAppend(Element* aContainer, nsIContent* aFirstNewContent);
   147   // Process any pending restyles. This should be called after
   148   // CreateNeededFrames.
   149   // Note: It's the caller's responsibility to make sure to wrap a
   150   // ProcessPendingRestyles call in a view update batch and a script blocker.
   151   // This function does not call ProcessAttachedQueue() on the binding manager.
   152   // If the caller wants that to happen synchronously, it needs to handle that
   153   // itself.
   154   void ProcessPendingRestyles();
   156   // ProcessPendingRestyles calls into one of our RestyleTracker
   157   // objects.  It then calls back to these functions at the beginning
   158   // and end of its work.
   159   void BeginProcessingRestyles();
   160   void EndProcessingRestyles();
   162   // Rebuilds all style data by throwing out the old rule tree and
   163   // building a new one, and additionally applying aExtraHint (which
   164   // must not contain nsChangeHint_ReconstructFrame) to the root frame.
   165   void RebuildAllStyleData(nsChangeHint aExtraHint);
   167   // Helper that does part of the work of RebuildAllStyleData, shared by
   168   // RestyleElement for 'rem' handling.
   169   void DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
   170                              nsChangeHint aExtraHint);
   172   // See PostRestyleEventCommon below.
   173   void PostRestyleEvent(Element* aElement,
   174                         nsRestyleHint aRestyleHint,
   175                         nsChangeHint aMinChangeHint)
   176   {
   177     if (mPresContext) {
   178       PostRestyleEventCommon(aElement, aRestyleHint, aMinChangeHint,
   179                              mPresContext->IsProcessingAnimationStyleChange());
   180     }
   181   }
   183   // See PostRestyleEventCommon below.
   184   void PostAnimationRestyleEvent(Element* aElement,
   185                                  nsRestyleHint aRestyleHint,
   186                                  nsChangeHint aMinChangeHint)
   187   {
   188     PostRestyleEventCommon(aElement, aRestyleHint, aMinChangeHint, true);
   189   }
   191   void PostRestyleEventForLazyConstruction()
   192   {
   193     PostRestyleEventInternal(true);
   194   }
   196   void FlushOverflowChangedTracker()
   197   {
   198     mOverflowChangedTracker.Flush();
   199   }
   201 private:
   202   /**
   203    * Notify the frame constructor that an element needs to have its
   204    * style recomputed.
   205    * @param aElement: The element to be restyled.
   206    * @param aRestyleHint: Which nodes need to have selector matching run
   207    *                      on them.
   208    * @param aMinChangeHint: A minimum change hint for aContent and its
   209    *                        descendants.
   210    * @param aForAnimation: Whether the style should be computed with or
   211    *                       without animation data.  Animation code
   212    *                       sometimes needs to pass true; other code
   213    *                       should generally pass the the pres context's
   214    *                       IsProcessingAnimationStyleChange() value
   215    *                       (which is the default value).
   216    */
   217   void PostRestyleEventCommon(Element* aElement,
   218                               nsRestyleHint aRestyleHint,
   219                               nsChangeHint aMinChangeHint,
   220                               bool aForAnimation);
   221   void PostRestyleEventInternal(bool aForLazyConstruction);
   223 public:
   224   /**
   225    * Asynchronously clear style data from the root frame downwards and ensure
   226    * it will all be rebuilt. This is safe to call anytime; it will schedule
   227    * a restyle and take effect next time style changes are flushed.
   228    * This method is used to recompute the style data when some change happens
   229    * outside of any style rules, like a color preference change or a change
   230    * in a system font size, or to fix things up when an optimization in the
   231    * style data has become invalid. We assume that the root frame will not
   232    * need to be reframed.
   233    */
   234   void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint);
   236 private:
   237   /* aMinHint is the minimal change that should be made to the element */
   238   // XXXbz do we really need the aPrimaryFrame argument here?
   239   void RestyleElement(Element*        aElement,
   240                       nsIFrame*       aPrimaryFrame,
   241                       nsChangeHint    aMinHint,
   242                       RestyleTracker& aRestyleTracker,
   243                       bool            aRestyleDescendants);
   245   nsresult StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
   247   // Returns true if this function managed to successfully move a frame, and
   248   // false if it could not process the position change, and a reflow should
   249   // be performed instead.
   250   bool RecomputePosition(nsIFrame* aFrame);
   252 private:
   253   nsPresContext* mPresContext; // weak, disconnected in Disconnect
   255   bool mRebuildAllStyleData : 1;
   256   // True if we're already waiting for a refresh notification
   257   bool mObservingRefreshDriver : 1;
   258   // True if we're in the middle of a nsRefreshDriver refresh
   259   bool mInStyleRefresh : 1;
   260   uint32_t mHoverGeneration;
   261   nsChangeHint mRebuildAllExtraHint;
   263   OverflowChangedTracker mOverflowChangedTracker;
   265   // The total number of animation flushes by this frame constructor.
   266   // Used to keep the layer and animation manager in sync.
   267   uint64_t mAnimationGeneration;
   269   RestyleTracker mPendingRestyles;
   270   RestyleTracker mPendingAnimationRestyles;
   271 };
   273 /**
   274  * An ElementRestyler is created for *each* element in a subtree that we
   275  * recompute styles for.
   276  */
   277 class ElementRestyler MOZ_FINAL {
   278 public:
   279   typedef mozilla::dom::Element Element;
   281   // Construct for the root of the subtree that we're restyling.
   282   ElementRestyler(nsPresContext* aPresContext,
   283                   nsIFrame* aFrame,
   284                   nsStyleChangeList* aChangeList,
   285                   nsChangeHint aHintsHandledByAncestors,
   286                   RestyleTracker& aRestyleTracker,
   287                   TreeMatchContext& aTreeMatchContext,
   288                   nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement);
   290   // Construct for an element whose parent is being restyled.
   291   enum ConstructorFlags {
   292     FOR_OUT_OF_FLOW_CHILD = 1<<0
   293   };
   294   ElementRestyler(const ElementRestyler& aParentRestyler,
   295                   nsIFrame* aFrame,
   296                   uint32_t aConstructorFlags);
   298   // Construct for a frame whose parent is being restyled, but whose
   299   // style context is the parent style context for its parent frame.
   300   // (This is only used for table frames, whose style contexts are used
   301   // as the parent style context for their outer table frame (table
   302   // wrapper frame).  We should probably try to get rid of this
   303   // exception and have the inheritance go the other way.)
   304   enum ParentContextFromChildFrame { PARENT_CONTEXT_FROM_CHILD_FRAME };
   305   ElementRestyler(ParentContextFromChildFrame,
   306                   const ElementRestyler& aParentFrameRestyler,
   307                   nsIFrame* aFrame);
   309   /**
   310    * Restyle our frame's element and its subtree.
   311    *
   312    * Use eRestyle_Self for the aRestyleHint argument to mean
   313    * "reresolve our style context but not kids", use eRestyle_Subtree
   314    * to mean "reresolve our style context and kids", and use
   315    * nsRestyleHint(0) to mean recompute a new style context for our
   316    * current parent and existing rulenode, and the same for kids.
   317    */
   318   void Restyle(nsRestyleHint aRestyleHint);
   320   /**
   321    * mHintsHandled changes over time; it starts off as the hints that
   322    * have been handled by ancestors, and by the end of Restyle it
   323    * represents the hints that have been handled for this frame.  This
   324    * method is intended to be called after Restyle, to find out what
   325    * hints have been handled for this frame.
   326    */
   327   nsChangeHint HintsHandledForFrame() { return mHintsHandled; }
   329 private:
   330   /**
   331    * First half of Restyle().
   332    */
   333   void RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint);
   335   /**
   336    * Restyle the children of this frame (and, in turn, their children).
   337    *
   338    * Second half of Restyle().
   339    */
   340   void RestyleChildren(nsRestyleHint aChildRestyleHint);
   342   /**
   343    * Helper for RestyleSelf().
   344    */
   345   void CaptureChange(nsStyleContext* aOldContext,
   346                      nsStyleContext* aNewContext,
   347                      nsChangeHint aChangeToAssume);
   349   /**
   350    * Helpers for RestyleChildren().
   351    */
   352   void RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint);
   353   void RestyleBeforePseudo();
   354   void RestyleAfterPseudo(nsIFrame* aFrame);
   355   void RestyleContentChildren(nsIFrame* aParent,
   356                               nsRestyleHint aChildRestyleHint);
   357   void InitializeAccessibilityNotifications();
   358   void SendAccessibilityNotifications();
   360   enum DesiredA11yNotifications {
   361     eSkipNotifications,
   362     eSendAllNotifications,
   363     eNotifyIfShown
   364   };
   366   enum A11yNotificationType {
   367     eDontNotify,
   368     eNotifyShown,
   369     eNotifyHidden
   370   };
   372 private:
   373   nsPresContext* const mPresContext;
   374   nsIFrame* const mFrame;
   375   nsIContent* const mParentContent;
   376   // |mContent| is the node that we used for rule matching of
   377   // normal elements (not pseudo-elements) and for which we generate
   378   // framechange hints if we need them.
   379   nsIContent* const mContent;
   380   nsStyleChangeList* const mChangeList;
   381   // We have already generated change list entries for hints listed in
   382   // mHintsHandled (initially it's those handled by ancestors, but by
   383   // the end of Restyle it is those handled for this frame as well).  We
   384   // need to generate a new change list entry for the frame when its
   385   // style comparision returns a hint other than one of these hints.
   386   nsChangeHint mHintsHandled;
   387   // See nsStyleContext::CalcStyleDifference
   388   nsChangeHint mParentFrameHintsNotHandledForDescendants;
   389   nsChangeHint mHintsNotHandledForDescendants;
   390   RestyleTracker& mRestyleTracker;
   391   TreeMatchContext& mTreeMatchContext;
   392   nsIFrame* mResolvedChild; // child that provides our parent style context
   394 #ifdef ACCESSIBILITY
   395   const DesiredA11yNotifications mDesiredA11yNotifications;
   396   DesiredA11yNotifications mKidsDesiredA11yNotifications;
   397   A11yNotificationType mOurA11yNotification;
   398   nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement;
   399   bool mWasFrameVisible;
   400 #endif
   401 };
   403 } // namespace mozilla
   405 #endif /* mozilla_RestyleManager_h */

mercurial