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