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 /* constants for what needs to be recomputed in response to style changes */
7
8 #ifndef nsChangeHint_h___
9 #define nsChangeHint_h___
10
11 #include "mozilla/Types.h"
12 #include "nsDebug.h"
13 #include "nsTArray.h"
14
15 struct nsCSSSelector;
16
17 // Defines for various style related constants
18
19 enum nsChangeHint {
20 // change was visual only (e.g., COLOR=)
21 // Invalidates all descendant frames (including following
22 // placeholders to out-of-flow frames).
23 nsChangeHint_RepaintFrame = 1 << 0,
24
25 // For reflow, we want flags to give us arbitrary FrameNeedsReflow behavior.
26 // just do a FrameNeedsReflow.
27 nsChangeHint_NeedReflow = 1 << 1,
28
29 // Invalidate intrinsic widths on the frame's ancestors. Must not be set
30 // without setting nsChangeHint_NeedReflow.
31 nsChangeHint_ClearAncestorIntrinsics = 1 << 2,
32
33 // Invalidate intrinsic widths on the frame's descendants. Must not be set
34 // without also setting nsChangeHint_ClearAncestorIntrinsics.
35 nsChangeHint_ClearDescendantIntrinsics = 1 << 3,
36
37 // Force unconditional reflow of all descendants. Must not be set without
38 // setting nsChangeHint_NeedReflow, but is independent of both the
39 // Clear*Intrinsics flags.
40 nsChangeHint_NeedDirtyReflow = 1 << 4,
41
42 // change requires view to be updated, if there is one (e.g., clip:).
43 // Updates all descendants (including following placeholders to out-of-flows).
44 nsChangeHint_SyncFrameView = 1 << 5,
45
46 // The currently shown mouse cursor needs to be updated
47 nsChangeHint_UpdateCursor = 1 << 6,
48
49 /**
50 * Used when the computed value (a URI) of one or more of an element's
51 * filter/mask/clip/etc CSS properties changes, causing the element's frame
52 * to start/stop referencing (or reference different) SVG resource elements.
53 * (_Not_ used to handle changes to referenced resource elements.) Using this
54 * hint results in nsSVGEffects::UpdateEffects being called on the element's
55 * frame.
56 */
57 nsChangeHint_UpdateEffects = 1 << 7,
58
59 /**
60 * Visual change only, but the change can be handled entirely by
61 * updating the layer(s) for the frame.
62 * Updates all descendants (including following placeholders to out-of-flows).
63 */
64 nsChangeHint_UpdateOpacityLayer = 1 << 8,
65 /**
66 * Updates all descendants. Any placeholder descendants' out-of-flows
67 * are also descendants of the transformed frame, so they're updated.
68 */
69 nsChangeHint_UpdateTransformLayer = 1 << 9,
70
71 /**
72 * Change requires frame change (e.g., display:).
73 * Reconstructs all frame descendants, including following placeholders
74 * to out-of-flows.
75 *
76 * Note that this subsumes all the other change hints. (see
77 * RestyleManager::ProcessRestyledFrames for details).
78 */
79 nsChangeHint_ReconstructFrame = 1 << 10,
80
81 /**
82 * The frame's overflow area has changed. Does not update any descendant
83 * frames.
84 */
85 nsChangeHint_UpdateOverflow = 1 << 11,
86
87 /**
88 * The overflow area of the frame and all of its descendants has changed. This
89 * can happen through a text-decoration change.
90 */
91 nsChangeHint_UpdateSubtreeOverflow = 1 << 12,
92
93 /**
94 * The frame's overflow area has changed, through a change in its transform.
95 * In other words, the frame's pre-transform overflow is unchanged, but
96 * its post-transform overflow has changed, and thus its effect on its
97 * parent's overflow has changed. If the pre-transform overflow has
98 * changed, see nsChangeHint_UpdateOverflow.
99 * Does not update any descendant frames.
100 */
101 nsChangeHint_UpdatePostTransformOverflow = 1 << 13,
102
103 /**
104 * This frame's effect on its parent's overflow area has changed.
105 * (But neither its pre-transform nor post-transform overflow have
106 * changed; if those are the case, see
107 * nsChangeHint_UpdatePostTransformOverflow.)
108 */
109 nsChangeHint_UpdateParentOverflow = 1 << 14,
110
111 /**
112 * The children-only transform of an SVG frame changed, requiring the
113 * overflow rects of the frame's immediate children to be updated.
114 */
115 nsChangeHint_ChildrenOnlyTransform = 1 << 15,
116
117 /**
118 * The frame's offsets have changed, while its dimensions might have
119 * changed as well. This hint is used for positioned frames if their
120 * offset changes. If we decide that the dimensions are likely to
121 * change, this will trigger a reflow.
122 *
123 * Note that this should probably be used in combination with
124 * nsChangeHint_UpdateOverflow in order to get the overflow areas of
125 * the ancestors updated as well.
126 */
127 nsChangeHint_RecomputePosition = 1 << 16,
128
129 /**
130 * Behaves like ReconstructFrame, but only if the frame has descendants
131 * that are absolutely or fixed position. Use this hint when a style change
132 * has changed whether the frame is a container for fixed-pos or abs-pos
133 * elements, but reframing is otherwise not needed.
134 *
135 * Note that nsStyleContext::CalcStyleDifference adjusts results
136 * returned by style struct CalcDifference methods to return this hint
137 * only if there was a change to whether the element's overall style
138 * indicates that it establishes a containing block.
139 */
140 nsChangeHint_UpdateContainingBlock = 1 << 17,
141
142 /**
143 * This change hint has *no* change handling behavior. However, it
144 * exists to be a non-inherited hint, because when the border-style
145 * changes, and it's inherited by a child, that might require a reflow
146 * due to the border-width change on the child.
147 */
148 nsChangeHint_BorderStyleNoneChange = 1 << 18,
149
150 /**
151 * SVG textPath needs to be recomputed because the path has changed.
152 * This means that the glyph positions of the text need to be recomputed.
153 */
154 nsChangeHint_UpdateTextPath = 1 << 19,
155
156 /**
157 * This will schedule an invalidating paint. This is useful if something
158 * has changed which will be invalidated by DLBI.
159 */
160 nsChangeHint_SchedulePaint = 1 << 20,
161
162 /**
163 * A hint reflecting that style data changed with no change handling
164 * behavior. We need to return this, rather than nsChangeHint(0),
165 * so that certain optimizations that manipulate the style context tree are
166 * correct.
167 *
168 * nsChangeHint_NeutralChange must be returned by CalcDifference on a given
169 * style struct if the data in the style structs are meaningfully different
170 * and if no other change hints are returned. If any other change hints are
171 * set, then nsChangeHint_NeutralChange need not also be included, but it is
172 * safe to do so. (An example of style structs having non-meaningfully
173 * different data would be cached information that would be re-calculated
174 * to the same values, such as nsStyleBorder::mSubImages.)
175 */
176 nsChangeHint_NeutralChange = 1 << 21,
177
178 /**
179 * This will cause rendering observers to be invalidated.
180 */
181 nsChangeHint_InvalidateRenderingObservers = 1 << 22,
182
183 /**
184 * Indicates that the reflow changes the size or position of the
185 * element, and thus the reflow must start from at least the frame's
186 * parent.
187 */
188 nsChangeHint_ReflowChangesSizeOrPosition = 1 << 23,
189
190 /**
191 * Indicates that the style changes the computed BSize --- e.g. 'height'.
192 */
193 nsChangeHint_UpdateComputedBSize = 1 << 24,
194
195 /**
196 * Indicates that the 'opacity' property changed between 1 and non-1.
197 *
198 * Used as extra data for handling UpdateOpacityLayer hints.
199 *
200 * Note that we do not send this hint if the non-1 value was 0.99 or
201 * greater, since in that case we send a RepaintFrame hint instead.
202 */
203 nsChangeHint_UpdateUsesOpacity = 1 << 25,
204
205 /**
206 * Indicates that the 'background-position' property changed.
207 * Regular frames can invalidate these changes using DLBI, but
208 * for some frame types we need to repaint the whole frame because
209 * the frame does not build individual background image display items
210 * for each background layer.
211 */
212 nsChangeHint_UpdateBackgroundPosition = 1 << 26,
213
214 /**
215 * Indicates that a frame has changed to or from having the CSS
216 * transform property set.
217 */
218 nsChangeHint_AddOrRemoveTransform = 1 << 27,
219
220 // IMPORTANT NOTE: When adding new hints, consider whether you need
221 // to add them to NS_HintsNotHandledForDescendantsIn() below. Please
222 // also add them to RestyleManager::ChangeHintToString and modify
223 // nsChangeHint_AllHints below accordingly.
224
225 /**
226 * Dummy hint value for all hints. It exists for compile time check.
227 */
228 nsChangeHint_AllHints = (1 << 28) - 1,
229 };
230
231 // Redefine these operators to return nothing. This will catch any use
232 // of these operators on hints. We should not be using these operators
233 // on nsChangeHints
234 inline void operator<(nsChangeHint s1, nsChangeHint s2) {}
235 inline void operator>(nsChangeHint s1, nsChangeHint s2) {}
236 inline void operator!=(nsChangeHint s1, nsChangeHint s2) {}
237 inline void operator==(nsChangeHint s1, nsChangeHint s2) {}
238 inline void operator<=(nsChangeHint s1, nsChangeHint s2) {}
239 inline void operator>=(nsChangeHint s1, nsChangeHint s2) {}
240
241 // Operators on nsChangeHints
242
243 // Returns true iff the second hint contains all the hints of the first hint
NS_IsHintSubset(nsChangeHint aSubset,nsChangeHint aSuperSet)244 inline bool NS_IsHintSubset(nsChangeHint aSubset, nsChangeHint aSuperSet) {
245 return (aSubset & aSuperSet) == aSubset;
246 }
247
248 // The functions below need an integral type to cast to to avoid
249 // infinite recursion.
250 typedef decltype(nsChangeHint(0) + nsChangeHint(0)) nsChangeHint_size_t;
251
252 inline nsChangeHint constexpr
253 operator|(nsChangeHint aLeft, nsChangeHint aRight)
254 {
255 return nsChangeHint(nsChangeHint_size_t(aLeft) | nsChangeHint_size_t(aRight));
256 }
257
258 inline nsChangeHint constexpr
259 operator&(nsChangeHint aLeft, nsChangeHint aRight)
260 {
261 return nsChangeHint(nsChangeHint_size_t(aLeft) & nsChangeHint_size_t(aRight));
262 }
263
264 inline nsChangeHint& operator|=(nsChangeHint& aLeft, nsChangeHint aRight)
265 {
266 return aLeft = aLeft | aRight;
267 }
268
269 inline nsChangeHint& operator&=(nsChangeHint& aLeft, nsChangeHint aRight)
270 {
271 return aLeft = aLeft & aRight;
272 }
273
274 inline nsChangeHint constexpr
275 operator~(nsChangeHint aArg)
276 {
277 return nsChangeHint(~nsChangeHint_size_t(aArg));
278 }
279
280 inline nsChangeHint constexpr
281 operator^(nsChangeHint aLeft, nsChangeHint aRight)
282 {
283 return nsChangeHint(nsChangeHint_size_t(aLeft) ^ nsChangeHint_size_t(aRight));
284 }
285
286 inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight)
287 {
288 return aLeft = aLeft ^ aRight;
289 }
290
291 /**
292 * We have an optimization when processing change hints which prevents
293 * us from visiting the descendants of a node when a hint on that node
294 * is being processed. This optimization does not apply in some of the
295 * cases where applying a hint to an element does not necessarily result
296 * in the same hint being handled on the descendants.
297 */
298
299 // The most hints that NS_HintsNotHandledForDescendantsIn could possibly return:
300 #define nsChangeHint_Hints_NotHandledForDescendants nsChangeHint( \
301 nsChangeHint_UpdateTransformLayer | \
302 nsChangeHint_UpdateEffects | \
303 nsChangeHint_InvalidateRenderingObservers | \
304 nsChangeHint_UpdateOpacityLayer | \
305 nsChangeHint_UpdateOverflow | \
306 nsChangeHint_UpdatePostTransformOverflow | \
307 nsChangeHint_UpdateParentOverflow | \
308 nsChangeHint_ChildrenOnlyTransform | \
309 nsChangeHint_RecomputePosition | \
310 nsChangeHint_UpdateContainingBlock | \
311 nsChangeHint_AddOrRemoveTransform | \
312 nsChangeHint_BorderStyleNoneChange | \
313 nsChangeHint_NeedReflow | \
314 nsChangeHint_ReflowChangesSizeOrPosition | \
315 nsChangeHint_ClearAncestorIntrinsics | \
316 nsChangeHint_UpdateComputedBSize | \
317 nsChangeHint_UpdateUsesOpacity | \
318 nsChangeHint_UpdateBackgroundPosition)
319
NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint)320 inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) {
321 nsChangeHint result = nsChangeHint(aChangeHint & (
322 nsChangeHint_UpdateTransformLayer |
323 nsChangeHint_UpdateEffects |
324 nsChangeHint_InvalidateRenderingObservers |
325 nsChangeHint_UpdateOpacityLayer |
326 nsChangeHint_UpdateOverflow |
327 nsChangeHint_UpdatePostTransformOverflow |
328 nsChangeHint_UpdateParentOverflow |
329 nsChangeHint_ChildrenOnlyTransform |
330 nsChangeHint_RecomputePosition |
331 nsChangeHint_UpdateContainingBlock |
332 nsChangeHint_AddOrRemoveTransform |
333 nsChangeHint_BorderStyleNoneChange |
334 nsChangeHint_UpdateComputedBSize |
335 nsChangeHint_UpdateUsesOpacity | \
336 nsChangeHint_UpdateBackgroundPosition));
337
338 if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aChangeHint)) {
339 if (NS_IsHintSubset(nsChangeHint_NeedReflow, aChangeHint)) {
340 // If NeedDirtyReflow is *not* set, then NeedReflow is a
341 // non-inherited hint.
342 result |= nsChangeHint_NeedReflow;
343 }
344
345 if (NS_IsHintSubset(nsChangeHint_ReflowChangesSizeOrPosition,
346 aChangeHint)) {
347 // If NeedDirtyReflow is *not* set, then ReflowChangesSizeOrPosition is a
348 // non-inherited hint.
349 result |= nsChangeHint_ReflowChangesSizeOrPosition;
350 }
351 }
352
353 if (!NS_IsHintSubset(nsChangeHint_ClearDescendantIntrinsics, aChangeHint) &&
354 NS_IsHintSubset(nsChangeHint_ClearAncestorIntrinsics, aChangeHint)) {
355 // If ClearDescendantIntrinsics is *not* set, then
356 // ClearAncestorIntrinsics is a non-inherited hint.
357 result |= nsChangeHint_ClearAncestorIntrinsics;
358 }
359
360 MOZ_ASSERT(NS_IsHintSubset(result,
361 nsChangeHint_Hints_NotHandledForDescendants),
362 "something is inconsistent");
363
364 return result;
365 }
366
367 // Redefine the old NS_STYLE_HINT constants in terms of the new hint structure
368 #define NS_STYLE_HINT_VISUAL \
369 nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView | \
370 nsChangeHint_SchedulePaint)
371 #define nsChangeHint_AllReflowHints \
372 nsChangeHint(nsChangeHint_NeedReflow | \
373 nsChangeHint_ReflowChangesSizeOrPosition|\
374 nsChangeHint_ClearAncestorIntrinsics | \
375 nsChangeHint_ClearDescendantIntrinsics | \
376 nsChangeHint_NeedDirtyReflow)
377 #define NS_STYLE_HINT_REFLOW \
378 nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints)
379
380 #define nsChangeHint_Hints_CanIgnoreIfNotVisible \
381 nsChangeHint(NS_STYLE_HINT_VISUAL | \
382 nsChangeHint_NeutralChange | \
383 nsChangeHint_UpdateOpacityLayer | \
384 nsChangeHint_UpdateTransformLayer | \
385 nsChangeHint_UpdateUsesOpacity)
386
387 /**
388 * |nsRestyleHint| is a bitfield for the result of
389 * |HasStateDependentStyle| and |HasAttributeDependentStyle|. When no
390 * restyling is necessary, use |nsRestyleHint(0)|.
391 *
392 * Without eRestyle_Force or eRestyle_ForceDescendants, the restyling process
393 * can stop processing at a frame when it detects no style changes and it is
394 * known that the styles of the subtree beneath it will not change, leaving
395 * the old style context on the frame. eRestyle_Force can be used to skip this
396 * optimization on a frame, and to force its new style context to be used.
397 *
398 * Similarly, eRestyle_ForceDescendants will cause the frame and all of its
399 * descendants to be traversed and for the new style contexts that are created
400 * to be set on the frames.
401 *
402 * NOTE: When adding new restyle hints, please also add them to
403 * RestyleManager::RestyleHintToString.
404 */
405 enum nsRestyleHint {
406 // Rerun selector matching on the element. If a new style context
407 // results, update the style contexts of descendants. (Irrelevant if
408 // eRestyle_Subtree is also set, since that implies a superset of the
409 // work.)
410 eRestyle_Self = 1 << 0,
411
412 // Rerun selector matching on descendants of the element that match
413 // a given selector.
414 eRestyle_SomeDescendants = 1 << 1,
415
416 // Rerun selector matching on the element and all of its descendants.
417 // (Implies eRestyle_ForceDescendants, which ensures that we continue
418 // the restyling process for all descendants, but doesn't cause
419 // selector matching.)
420 eRestyle_Subtree = 1 << 2,
421
422 // Rerun selector matching on all later siblings of the element and
423 // all of their descendants.
424 eRestyle_LaterSiblings = 1 << 3,
425
426 // Replace the style data coming from CSS transitions without updating
427 // any other style data. If a new style context results, update style
428 // contexts on the descendants. (Irrelevant if eRestyle_Self or
429 // eRestyle_Subtree is also set, since those imply a superset of the
430 // work.)
431 eRestyle_CSSTransitions = 1 << 4,
432
433 // Replace the style data coming from CSS animations without updating
434 // any other style data. If a new style context results, update style
435 // contexts on the descendants. (Irrelevant if eRestyle_Self or
436 // eRestyle_Subtree is also set, since those imply a superset of the
437 // work.)
438 eRestyle_CSSAnimations = 1 << 5,
439
440 // Replace the style data coming from SVG animations (SMIL Animations)
441 // without updating any other style data. If a new style context
442 // results, update style contexts on the descendants. (Irrelevant if
443 // eRestyle_Self or eRestyle_Subtree is also set, since those imply a
444 // superset of the work.)
445 eRestyle_SVGAttrAnimations = 1 << 6,
446
447 // Replace the style data coming from inline style without updating
448 // any other style data. If a new style context results, update style
449 // contexts on the descendants. (Irrelevant if eRestyle_Self or
450 // eRestyle_Subtree is also set, since those imply a superset of the
451 // work.) Supported only for element style contexts and not for
452 // pseudo-elements or anonymous boxes, on which it converts to
453 // eRestyle_Self.
454 // If the change is for the advance of a declarative animation, use
455 // the value below instead.
456 eRestyle_StyleAttribute = 1 << 7,
457
458 // Same as eRestyle_StyleAttribute, but for when the change results
459 // from the advance of a declarative animation.
460 eRestyle_StyleAttribute_Animations = 1 << 8,
461
462 // Continue the restyling process to the current frame's children even
463 // if this frame's restyling resulted in no style changes.
464 eRestyle_Force = 1 << 9,
465
466 // Continue the restyling process to all of the current frame's
467 // descendants, even if any frame's restyling resulted in no style
468 // changes. (Implies eRestyle_Force.) Note that this is weaker than
469 // eRestyle_Subtree, which makes us rerun selector matching on all
470 // descendants rather than just continuing the restyling process.
471 eRestyle_ForceDescendants = 1 << 10,
472
473 // Useful unions:
474 eRestyle_AllHintsWithAnimations = eRestyle_CSSTransitions |
475 eRestyle_CSSAnimations |
476 eRestyle_SVGAttrAnimations |
477 eRestyle_StyleAttribute_Animations,
478 };
479
480 // The functions below need an integral type to cast to to avoid
481 // infinite recursion.
482 typedef decltype(nsRestyleHint(0) + nsRestyleHint(0)) nsRestyleHint_size_t;
483
484 inline constexpr nsRestyleHint operator|(nsRestyleHint aLeft,
485 nsRestyleHint aRight)
486 {
487 return nsRestyleHint(nsRestyleHint_size_t(aLeft) |
488 nsRestyleHint_size_t(aRight));
489 }
490
491 inline constexpr nsRestyleHint operator&(nsRestyleHint aLeft,
492 nsRestyleHint aRight)
493 {
494 return nsRestyleHint(nsRestyleHint_size_t(aLeft) &
495 nsRestyleHint_size_t(aRight));
496 }
497
498 inline nsRestyleHint& operator|=(nsRestyleHint& aLeft, nsRestyleHint aRight)
499 {
500 return aLeft = aLeft | aRight;
501 }
502
503 inline nsRestyleHint& operator&=(nsRestyleHint& aLeft, nsRestyleHint aRight)
504 {
505 return aLeft = aLeft & aRight;
506 }
507
508 inline constexpr nsRestyleHint operator~(nsRestyleHint aArg)
509 {
510 return nsRestyleHint(~nsRestyleHint_size_t(aArg));
511 }
512
513 inline constexpr nsRestyleHint operator^(nsRestyleHint aLeft,
514 nsRestyleHint aRight)
515 {
516 return nsRestyleHint(nsRestyleHint_size_t(aLeft) ^
517 nsRestyleHint_size_t(aRight));
518 }
519
520 inline nsRestyleHint operator^=(nsRestyleHint& aLeft, nsRestyleHint aRight)
521 {
522 return aLeft = aLeft ^ aRight;
523 }
524
525 namespace mozilla {
526
527 /**
528 * Additional data used in conjunction with an nsRestyleHint to control the
529 * restyle process.
530 */
531 struct RestyleHintData
532 {
533 // When eRestyle_SomeDescendants is used, this array contains the selectors
534 // that identify which descendants will be restyled.
535 nsTArray<nsCSSSelector*> mSelectorsForDescendants;
536 };
537
538 } // namespace mozilla
539
540 #endif /* nsChangeHint_h___ */
541