layout/base/RestyleManager.h

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

mercurial