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 /** 8 * Code responsible for managing style changes: tracking what style 9 * changes need to happen, scheduling them, and doing them. 10 */ 11 12 #ifndef mozilla_GeckoRestyleManager_h 13 #define mozilla_GeckoRestyleManager_h 14 15 #include "mozilla/RestyleLogging.h" 16 #include "mozilla/RestyleManager.h" 17 #include "nsISupportsImpl.h" 18 #include "nsChangeHint.h" 19 #include "RestyleTracker.h" 20 #include "nsPresContext.h" 21 #include "nsRefreshDriver.h" 22 #include "nsRefPtrHashtable.h" 23 #include "nsTransitionManager.h" 24 25 class nsIFrame; 26 class nsStyleChangeList; 27 struct TreeMatchContext; 28 29 namespace mozilla { 30 enum class CSSPseudoElementType : uint8_t; 31 class EventStates; 32 struct UndisplayedNode; 33 34 namespace dom { 35 class Element; 36 } // namespace dom 37 38 class GeckoRestyleManager final : public RestyleManager { 39 public: 40 typedef RestyleManager base_type; 41 42 friend class RestyleTracker; 43 friend class ElementRestyler; 44 45 explicit GeckoRestyleManager(nsPresContext* aPresContext); 46 47 protected: ~GeckoRestyleManager()48 ~GeckoRestyleManager() override { 49 MOZ_ASSERT(!mReframingStyleContexts, 50 "temporary member should be nulled out before destruction"); 51 } 52 53 public: 54 // Forwarded nsIDocumentObserver method, to handle restyling (and 55 // passing the notification to the frame). 56 void ContentStateChanged(nsIContent* aContent, EventStates aStateMask); 57 58 // Forwarded nsIMutationObserver method, to handle restyling. 59 void AttributeWillChange(Element* aElement, int32_t aNameSpaceID, 60 nsAtom* aAttribute, int32_t aModType, 61 const nsAttrValue* aNewValue); 62 // Forwarded nsIMutationObserver method, to handle restyling (and 63 // passing the notification to the frame). 64 void AttributeChanged(Element* aElement, int32_t aNameSpaceID, 65 nsAtom* aAttribute, int32_t aModType, 66 const nsAttrValue* aOldValue); 67 68 // Whether rule matching should skip styles associated with animation SkipAnimationRules()69 bool SkipAnimationRules() const { return mSkipAnimationRules; } 70 SetSkipAnimationRules(bool aSkipAnimationRules)71 void SetSkipAnimationRules(bool aSkipAnimationRules) { 72 mSkipAnimationRules = aSkipAnimationRules; 73 } 74 75 /** 76 * Reparent the style contexts of this frame subtree. The parent frame of 77 * aFrame must be changed to the new parent before this function is called; 78 * the new parent style context will be automatically computed based on the 79 * new position in the frame tree. 80 * 81 * @param aFrame the root of the subtree to reparent. Must not be null. 82 */ 83 nsresult ReparentStyleContext(nsIFrame* aFrame); 84 85 private: 86 /** 87 * Reparent the descendants of aFrame. This is used by ReparentStyleContext 88 * and shouldn't be called by anyone else. aProviderChild, if non-null, is a 89 * child that was the style parent for aFrame and hence shouldn't be 90 * reparented. 91 */ 92 void ReparentFrameDescendants(nsIFrame* aFrame, nsIFrame* aProviderChild); 93 94 public: ClearSelectors()95 void ClearSelectors() { mPendingRestyles.ClearSelectors(); } 96 PostRestyleEventForLazyConstruction()97 void PostRestyleEventForLazyConstruction() { PostRestyleEventInternal(); } 98 99 private: 100 void PostRestyleEventInternal(); 101 102 // Used when restyling an element with a frame. 103 void ComputeAndProcessStyleChange(nsIFrame* aFrame, nsChangeHint aMinChange, 104 RestyleTracker& aRestyleTracker, 105 nsRestyleHint aRestyleHint, 106 const RestyleHintData& aRestyleHintData); 107 108 // Used when restyling a display:contents element. 109 void ComputeAndProcessStyleChange(GeckoStyleContext* aNewContext, 110 Element* aElement, nsChangeHint aMinChange, 111 RestyleTracker& aRestyleTracker, 112 nsRestyleHint aRestyleHint, 113 const RestyleHintData& aRestyleHintData); 114 115 public: 116 /** 117 * In order to start CSS transitions on elements that are being 118 * reframed, we need to stash their style contexts somewhere during 119 * the reframing process. 120 * 121 * In all cases, the content node in the hash table is the real 122 * content node, not the anonymous content node we create for ::before 123 * or ::after. The content node passed to the Get and Put methods is, 124 * however, the content node to be associate with the frame's style 125 * context. 126 */ 127 typedef nsRefPtrHashtable<nsRefPtrHashKey<nsIContent>, GeckoStyleContext> 128 ReframingStyleContextTable; 129 class MOZ_STACK_CLASS ReframingStyleContexts final { 130 public: 131 /** 132 * Construct a ReframingStyleContexts object. The caller must 133 * ensure that aRestyleManager lives at least as long as the 134 * object. (This is generally easy since the caller is typically a 135 * method of RestyleManager.) 136 */ 137 explicit ReframingStyleContexts(GeckoRestyleManager* aRestyleManager); 138 ~ReframingStyleContexts(); 139 Put(nsIContent * aContent,GeckoStyleContext * aStyleContext)140 void Put(nsIContent* aContent, GeckoStyleContext* aStyleContext) { 141 MOZ_ASSERT(aContent); 142 CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType(); 143 if (pseudoType == CSSPseudoElementType::NotPseudo) { 144 mElementContexts.Put(aContent, aStyleContext); 145 } else if (pseudoType == CSSPseudoElementType::before) { 146 MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == 147 nsGkAtoms::mozgeneratedcontentbefore); 148 mBeforePseudoContexts.Put(aContent->GetParent(), aStyleContext); 149 } else if (pseudoType == CSSPseudoElementType::after) { 150 MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == 151 nsGkAtoms::mozgeneratedcontentafter); 152 mAfterPseudoContexts.Put(aContent->GetParent(), aStyleContext); 153 } 154 } 155 Get(nsIContent * aContent,CSSPseudoElementType aPseudoType)156 GeckoStyleContext* Get(nsIContent* aContent, 157 CSSPseudoElementType aPseudoType) { 158 MOZ_ASSERT(aContent); 159 if (aPseudoType == CSSPseudoElementType::NotPseudo) { 160 return mElementContexts.GetWeak(aContent); 161 } 162 if (aPseudoType == CSSPseudoElementType::before) { 163 MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == 164 nsGkAtoms::mozgeneratedcontentbefore); 165 return mBeforePseudoContexts.GetWeak(aContent->GetParent()); 166 } 167 if (aPseudoType == CSSPseudoElementType::after) { 168 MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == 169 nsGkAtoms::mozgeneratedcontentafter); 170 return mAfterPseudoContexts.GetWeak(aContent->GetParent()); 171 } 172 MOZ_ASSERT(false, "unexpected aPseudoType"); 173 return nullptr; 174 } 175 176 private: 177 GeckoRestyleManager* mRestyleManager; 178 AutoRestore<ReframingStyleContexts*> mRestorePointer; 179 ReframingStyleContextTable mElementContexts; 180 ReframingStyleContextTable mBeforePseudoContexts; 181 ReframingStyleContextTable mAfterPseudoContexts; 182 }; 183 184 /** 185 * Return the current ReframingStyleContexts struct, or null if we're 186 * not currently in a restyling operation. 187 */ GetReframingStyleContexts()188 ReframingStyleContexts* GetReframingStyleContexts() { 189 return mReframingStyleContexts; 190 } 191 192 /** 193 * Try initiating a transition for an element or a ::before or ::after 194 * pseudo-element, given an old and new style context. This may 195 * change the new style context if a transition is started. Returns 196 * true if it does change aNewStyleContext. 197 * 198 * For the pseudo-elements, aContent must be the anonymous content 199 * that we're creating for that pseudo-element, not the real element. 200 */ 201 static bool TryInitiatingTransition( 202 nsPresContext* aPresContext, nsIContent* aContent, 203 GeckoStyleContext* aOldStyleContext, 204 RefPtr<GeckoStyleContext>* aNewStyleContext /* inout */); 205 206 public: 207 // Process any pending restyles. This should be called after 208 // CreateNeededFrames. 209 // Note: It's the caller's responsibility to make sure to wrap a 210 // ProcessPendingRestyles call in a view update batch and a script blocker. 211 // This function does not call ProcessAttachedQueue() on the binding manager. 212 // If the caller wants that to happen synchronously, it needs to handle that 213 // itself. 214 void ProcessPendingRestyles(); 215 216 private: 217 // ProcessPendingRestyles calls into one of our RestyleTracker 218 // objects. It then calls back to these functions at the beginning 219 // and end of its work. 220 void BeginProcessingRestyles(RestyleTracker& aRestyleTracker); 221 void EndProcessingRestyles(); 222 223 public: 224 // Update styles for animations that are running on the compositor and 225 // whose updating is suppressed on the main thread (to save 226 // unnecessary work), while leaving all other aspects of style 227 // out-of-date. 228 // 229 // Performs an animation-only style flush to make styles from 230 // throttled transitions up-to-date prior to processing an unrelated 231 // style change, so that any transitions triggered by that style 232 // change produce correct results. 233 // 234 // In more detail: when we're able to run animations on the 235 // compositor, we sometimes "throttle" these animations by skipping 236 // updating style data on the main thread. However, whenever we 237 // process a normal (non-animation) style change, any changes in 238 // computed style on elements that have transition-* properties set 239 // may need to trigger new transitions; this process requires knowing 240 // both the old and new values of the property. To do this correctly, 241 // we need to have an up-to-date *old* value of the property on the 242 // primary frame. So the purpose of the mini-flush is to update the 243 // style for all throttled transitions and animations to the current 244 // animation state without making any other updates, so that when we 245 // process the queued style updates we'll have correct old data to 246 // compare against. When we do this, we don't bother touching frames 247 // other than primary frames. 248 void UpdateOnlyAnimationStyles(); 249 250 // Rebuilds all style data by throwing out the old rule tree and 251 // building a new one, and additionally applying aExtraHint (which 252 // must not contain nsChangeHint_ReconstructFrame) to the root frame. 253 // 254 // aRestyleHint says which restyle hint to use for the computation; 255 // the only sensible values to use are eRestyle_Subtree (which says 256 // that the rebuild must run selector matching) and nsRestyleHint(0) 257 // (which says that rerunning selector matching is not required. (The 258 // method adds eRestyle_ForceDescendants internally, and including it 259 // in the restyle hint is harmless; some callers (e.g., 260 // nsPresContext::MediaFeatureValuesChanged) might do this for their 261 // own reasons.) 262 void RebuildAllStyleData(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint); 263 264 /** 265 * Notify the frame constructor that an element needs to have its 266 * style recomputed. 267 * @param aElement: The element to be restyled. 268 * @param aRestyleHint: Which nodes need to have selector matching run 269 * on them. 270 * @param aMinChangeHint: A minimum change hint for aContent and its 271 * descendants. 272 * @param aRestyleHintData: Additional data to go with aRestyleHint. 273 */ 274 void PostRestyleEvent(Element* aElement, nsRestyleHint aRestyleHint, 275 nsChangeHint aMinChangeHint, 276 const RestyleHintData* aRestyleHintData = nullptr); 277 278 public: 279 /** 280 * Asynchronously clear style data from the root frame downwards and ensure 281 * it will all be rebuilt. This is safe to call anytime; it will schedule 282 * a restyle and take effect next time style changes are flushed. 283 * This method is used to recompute the style data when some change happens 284 * outside of any style rules, like a color preference change or a change 285 * in a system font size, or to fix things up when an optimization in the 286 * style data has become invalid. We assume that the root frame will not 287 * need to be reframed. 288 * 289 * For parameters, see RebuildAllStyleData. 290 */ 291 void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint, 292 nsRestyleHint aRestyleHint); 293 294 #ifdef DEBUG InRebuildAllStyleData()295 bool InRebuildAllStyleData() const { return mInRebuildAllStyleData; } 296 #endif 297 298 #ifdef RESTYLE_LOGGING 299 /** 300 * Returns whether a restyle event currently being processed by this 301 * GeckoRestyleManager should be logged. 302 */ ShouldLogRestyle()303 bool ShouldLogRestyle() { return ShouldLogRestyle(PresContext()); } 304 305 /** 306 * Returns whether a restyle event currently being processed for the 307 * document with the specified nsPresContext should be logged. 308 */ ShouldLogRestyle(nsPresContext * aPresContext)309 static bool ShouldLogRestyle(nsPresContext* aPresContext) { 310 return aPresContext->RestyleLoggingEnabled() && 311 (!aPresContext->TransitionManager()->InAnimationOnlyStyleUpdate() || 312 AnimationRestyleLoggingEnabled()); 313 } 314 RestyleLoggingInitiallyEnabled()315 static bool RestyleLoggingInitiallyEnabled() { 316 static bool enabled = getenv("MOZ_DEBUG_RESTYLE") != 0; 317 return enabled; 318 } 319 AnimationRestyleLoggingEnabled()320 static bool AnimationRestyleLoggingEnabled() { 321 static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0; 322 return animations; 323 } 324 325 // Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of 326 // style struct names -- such as "Font,SVGReset" -- to log the style context 327 // tree and those cached struct pointers before each restyle. This 328 // function returns a bitfield of the structs named in the 329 // environment variable. 330 static uint32_t StructsToLog(); 331 332 static nsCString StructNamesToString(uint32_t aSIDs); LoggingDepth()333 int32_t& LoggingDepth() { return mLoggingDepth; } 334 #endif 335 IsProcessingRestyles()336 bool IsProcessingRestyles() { return mIsProcessingRestyles; } 337 bool HasPendingRestyles() const; 338 339 private: StyleSet()340 inline nsStyleSet* StyleSet() const { 341 MOZ_ASSERT(PresContext()->StyleSet()->IsGecko(), 342 "GeckoRestyleManager should only be used with a Gecko-flavored " 343 "style backend"); 344 return PresContext()->StyleSet()->AsGecko(); 345 } 346 347 /* aMinHint is the minimal change that should be made to the element */ 348 // XXXbz do we really need the aPrimaryFrame argument here? 349 void RestyleElement(Element* aElement, nsIFrame* aPrimaryFrame, 350 nsChangeHint aMinHint, RestyleTracker& aRestyleTracker, 351 nsRestyleHint aRestyleHint, 352 const RestyleHintData& aRestyleHintData); 353 354 void StartRebuildAllStyleData(RestyleTracker& aRestyleTracker); 355 void FinishRebuildAllStyleData(); 356 ShouldStartRebuildAllFor(RestyleTracker & aRestyleTracker)357 bool ShouldStartRebuildAllFor(RestyleTracker& aRestyleTracker) { 358 // When we process our primary restyle tracker and we have a pending 359 // rebuild-all, we need to process it. 360 return mDoRebuildAllStyleData && &aRestyleTracker == &mPendingRestyles; 361 } 362 ProcessRestyles(RestyleTracker & aRestyleTracker)363 void ProcessRestyles(RestyleTracker& aRestyleTracker) { 364 // Fast-path the common case (esp. for the animation restyle 365 // tracker) of not having anything to do. 366 if (aRestyleTracker.Count() || ShouldStartRebuildAllFor(aRestyleTracker)) { 367 IncrementRestyleGeneration(); 368 aRestyleTracker.DoProcessRestyles(); 369 } 370 } 371 372 private: 373 // True if we need to reconstruct the rule tree the next time we 374 // process restyles. 375 bool mDoRebuildAllStyleData : 1; 376 // True if we're currently in the process of reconstructing the rule tree. 377 bool mInRebuildAllStyleData : 1; 378 // Whether rule matching should skip styles associated with animation 379 bool mSkipAnimationRules : 1; 380 bool mHavePendingNonAnimationRestyles : 1; 381 382 nsChangeHint mRebuildAllExtraHint; 383 nsRestyleHint mRebuildAllRestyleHint; 384 385 ReframingStyleContexts* mReframingStyleContexts; 386 387 RestyleTracker mPendingRestyles; 388 389 // Are we currently in the middle of a call to ProcessRestyles? 390 // This flag is used both as a debugging aid to assert that we are not 391 // performing nested calls to ProcessPendingRestyles, as well as to ignore 392 // redundant calls to IncrementAnimationGeneration. 393 bool mIsProcessingRestyles; 394 395 #ifdef RESTYLE_LOGGING 396 int32_t mLoggingDepth; 397 #endif 398 }; 399 400 /** 401 * An ElementRestyler is created for *each* element in a subtree that we 402 * recompute styles for. 403 */ 404 class ElementRestyler final { 405 public: 406 typedef mozilla::dom::Element Element; 407 408 struct ContextToClear { 409 RefPtr<GeckoStyleContext> mStyleContext; 410 uint32_t mStructs; 411 }; 412 413 // Construct for the root of the subtree that we're restyling. 414 ElementRestyler(nsPresContext* aPresContext, nsIFrame* aFrame, 415 nsStyleChangeList* aChangeList, 416 nsChangeHint aHintsHandledByAncestors, 417 RestyleTracker& aRestyleTracker, 418 nsTArray<nsCSSSelector*>& aSelectorsForDescendants, 419 TreeMatchContext& aTreeMatchContext, 420 nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement, 421 nsTArray<ContextToClear>& aContextsToClear, 422 nsTArray<RefPtr<GeckoStyleContext>>& aSwappedStructOwners); 423 424 // Construct for an element whose parent is being restyled. 425 enum ConstructorFlags { FOR_OUT_OF_FLOW_CHILD = 1 << 0 }; 426 ElementRestyler(const ElementRestyler& aParentRestyler, nsIFrame* aFrame, 427 uint32_t aConstructorFlags); 428 429 // Construct for a frame whose parent is being restyled, but whose 430 // style context is the parent style context for its parent frame. 431 // (This is only used for table frames, whose style contexts are used 432 // as the parent style context for their table wrapper frame. We should 433 // probably try to get rid of this exception and have the inheritance go 434 // the other way.) 435 enum ParentContextFromChildFrame { PARENT_CONTEXT_FROM_CHILD_FRAME }; 436 ElementRestyler(ParentContextFromChildFrame, 437 const ElementRestyler& aParentFrameRestyler, 438 nsIFrame* aFrame); 439 440 // For restyling undisplayed content only (mFrame==null). 441 ElementRestyler(nsPresContext* aPresContext, nsIContent* aContent, 442 nsStyleChangeList* aChangeList, 443 nsChangeHint aHintsHandledByAncestors, 444 RestyleTracker& aRestyleTracker, 445 nsTArray<nsCSSSelector*>& aSelectorsForDescendants, 446 TreeMatchContext& aTreeMatchContext, 447 nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement, 448 nsTArray<ContextToClear>& aContextsToClear, 449 nsTArray<RefPtr<GeckoStyleContext>>& aSwappedStructOwners); 450 451 /** 452 * Restyle our frame's element and its subtree. 453 * 454 * Use eRestyle_Self for the aRestyleHint argument to mean 455 * "reresolve our style context but not kids", use eRestyle_Subtree 456 * to mean "reresolve our style context and kids", and use 457 * nsRestyleHint(0) to mean recompute a new style context for our 458 * current parent and existing rulenode, and the same for kids. 459 */ 460 void Restyle(nsRestyleHint aRestyleHint); 461 462 /** 463 * mHintsHandledBySelf changes over time; it starts off as nsChangeHint(0), 464 * and by the end of Restyle it represents the hints that have been handled 465 * for this frame. This method is intended to be called after Restyle, to 466 * find out what hints have been handled for this frame. 467 */ HintsHandledForFrame()468 nsChangeHint HintsHandledForFrame() { return mHintsHandledBySelf; } 469 470 /** 471 * Called from GeckoRestyleManager::ComputeAndProcessStyleChange to restyle 472 * children of a display:contents element. 473 */ 474 void RestyleChildrenOfDisplayContentsElement( 475 nsIFrame* aParentFrame, GeckoStyleContext* aNewContext, 476 nsChangeHint aMinHint, RestyleTracker& aRestyleTracker, 477 nsRestyleHint aRestyleHint, const RestyleHintData& aRestyleHintData); 478 479 /** 480 * Re-resolve the style contexts for a frame tree, building aChangeList 481 * based on the resulting style changes, plus aMinChange applied to aFrame. 482 */ 483 static void ComputeStyleChangeFor( 484 nsIFrame* aFrame, nsStyleChangeList* aChangeList, nsChangeHint aMinChange, 485 RestyleTracker& aRestyleTracker, nsRestyleHint aRestyleHint, 486 const RestyleHintData& aRestyleHintData, 487 nsTArray<ContextToClear>& aContextsToClear, 488 nsTArray<RefPtr<GeckoStyleContext>>& aSwappedStructOwners); 489 490 #ifdef RESTYLE_LOGGING ShouldLogRestyle()491 bool ShouldLogRestyle() { 492 return GeckoRestyleManager::ShouldLogRestyle(mPresContext); 493 } 494 #endif 495 496 private: 497 inline nsStyleSet* StyleSet() const; 498 499 // Enum class for the result of RestyleSelf, which indicates whether the 500 // restyle procedure should continue to the children, and how. 501 // 502 // These values must be ordered so that later values imply that all 503 // the work of the earlier values is also done. 504 enum class RestyleResult : uint8_t { 505 // default initial value 506 eNone, 507 508 // we left the old style context on the frame; do not restyle children 509 eStop, 510 511 // we got a new style context on this frame, but we know that children 512 // do not depend on the changed values; do not restyle children 513 eStopWithStyleChange, 514 515 // continue restyling children 516 eContinue, 517 518 // continue restyling children with eRestyle_ForceDescendants set 519 eContinueAndForceDescendants 520 }; 521 522 struct SwapInstruction { 523 RefPtr<GeckoStyleContext> mOldContext; 524 RefPtr<GeckoStyleContext> mNewContext; 525 uint32_t mStructsToSwap; 526 }; 527 528 /** 529 * First half of Restyle(). 530 */ 531 RestyleResult RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint, 532 uint32_t* aSwappedStructs, 533 nsTArray<SwapInstruction>& aSwaps); 534 535 /** 536 * Restyle the children of this frame (and, in turn, their children). 537 * 538 * Second half of Restyle(). 539 */ 540 void RestyleChildren(nsRestyleHint aChildRestyleHint); 541 542 /** 543 * Returns true iff a selector in mSelectorsForDescendants matches aElement. 544 * This is called when processing a eRestyle_SomeDescendants restyle hint. 545 */ 546 bool SelectorMatchesForRestyle(Element* aElement); 547 548 /** 549 * Returns true iff aRestyleHint indicates that we should be restyling. 550 * Specifically, this will return true when eRestyle_Self or 551 * eRestyle_Subtree is present, or if eRestyle_SomeDescendants is 552 * present and the specified element matches one of the selectors in 553 * mSelectorsForDescendants. 554 */ 555 bool MustRestyleSelf(nsRestyleHint aRestyleHint, Element* aElement); 556 557 /** 558 * Returns true iff aRestyleHint indicates that we can call 559 * ReparentStyleContext rather than any other restyling method of 560 * nsStyleSet that looks up a new rule node, and if we are 561 * not in the process of reconstructing the whole rule tree. 562 * This is used to check whether it is appropriate to call 563 * ReparentStyleContext. 564 */ 565 bool CanReparentStyleContext(nsRestyleHint aRestyleHint); 566 567 /** 568 * Helpers for Restyle(). 569 */ 570 bool MoveStyleContextsForContentChildren( 571 nsIFrame* aParent, GeckoStyleContext* aOldContext, 572 nsTArray<GeckoStyleContext*>& aContextsToMove); 573 bool MoveStyleContextsForChildren(GeckoStyleContext* aOldContext); 574 575 /** 576 * Helpers for RestyleSelf(). 577 */ 578 void CaptureChange(GeckoStyleContext* aOldContext, 579 GeckoStyleContext* aNewContext, 580 nsChangeHint aChangeToAssume, uint32_t* aEqualStructs, 581 uint32_t* aSamePointerStructs); 582 void ComputeRestyleResultFromFrame(nsIFrame* aSelf, 583 RestyleResult& aRestyleResult, 584 bool& aCanStopWithStyleChange); 585 void ComputeRestyleResultFromNewContext(nsIFrame* aSelf, 586 GeckoStyleContext* aNewContext, 587 RestyleResult& aRestyleResult, 588 bool& aCanStopWithStyleChange); 589 590 // Helpers for RestyleChildren(). 591 void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint); 592 bool MustCheckUndisplayedContent(nsIFrame* aFrame, 593 nsIContent*& aUndisplayedParent); 594 595 /** 596 * In the following two methods, aParentStyleContext is either 597 * mFrame->StyleContext() if we have a frame, or a display:contents 598 * style context if we don't. 599 */ 600 void DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint, 601 nsIContent* aParent, 602 GeckoStyleContext* aParentStyleContext); 603 void RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint, 604 UndisplayedNode* aUndisplayed, 605 nsIContent* aUndisplayedParent, 606 GeckoStyleContext* aParentStyleContext, 607 const StyleDisplay aDisplay); 608 void MaybeReframeForBeforePseudo(); 609 void MaybeReframeForAfterPseudo(nsIFrame* aFrame); 610 void MaybeReframeForPseudo(CSSPseudoElementType aPseudoType, 611 nsIFrame* aGenConParentFrame, nsIFrame* aFrame, 612 nsIContent* aContent, 613 GeckoStyleContext* aStyleContext); 614 #ifdef DEBUG 615 bool MustReframeForBeforePseudo(); 616 bool MustReframeForAfterPseudo(nsIFrame* aFrame); 617 #endif 618 bool MustReframeForPseudo(CSSPseudoElementType aPseudoType, 619 nsIFrame* aGenConParentFrame, nsIFrame* aFrame, 620 nsIContent* aContent, 621 GeckoStyleContext* aStyleContext); 622 void RestyleContentChildren(nsIFrame* aParent, 623 nsRestyleHint aChildRestyleHint); 624 void InitializeAccessibilityNotifications(nsStyleContext* aNewContext); 625 void SendAccessibilityNotifications(); 626 627 enum DesiredA11yNotifications { 628 eSkipNotifications, 629 eSendAllNotifications, 630 eNotifyIfShown 631 }; 632 633 enum A11yNotificationType { eDontNotify, eNotifyShown, eNotifyHidden }; 634 635 // These methods handle the eRestyle_SomeDescendants hint by traversing 636 // down the frame tree (and then when reaching undisplayed content, 637 // the flattened content tree) find elements that match a selector 638 // in mSelectorsForDescendants and call AddPendingRestyle for them. 639 void ConditionallyRestyleChildren(); 640 void ConditionallyRestyleChildren(nsIFrame* aFrame, Element* aRestyleRoot); 641 void ConditionallyRestyleContentChildren(nsIFrame* aFrame, 642 Element* aRestyleRoot); 643 void ConditionallyRestyleUndisplayedDescendants(nsIFrame* aFrame, 644 Element* aRestyleRoot); 645 void DoConditionallyRestyleUndisplayedDescendants(nsIContent* aParent, 646 Element* aRestyleRoot); 647 void ConditionallyRestyleUndisplayedNodes(UndisplayedNode* aUndisplayed, 648 nsIContent* aUndisplayedParent, 649 const StyleDisplay aDisplay, 650 Element* aRestyleRoot); 651 void ConditionallyRestyleContentDescendants(Element* aElement, 652 Element* aRestyleRoot); 653 bool ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot); 654 bool ConditionallyRestyle(Element* aElement, Element* aRestyleRoot); 655 656 #ifdef RESTYLE_LOGGING LoggingDepth()657 int32_t& LoggingDepth() { return mLoggingDepth; } 658 #endif 659 660 #ifdef DEBUG 661 static nsCString RestyleResultToString(RestyleResult aRestyleResult); 662 #endif 663 664 private: 665 nsPresContext* const mPresContext; 666 nsIFrame* const mFrame; 667 nsIContent* const mParentContent; 668 // |mContent| is the node that we used for rule matching of 669 // normal elements (not pseudo-elements) and for which we generate 670 // framechange hints if we need them. 671 nsIContent* const mContent; 672 nsStyleChangeList* const mChangeList; 673 // Hints that we computed on an ancestor (and which we already have 674 // generated a change list entry for). When we traverse to children 675 // after restyling an element, this field accumulates the hints 676 // generated for that element. 677 const nsChangeHint mHintsHandledByAncestors; 678 // Hints that we have computed so far the current node. This is 679 // initially zero, and accumulates hints for each same-style continuation 680 // and {ib} split sibling we restyle for the node. 681 nsChangeHint mHintsHandledBySelf; 682 RestyleTracker& mRestyleTracker; 683 nsTArray<nsCSSSelector*>& mSelectorsForDescendants; 684 TreeMatchContext& mTreeMatchContext; 685 nsIFrame* mResolvedChild; // child that provides our parent style context 686 // Array of style context subtrees in which we need to clear out cached 687 // structs at the end of the restyle (after change hints have been 688 // processed). 689 nsTArray<ContextToClear>& mContextsToClear; 690 // Style contexts that had old structs swapped into it and which should 691 // stay alive until the end of the restyle. (See comment in 692 // ElementRestyler::Restyle.) 693 nsTArray<RefPtr<GeckoStyleContext>>& mSwappedStructOwners; 694 // Whether this is the root of the restyle. 695 bool mIsRootOfRestyle; 696 697 #ifdef ACCESSIBILITY 698 const DesiredA11yNotifications mDesiredA11yNotifications; 699 DesiredA11yNotifications mKidsDesiredA11yNotifications; 700 A11yNotificationType mOurA11yNotification; 701 nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement; 702 bool mWasFrameVisible; 703 #endif 704 705 #ifdef RESTYLE_LOGGING 706 int32_t mLoggingDepth; 707 #endif 708 }; 709 710 /** 711 * This pushes any display:contents nodes onto a TreeMatchContext. 712 * Use it before resolving style for kids of aParent where aParent 713 * (and further ancestors) may be display:contents nodes which have 714 * not yet been pushed onto TreeMatchContext. 715 */ 716 class MOZ_RAII AutoDisplayContentsAncestorPusher final { 717 public: 718 typedef mozilla::dom::Element Element; 719 AutoDisplayContentsAncestorPusher(TreeMatchContext& aTreeMatchContext, 720 nsPresContext* aPresContext, 721 nsIContent* aParent); 722 ~AutoDisplayContentsAncestorPusher(); IsEmpty()723 bool IsEmpty() const { return mAncestors.Length() == 0; } 724 725 private: 726 TreeMatchContext& mTreeMatchContext; 727 nsPresContext* const mPresContext; 728 AutoTArray<mozilla::dom::Element*, 4> mAncestors; 729 }; 730 731 } // namespace mozilla 732 733 #endif /* mozilla_GeckoRestyleManager_h */ 734