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

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

mercurial