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 */