layout/base/RestyleManager.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/base/RestyleManager.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,405 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/**
    1.10 + * Code responsible for managing style changes: tracking what style
    1.11 + * changes need to happen, scheduling them, and doing them.
    1.12 + */
    1.13 +
    1.14 +#ifndef mozilla_RestyleManager_h
    1.15 +#define mozilla_RestyleManager_h
    1.16 +
    1.17 +#include "nsISupportsImpl.h"
    1.18 +#include "nsChangeHint.h"
    1.19 +#include "RestyleTracker.h"
    1.20 +#include "nsPresContext.h"
    1.21 +
    1.22 +class nsRefreshDriver;
    1.23 +class nsIFrame;
    1.24 +struct TreeMatchContext;
    1.25 +
    1.26 +namespace mozilla {
    1.27 +  class EventStates;
    1.28 +
    1.29 +namespace dom {
    1.30 +  class Element;
    1.31 +} // namespace dom
    1.32 +
    1.33 +class RestyleManager MOZ_FINAL {
    1.34 +public:
    1.35 +  friend class ::nsRefreshDriver;
    1.36 +  friend class RestyleTracker;
    1.37 +
    1.38 +  typedef mozilla::dom::Element Element;
    1.39 +
    1.40 +  RestyleManager(nsPresContext* aPresContext);
    1.41 +
    1.42 +private:
    1.43 +  // Private destructor, to discourage deletion outside of Release():
    1.44 +  ~RestyleManager()
    1.45 +  {
    1.46 +  }
    1.47 +
    1.48 +public:
    1.49 +  NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
    1.50 +
    1.51 +  void Disconnect() {
    1.52 +    mPresContext = nullptr;
    1.53 +  }
    1.54 +
    1.55 +  nsPresContext* PresContext() const {
    1.56 +    MOZ_ASSERT(mPresContext);
    1.57 +    return mPresContext;
    1.58 +  }
    1.59 +
    1.60 +  nsCSSFrameConstructor* FrameConstructor() const
    1.61 +    { return PresContext()->FrameConstructor(); }
    1.62 +
    1.63 +  // Should be called when a frame is going to be destroyed and
    1.64 +  // WillDestroyFrameTree hasn't been called yet.
    1.65 +  void NotifyDestroyingFrame(nsIFrame* aFrame);
    1.66 +
    1.67 +  // Forwarded nsIDocumentObserver method, to handle restyling (and
    1.68 +  // passing the notification to the frame).
    1.69 +  nsresult ContentStateChanged(nsIContent*   aContent,
    1.70 +                               EventStates aStateMask);
    1.71 +
    1.72 +  // Forwarded nsIMutationObserver method, to handle restyling.
    1.73 +  void AttributeWillChange(Element* aElement,
    1.74 +                           int32_t  aNameSpaceID,
    1.75 +                           nsIAtom* aAttribute,
    1.76 +                           int32_t  aModType);
    1.77 +  // Forwarded nsIMutationObserver method, to handle restyling (and
    1.78 +  // passing the notification to the frame).
    1.79 +  void AttributeChanged(Element* aElement,
    1.80 +                        int32_t  aNameSpaceID,
    1.81 +                        nsIAtom* aAttribute,
    1.82 +                        int32_t  aModType);
    1.83 +
    1.84 +  // Get an integer that increments every time there is a style change
    1.85 +  // as a result of a change to the :hover content state.
    1.86 +  uint32_t GetHoverGeneration() const { return mHoverGeneration; }
    1.87 +
    1.88 +  // Get a counter that increments on every style change, that we use to
    1.89 +  // track whether off-main-thread animations are up-to-date.
    1.90 +  uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
    1.91 +
    1.92 +  /**
    1.93 +   * Reparent the style contexts of this frame subtree.  The parent frame of
    1.94 +   * aFrame must be changed to the new parent before this function is called;
    1.95 +   * the new parent style context will be automatically computed based on the
    1.96 +   * new position in the frame tree.
    1.97 +   *
    1.98 +   * @param aFrame the root of the subtree to reparent.  Must not be null.
    1.99 +   */
   1.100 +  NS_HIDDEN_(nsresult) ReparentStyleContext(nsIFrame* aFrame);
   1.101 +
   1.102 +  /**
   1.103 +   * Re-resolve the style contexts for a frame tree, building
   1.104 +   * aChangeList based on the resulting style changes, plus aMinChange
   1.105 +   * applied to aFrame.
   1.106 +   */
   1.107 +  NS_HIDDEN_(void)
   1.108 +    ComputeStyleChangeFor(nsIFrame* aFrame,
   1.109 +                          nsStyleChangeList* aChangeList,
   1.110 +                          nsChangeHint aMinChange,
   1.111 +                          RestyleTracker& aRestyleTracker,
   1.112 +                          bool aRestyleDescendants);
   1.113 +
   1.114 +#ifdef DEBUG
   1.115 +  /**
   1.116 +   * DEBUG ONLY method to verify integrity of style tree versus frame tree
   1.117 +   */
   1.118 +  NS_HIDDEN_(void) DebugVerifyStyleTree(nsIFrame* aFrame);
   1.119 +#endif
   1.120 +
   1.121 +  // Note: It's the caller's responsibility to make sure to wrap a
   1.122 +  // ProcessRestyledFrames call in a view update batch and a script blocker.
   1.123 +  // This function does not call ProcessAttachedQueue() on the binding manager.
   1.124 +  // If the caller wants that to happen synchronously, it needs to handle that
   1.125 +  // itself.
   1.126 +  nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray);
   1.127 +
   1.128 +private:
   1.129 +  void RestyleForEmptyChange(Element* aContainer);
   1.130 +
   1.131 +public:
   1.132 +  // Restyling for a ContentInserted (notification after insertion) or
   1.133 +  // for a CharacterDataChanged.  |aContainer| must be non-null; when
   1.134 +  // the container is null, no work is needed.
   1.135 +  void RestyleForInsertOrChange(Element* aContainer, nsIContent* aChild);
   1.136 +
   1.137 +  // This would be the same as RestyleForInsertOrChange if we got the
   1.138 +  // notification before the removal.  However, we get it after, so we need the
   1.139 +  // following sibling in addition to the old child.  |aContainer| must be
   1.140 +  // non-null; when the container is null, no work is needed.  aFollowingSibling
   1.141 +  // is the sibling that used to come after aOldChild before the removal.
   1.142 +  void RestyleForRemove(Element* aContainer,
   1.143 +                        nsIContent* aOldChild,
   1.144 +                        nsIContent* aFollowingSibling);
   1.145 +
   1.146 +  // Same for a ContentAppended.  |aContainer| must be non-null; when
   1.147 +  // the container is null, no work is needed.
   1.148 +  void RestyleForAppend(Element* aContainer, nsIContent* aFirstNewContent);
   1.149 +
   1.150 +  // Process any pending restyles. This should be called after
   1.151 +  // CreateNeededFrames.
   1.152 +  // Note: It's the caller's responsibility to make sure to wrap a
   1.153 +  // ProcessPendingRestyles call in a view update batch and a script blocker.
   1.154 +  // This function does not call ProcessAttachedQueue() on the binding manager.
   1.155 +  // If the caller wants that to happen synchronously, it needs to handle that
   1.156 +  // itself.
   1.157 +  void ProcessPendingRestyles();
   1.158 +
   1.159 +  // ProcessPendingRestyles calls into one of our RestyleTracker
   1.160 +  // objects.  It then calls back to these functions at the beginning
   1.161 +  // and end of its work.
   1.162 +  void BeginProcessingRestyles();
   1.163 +  void EndProcessingRestyles();
   1.164 +
   1.165 +  // Rebuilds all style data by throwing out the old rule tree and
   1.166 +  // building a new one, and additionally applying aExtraHint (which
   1.167 +  // must not contain nsChangeHint_ReconstructFrame) to the root frame.
   1.168 +  void RebuildAllStyleData(nsChangeHint aExtraHint);
   1.169 +
   1.170 +  // Helper that does part of the work of RebuildAllStyleData, shared by
   1.171 +  // RestyleElement for 'rem' handling.
   1.172 +  void DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
   1.173 +                             nsChangeHint aExtraHint);
   1.174 +
   1.175 +  // See PostRestyleEventCommon below.
   1.176 +  void PostRestyleEvent(Element* aElement,
   1.177 +                        nsRestyleHint aRestyleHint,
   1.178 +                        nsChangeHint aMinChangeHint)
   1.179 +  {
   1.180 +    if (mPresContext) {
   1.181 +      PostRestyleEventCommon(aElement, aRestyleHint, aMinChangeHint,
   1.182 +                             mPresContext->IsProcessingAnimationStyleChange());
   1.183 +    }
   1.184 +  }
   1.185 +
   1.186 +  // See PostRestyleEventCommon below.
   1.187 +  void PostAnimationRestyleEvent(Element* aElement,
   1.188 +                                 nsRestyleHint aRestyleHint,
   1.189 +                                 nsChangeHint aMinChangeHint)
   1.190 +  {
   1.191 +    PostRestyleEventCommon(aElement, aRestyleHint, aMinChangeHint, true);
   1.192 +  }
   1.193 +
   1.194 +  void PostRestyleEventForLazyConstruction()
   1.195 +  {
   1.196 +    PostRestyleEventInternal(true);
   1.197 +  }
   1.198 +
   1.199 +  void FlushOverflowChangedTracker()
   1.200 +  {
   1.201 +    mOverflowChangedTracker.Flush();
   1.202 +  }
   1.203 +
   1.204 +private:
   1.205 +  /**
   1.206 +   * Notify the frame constructor that an element needs to have its
   1.207 +   * style recomputed.
   1.208 +   * @param aElement: The element to be restyled.
   1.209 +   * @param aRestyleHint: Which nodes need to have selector matching run
   1.210 +   *                      on them.
   1.211 +   * @param aMinChangeHint: A minimum change hint for aContent and its
   1.212 +   *                        descendants.
   1.213 +   * @param aForAnimation: Whether the style should be computed with or
   1.214 +   *                       without animation data.  Animation code
   1.215 +   *                       sometimes needs to pass true; other code
   1.216 +   *                       should generally pass the the pres context's
   1.217 +   *                       IsProcessingAnimationStyleChange() value
   1.218 +   *                       (which is the default value).
   1.219 +   */
   1.220 +  void PostRestyleEventCommon(Element* aElement,
   1.221 +                              nsRestyleHint aRestyleHint,
   1.222 +                              nsChangeHint aMinChangeHint,
   1.223 +                              bool aForAnimation);
   1.224 +  void PostRestyleEventInternal(bool aForLazyConstruction);
   1.225 +
   1.226 +public:
   1.227 +  /**
   1.228 +   * Asynchronously clear style data from the root frame downwards and ensure
   1.229 +   * it will all be rebuilt. This is safe to call anytime; it will schedule
   1.230 +   * a restyle and take effect next time style changes are flushed.
   1.231 +   * This method is used to recompute the style data when some change happens
   1.232 +   * outside of any style rules, like a color preference change or a change
   1.233 +   * in a system font size, or to fix things up when an optimization in the
   1.234 +   * style data has become invalid. We assume that the root frame will not
   1.235 +   * need to be reframed.
   1.236 +   */
   1.237 +  void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint);
   1.238 +
   1.239 +private:
   1.240 +  /* aMinHint is the minimal change that should be made to the element */
   1.241 +  // XXXbz do we really need the aPrimaryFrame argument here?
   1.242 +  void RestyleElement(Element*        aElement,
   1.243 +                      nsIFrame*       aPrimaryFrame,
   1.244 +                      nsChangeHint    aMinHint,
   1.245 +                      RestyleTracker& aRestyleTracker,
   1.246 +                      bool            aRestyleDescendants);
   1.247 +
   1.248 +  nsresult StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
   1.249 +
   1.250 +  // Returns true if this function managed to successfully move a frame, and
   1.251 +  // false if it could not process the position change, and a reflow should
   1.252 +  // be performed instead.
   1.253 +  bool RecomputePosition(nsIFrame* aFrame);
   1.254 +
   1.255 +private:
   1.256 +  nsPresContext* mPresContext; // weak, disconnected in Disconnect
   1.257 +
   1.258 +  bool mRebuildAllStyleData : 1;
   1.259 +  // True if we're already waiting for a refresh notification
   1.260 +  bool mObservingRefreshDriver : 1;
   1.261 +  // True if we're in the middle of a nsRefreshDriver refresh
   1.262 +  bool mInStyleRefresh : 1;
   1.263 +  uint32_t mHoverGeneration;
   1.264 +  nsChangeHint mRebuildAllExtraHint;
   1.265 +
   1.266 +  OverflowChangedTracker mOverflowChangedTracker;
   1.267 +
   1.268 +  // The total number of animation flushes by this frame constructor.
   1.269 +  // Used to keep the layer and animation manager in sync.
   1.270 +  uint64_t mAnimationGeneration;
   1.271 +
   1.272 +  RestyleTracker mPendingRestyles;
   1.273 +  RestyleTracker mPendingAnimationRestyles;
   1.274 +};
   1.275 +
   1.276 +/**
   1.277 + * An ElementRestyler is created for *each* element in a subtree that we
   1.278 + * recompute styles for.
   1.279 + */
   1.280 +class ElementRestyler MOZ_FINAL {
   1.281 +public:
   1.282 +  typedef mozilla::dom::Element Element;
   1.283 +
   1.284 +  // Construct for the root of the subtree that we're restyling.
   1.285 +  ElementRestyler(nsPresContext* aPresContext,
   1.286 +                  nsIFrame* aFrame,
   1.287 +                  nsStyleChangeList* aChangeList,
   1.288 +                  nsChangeHint aHintsHandledByAncestors,
   1.289 +                  RestyleTracker& aRestyleTracker,
   1.290 +                  TreeMatchContext& aTreeMatchContext,
   1.291 +                  nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement);
   1.292 +
   1.293 +  // Construct for an element whose parent is being restyled.
   1.294 +  enum ConstructorFlags {
   1.295 +    FOR_OUT_OF_FLOW_CHILD = 1<<0
   1.296 +  };
   1.297 +  ElementRestyler(const ElementRestyler& aParentRestyler,
   1.298 +                  nsIFrame* aFrame,
   1.299 +                  uint32_t aConstructorFlags);
   1.300 +
   1.301 +  // Construct for a frame whose parent is being restyled, but whose
   1.302 +  // style context is the parent style context for its parent frame.
   1.303 +  // (This is only used for table frames, whose style contexts are used
   1.304 +  // as the parent style context for their outer table frame (table
   1.305 +  // wrapper frame).  We should probably try to get rid of this
   1.306 +  // exception and have the inheritance go the other way.)
   1.307 +  enum ParentContextFromChildFrame { PARENT_CONTEXT_FROM_CHILD_FRAME };
   1.308 +  ElementRestyler(ParentContextFromChildFrame,
   1.309 +                  const ElementRestyler& aParentFrameRestyler,
   1.310 +                  nsIFrame* aFrame);
   1.311 +
   1.312 +  /**
   1.313 +   * Restyle our frame's element and its subtree.
   1.314 +   *
   1.315 +   * Use eRestyle_Self for the aRestyleHint argument to mean
   1.316 +   * "reresolve our style context but not kids", use eRestyle_Subtree
   1.317 +   * to mean "reresolve our style context and kids", and use
   1.318 +   * nsRestyleHint(0) to mean recompute a new style context for our
   1.319 +   * current parent and existing rulenode, and the same for kids.
   1.320 +   */
   1.321 +  void Restyle(nsRestyleHint aRestyleHint);
   1.322 +
   1.323 +  /**
   1.324 +   * mHintsHandled changes over time; it starts off as the hints that
   1.325 +   * have been handled by ancestors, and by the end of Restyle it
   1.326 +   * represents the hints that have been handled for this frame.  This
   1.327 +   * method is intended to be called after Restyle, to find out what
   1.328 +   * hints have been handled for this frame.
   1.329 +   */
   1.330 +  nsChangeHint HintsHandledForFrame() { return mHintsHandled; }
   1.331 +
   1.332 +private:
   1.333 +  /**
   1.334 +   * First half of Restyle().
   1.335 +   */
   1.336 +  void RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint);
   1.337 +
   1.338 +  /**
   1.339 +   * Restyle the children of this frame (and, in turn, their children).
   1.340 +   *
   1.341 +   * Second half of Restyle().
   1.342 +   */
   1.343 +  void RestyleChildren(nsRestyleHint aChildRestyleHint);
   1.344 +
   1.345 +  /**
   1.346 +   * Helper for RestyleSelf().
   1.347 +   */
   1.348 +  void CaptureChange(nsStyleContext* aOldContext,
   1.349 +                     nsStyleContext* aNewContext,
   1.350 +                     nsChangeHint aChangeToAssume);
   1.351 +
   1.352 +  /**
   1.353 +   * Helpers for RestyleChildren().
   1.354 +   */
   1.355 +  void RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint);
   1.356 +  void RestyleBeforePseudo();
   1.357 +  void RestyleAfterPseudo(nsIFrame* aFrame);
   1.358 +  void RestyleContentChildren(nsIFrame* aParent,
   1.359 +                              nsRestyleHint aChildRestyleHint);
   1.360 +  void InitializeAccessibilityNotifications();
   1.361 +  void SendAccessibilityNotifications();
   1.362 +
   1.363 +  enum DesiredA11yNotifications {
   1.364 +    eSkipNotifications,
   1.365 +    eSendAllNotifications,
   1.366 +    eNotifyIfShown
   1.367 +  };
   1.368 +
   1.369 +  enum A11yNotificationType {
   1.370 +    eDontNotify,
   1.371 +    eNotifyShown,
   1.372 +    eNotifyHidden
   1.373 +  };
   1.374 +
   1.375 +private:
   1.376 +  nsPresContext* const mPresContext;
   1.377 +  nsIFrame* const mFrame;
   1.378 +  nsIContent* const mParentContent;
   1.379 +  // |mContent| is the node that we used for rule matching of
   1.380 +  // normal elements (not pseudo-elements) and for which we generate
   1.381 +  // framechange hints if we need them.
   1.382 +  nsIContent* const mContent;
   1.383 +  nsStyleChangeList* const mChangeList;
   1.384 +  // We have already generated change list entries for hints listed in
   1.385 +  // mHintsHandled (initially it's those handled by ancestors, but by
   1.386 +  // the end of Restyle it is those handled for this frame as well).  We
   1.387 +  // need to generate a new change list entry for the frame when its
   1.388 +  // style comparision returns a hint other than one of these hints.
   1.389 +  nsChangeHint mHintsHandled;
   1.390 +  // See nsStyleContext::CalcStyleDifference
   1.391 +  nsChangeHint mParentFrameHintsNotHandledForDescendants;
   1.392 +  nsChangeHint mHintsNotHandledForDescendants;
   1.393 +  RestyleTracker& mRestyleTracker;
   1.394 +  TreeMatchContext& mTreeMatchContext;
   1.395 +  nsIFrame* mResolvedChild; // child that provides our parent style context
   1.396 +
   1.397 +#ifdef ACCESSIBILITY
   1.398 +  const DesiredA11yNotifications mDesiredA11yNotifications;
   1.399 +  DesiredA11yNotifications mKidsDesiredA11yNotifications;
   1.400 +  A11yNotificationType mOurA11yNotification;
   1.401 +  nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement;
   1.402 +  bool mWasFrameVisible;
   1.403 +#endif
   1.404 +};
   1.405 +
   1.406 +} // namespace mozilla
   1.407 +
   1.408 +#endif /* mozilla_RestyleManager_h */

mercurial