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